xref: /freebsd/contrib/ntp/ntpd/ntp_filegen.c (revision 9c2daa00c2315f101948c7144d62af5d5fb515cf)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * ntp_filegen.c,v 3.12 1994/01/25 19:06:11 kardel Exp
3c0b746e5SOllivier Robert  *
4c0b746e5SOllivier Robert  *  implements file generations support for NTP
5c0b746e5SOllivier Robert  *  logfiles and statistic files
6c0b746e5SOllivier Robert  *
7c0b746e5SOllivier Robert  *
8c0b746e5SOllivier Robert  * Copyright (C) 1992, 1996 by Rainer Pruy
9c0b746e5SOllivier Robert  * Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
10c0b746e5SOllivier Robert  *
11c0b746e5SOllivier Robert  * This code may be modified and used freely
12c0b746e5SOllivier Robert  * provided credits remain intact.
13c0b746e5SOllivier Robert  */
14c0b746e5SOllivier Robert 
15c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
16c0b746e5SOllivier Robert #include <config.h>
17c0b746e5SOllivier Robert #endif
18c0b746e5SOllivier Robert 
19c0b746e5SOllivier Robert #include <stdio.h>
20c0b746e5SOllivier Robert #include <sys/types.h>
21c0b746e5SOllivier Robert #include <sys/stat.h>
22c0b746e5SOllivier Robert 
23c0b746e5SOllivier Robert #include "ntpd.h"
24c0b746e5SOllivier Robert #include "ntp_io.h"
25c0b746e5SOllivier Robert #include "ntp_string.h"
26c0b746e5SOllivier Robert #include "ntp_calendar.h"
27c0b746e5SOllivier Robert #include "ntp_filegen.h"
28c0b746e5SOllivier Robert #include "ntp_stdlib.h"
29c0b746e5SOllivier Robert 
30c0b746e5SOllivier Robert /*
31c0b746e5SOllivier Robert  * NTP is intended to run long periods of time without restart.
32c0b746e5SOllivier Robert  * Thus log and statistic files generated by NTP will grow large.
33c0b746e5SOllivier Robert  *
34c0b746e5SOllivier Robert  * this set of routines provides a central interface
35c0b746e5SOllivier Robert  * to generating files using file generations
36c0b746e5SOllivier Robert  *
37c0b746e5SOllivier Robert  * the generation of a file is changed according to file generation type
38c0b746e5SOllivier Robert  */
39c0b746e5SOllivier Robert 
40c0b746e5SOllivier Robert 
41c0b746e5SOllivier Robert /*
42c0b746e5SOllivier Robert  * redefine this if your system dislikes filename suffixes like
43c0b746e5SOllivier Robert  * X.19910101 or X.1992W50 or ....
44c0b746e5SOllivier Robert  */
45c0b746e5SOllivier Robert #define SUFFIX_SEP '.'
46c0b746e5SOllivier Robert 
47c0b746e5SOllivier Robert /*
48c0b746e5SOllivier Robert  * other constants
49c0b746e5SOllivier Robert  */
50c0b746e5SOllivier Robert #define FGEN_AGE_SECS   (24*60*60) /* life time of FILEGEN_AGE in seconds */
51c0b746e5SOllivier Robert 
52c0b746e5SOllivier Robert static	void	filegen_open	P((FILEGEN *, u_long));
53c0b746e5SOllivier Robert static	int	valid_fileref	P((char *, char *));
54c0b746e5SOllivier Robert #ifdef	UNUSED
55c0b746e5SOllivier Robert static	FILEGEN *filegen_unregister P((char *));
56c0b746e5SOllivier Robert #endif	/* UNUSED */
57c0b746e5SOllivier Robert 
58c0b746e5SOllivier Robert /*
59c0b746e5SOllivier Robert  * open a file generation according to the current settings of gen
60c0b746e5SOllivier Robert  * will also provide a link to basename if requested to do so
61c0b746e5SOllivier Robert  */
62c0b746e5SOllivier Robert 
63c0b746e5SOllivier Robert static void
64c0b746e5SOllivier Robert filegen_open(
65c0b746e5SOllivier Robert 	FILEGEN *gen,
66c0b746e5SOllivier Robert 	u_long  newid
67c0b746e5SOllivier Robert 	)
68c0b746e5SOllivier Robert {
69c0b746e5SOllivier Robert 	char *filename;
70c0b746e5SOllivier Robert 	char *basename;
71c0b746e5SOllivier Robert 	u_int len;
72c0b746e5SOllivier Robert 	FILE *fp;
73c0b746e5SOllivier Robert 	struct calendar cal;
74c0b746e5SOllivier Robert 
75c0b746e5SOllivier Robert 	len = strlen(gen->prefix) + strlen(gen->basename) + 1;
76c0b746e5SOllivier Robert 	basename = (char*)emalloc(len);
77c0b746e5SOllivier Robert 	sprintf(basename, "%s%s", gen->prefix, gen->basename);
78c0b746e5SOllivier Robert 
79c0b746e5SOllivier Robert 	switch(gen->type) {
80c0b746e5SOllivier Robert 	    default:
81c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "unsupported file generations type %d for \"%s\" - reverting to FILEGEN_NONE",
82c0b746e5SOllivier Robert 			gen->type, basename);
83c0b746e5SOllivier Robert 		gen->type = FILEGEN_NONE;
84c0b746e5SOllivier Robert 
85c0b746e5SOllivier Robert 		/*FALLTHROUGH*/
86c0b746e5SOllivier Robert 	    case FILEGEN_NONE:
87c0b746e5SOllivier Robert 		filename = (char*)emalloc(len);
88c0b746e5SOllivier Robert 		sprintf(filename,"%s", basename);
89c0b746e5SOllivier Robert 		break;
90c0b746e5SOllivier Robert 
91c0b746e5SOllivier Robert 	    case FILEGEN_PID:
92c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 1 + 10);
93c0b746e5SOllivier Robert 		sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid);
94c0b746e5SOllivier Robert 		break;
95c0b746e5SOllivier Robert 
96c0b746e5SOllivier Robert 	    case FILEGEN_DAY:
97c0b746e5SOllivier Robert 		/* You can argue here in favor of using MJD, but
98c0b746e5SOllivier Robert 		 * I would assume it to be easier for humans to interpret dates
99c0b746e5SOllivier Robert 		 * in a format they are used to in everyday life.
100c0b746e5SOllivier Robert 		 */
101c0b746e5SOllivier Robert 		caljulian(newid,&cal);
102c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 4 + 2 + 2);
103c0b746e5SOllivier Robert 		sprintf(filename, "%s%c%04d%02d%02d",
104c0b746e5SOllivier Robert 			basename, SUFFIX_SEP, cal.year, cal.month, cal.monthday);
105c0b746e5SOllivier Robert 		break;
106c0b746e5SOllivier Robert 
107c0b746e5SOllivier Robert 	    case FILEGEN_WEEK:
108c0b746e5SOllivier Robert 		/*
109c0b746e5SOllivier Robert 		 * This is still a hack
110c0b746e5SOllivier Robert 		 * - the term week is not correlated to week as it is used
111c0b746e5SOllivier Robert 		 *   normally - it just refers to a period of 7 days
112c0b746e5SOllivier Robert 		 *   starting at Jan 1 - 'weeks' are counted starting from zero
113c0b746e5SOllivier Robert 		 */
114c0b746e5SOllivier Robert 		caljulian(newid,&cal);
115c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 4 + 1 + 2);
116c0b746e5SOllivier Robert 		sprintf(filename, "%s%c%04dw%02d",
117c0b746e5SOllivier Robert 			basename, SUFFIX_SEP, cal.year, cal.yearday / 7);
118c0b746e5SOllivier Robert 		break;
119c0b746e5SOllivier Robert 
120c0b746e5SOllivier Robert 	    case FILEGEN_MONTH:
121c0b746e5SOllivier Robert 		caljulian(newid,&cal);
122c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 4 + 2);
123c0b746e5SOllivier Robert 		sprintf(filename, "%s%c%04d%02d",
124c0b746e5SOllivier Robert 			basename, SUFFIX_SEP, cal.year, cal.month);
125c0b746e5SOllivier Robert 		break;
126c0b746e5SOllivier Robert 
127c0b746e5SOllivier Robert 	    case FILEGEN_YEAR:
128c0b746e5SOllivier Robert 		caljulian(newid,&cal);
129c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 4);
130c0b746e5SOllivier Robert 		sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year);
131c0b746e5SOllivier Robert 		break;
132c0b746e5SOllivier Robert 
133c0b746e5SOllivier Robert 	    case FILEGEN_AGE:
134c0b746e5SOllivier Robert 		filename = (char*)emalloc(len + 1 + 2 + 10);
135c0b746e5SOllivier Robert 		sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid);
136c0b746e5SOllivier Robert 		break;
137c0b746e5SOllivier Robert 	}
138c0b746e5SOllivier Robert 
139c0b746e5SOllivier Robert 	if (gen->type != FILEGEN_NONE) {
140c0b746e5SOllivier Robert 		/*
141c0b746e5SOllivier Robert 		 * check for existence of a file with name 'basename'
142c0b746e5SOllivier Robert 		 * as we disallow such a file
143c0b746e5SOllivier Robert 		 * if FGEN_FLAG_LINK is set create a link
144c0b746e5SOllivier Robert 		 */
145c0b746e5SOllivier Robert 		struct stat stats;
146c0b746e5SOllivier Robert 		/*
147c0b746e5SOllivier Robert 		 * try to resolve name collisions
148c0b746e5SOllivier Robert 		 */
149c0b746e5SOllivier Robert 		static u_long conflicts = 0;
150c0b746e5SOllivier Robert 
151c0b746e5SOllivier Robert #ifndef	S_ISREG
152c0b746e5SOllivier Robert #define	S_ISREG(mode)	(((mode) & S_IFREG) == S_IFREG)
153c0b746e5SOllivier Robert #endif
154c0b746e5SOllivier Robert 		if (stat(basename, &stats) == 0) {
155c0b746e5SOllivier Robert 			/* Hm, file exists... */
156c0b746e5SOllivier Robert 			if (S_ISREG(stats.st_mode)) {
157c0b746e5SOllivier Robert 				if (stats.st_nlink <= 1)	{
158c0b746e5SOllivier Robert 					/*
159c0b746e5SOllivier Robert 					 * Oh, it is not linked - try to save it
160c0b746e5SOllivier Robert 					 */
161c0b746e5SOllivier Robert 					char *savename = (char*)emalloc(len + 1 + 1 + 10 + 10);
162c0b746e5SOllivier Robert 					sprintf(savename, "%s%c%dC%lu",
163c0b746e5SOllivier Robert 						basename,
164c0b746e5SOllivier Robert 						SUFFIX_SEP,
165c0b746e5SOllivier Robert 						(int) getpid(),
166c0b746e5SOllivier Robert 						(u_long)conflicts++);
167c0b746e5SOllivier Robert 					if (rename(basename, savename) != 0)
168c0b746e5SOllivier Robert 					    msyslog(LOG_ERR," couldn't save %s: %m", basename);
169c0b746e5SOllivier Robert 					free(savename);
170c0b746e5SOllivier Robert 				} else {
171c0b746e5SOllivier Robert 					/*
172c0b746e5SOllivier Robert 					 * there is at least a second link tpo this file
173c0b746e5SOllivier Robert 					 * just remove the conflicting one
174c0b746e5SOllivier Robert 					 */
175c0b746e5SOllivier Robert 					if (
176c0b746e5SOllivier Robert #if !defined(VMS)
177c0b746e5SOllivier Robert 						unlink(basename) != 0
178c0b746e5SOllivier Robert #else
179c0b746e5SOllivier Robert 						delete(basename) != 0
180c0b746e5SOllivier Robert #endif
181c0b746e5SOllivier Robert 						)
182c0b746e5SOllivier Robert 					    msyslog(LOG_ERR, "couldn't unlink %s: %m", basename);
183c0b746e5SOllivier Robert 				}
184c0b746e5SOllivier Robert 			} else {
185c0b746e5SOllivier Robert 				/*
186c0b746e5SOllivier Robert 				 * Ehh? Not a regular file ?? strange !!!!
187c0b746e5SOllivier Robert 				 */
188c0b746e5SOllivier Robert 				msyslog(LOG_ERR, "expected regular file for %s (found mode 0%lo)",
189c0b746e5SOllivier Robert 					basename, (unsigned long)stats.st_mode);
190c0b746e5SOllivier Robert 			}
191c0b746e5SOllivier Robert 		} else {
192c0b746e5SOllivier Robert 			/*
193c0b746e5SOllivier Robert 			 * stat(..) failed, but it is absolutely correct for
194c0b746e5SOllivier Robert 			 * 'basename' not to exist
195c0b746e5SOllivier Robert 			 */
196c0b746e5SOllivier Robert 			if (errno != ENOENT)
197c0b746e5SOllivier Robert 			    msyslog(LOG_ERR,"stat(%s) failed: %m", basename);
198c0b746e5SOllivier Robert 		}
199c0b746e5SOllivier Robert 	}
200c0b746e5SOllivier Robert 
201c0b746e5SOllivier Robert 	/*
202c0b746e5SOllivier Robert 	 * now, try to open new file generation...
203c0b746e5SOllivier Robert 	 */
204c0b746e5SOllivier Robert 	fp = fopen(filename, "a");
205c0b746e5SOllivier Robert 
206c0b746e5SOllivier Robert #ifdef DEBUG
207c0b746e5SOllivier Robert 	if (debug > 3)
208c0b746e5SOllivier Robert 	    printf("opening filegen (type=%d/id=%lu) \"%s\"\n",
209c0b746e5SOllivier Robert 		   gen->type, (u_long)newid, filename);
210c0b746e5SOllivier Robert #endif
211c0b746e5SOllivier Robert 
212c0b746e5SOllivier Robert 	if (fp == NULL)	{
213c0b746e5SOllivier Robert 		/* open failed -- keep previous state
214c0b746e5SOllivier Robert 		 *
215c0b746e5SOllivier Robert 		 * If the file was open before keep the previous generation.
216c0b746e5SOllivier Robert 		 * This will cause output to end up in the 'wrong' file,
2179c2daa00SOllivier Robert 		 * but I think this is still better than losing output
218c0b746e5SOllivier Robert 		 *
219c0b746e5SOllivier Robert 		 * ignore errors due to missing directories
220c0b746e5SOllivier Robert 		 */
221c0b746e5SOllivier Robert 
222c0b746e5SOllivier Robert 		if (errno != ENOENT)
223c0b746e5SOllivier Robert 		    msyslog(LOG_ERR, "can't open %s: %m", filename);
224c0b746e5SOllivier Robert 	} else {
225c0b746e5SOllivier Robert 		if (gen->fp != NULL) {
226c0b746e5SOllivier Robert 			fclose(gen->fp);
227c0b746e5SOllivier Robert 		}
228c0b746e5SOllivier Robert 		gen->fp = fp;
229c0b746e5SOllivier Robert 		gen->id = newid;
230c0b746e5SOllivier Robert 
231c0b746e5SOllivier Robert 		if (gen->flag & FGEN_FLAG_LINK) {
232c0b746e5SOllivier Robert 			/*
233c0b746e5SOllivier Robert 			 * need to link file to basename
234c0b746e5SOllivier Robert 			 * have to use hardlink for now as I want to allow
235c0b746e5SOllivier Robert 			 * gen->basename spanning directory levels
236c0b746e5SOllivier Robert 			 * this would make it more complex to get the correct
237c0b746e5SOllivier Robert 			 * filename for symlink
238c0b746e5SOllivier Robert 			 *
239c0b746e5SOllivier Robert 			 * Ok, it would just mean taking the part following
240c0b746e5SOllivier Robert 			 * the last '/' in the name.... Should add it later....
241c0b746e5SOllivier Robert 			 */
242c0b746e5SOllivier Robert 
243c0b746e5SOllivier Robert 			/* Windows NT does not support file links -Greg Schueman 1/18/97 */
244c0b746e5SOllivier Robert 
245c0b746e5SOllivier Robert #if defined SYS_WINNT || defined SYS_VXWORKS
246c0b746e5SOllivier Robert 			SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */
247c0b746e5SOllivier Robert #elif defined(VMS)
248c0b746e5SOllivier Robert 			errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */
249c0b746e5SOllivier Robert #else  /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */
250c0b746e5SOllivier Robert 			if (link(filename, basename) != 0)
251c0b746e5SOllivier Robert 			    if (errno != EEXIST)
252c0b746e5SOllivier Robert 				msyslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename);
253c0b746e5SOllivier Robert #endif /* SYS_WINNT || VXWORKS */
254c0b746e5SOllivier Robert 		}		/* flags & FGEN_FLAG_LINK */
255c0b746e5SOllivier Robert 	}			/* else fp == NULL */
256c0b746e5SOllivier Robert 
257c0b746e5SOllivier Robert 	free(basename);
258c0b746e5SOllivier Robert 	free(filename);
259c0b746e5SOllivier Robert 	return;
260c0b746e5SOllivier Robert }
261c0b746e5SOllivier Robert 
262c0b746e5SOllivier Robert /*
263c0b746e5SOllivier Robert  * this function sets up gen->fp to point to the correct
264c0b746e5SOllivier Robert  * generation of the file for the time specified by 'now'
265c0b746e5SOllivier Robert  *
266c0b746e5SOllivier Robert  * 'now' usually is interpreted as second part of a l_fp as is in the cal...
267c0b746e5SOllivier Robert  * library routines
268c0b746e5SOllivier Robert  */
269c0b746e5SOllivier Robert 
270c0b746e5SOllivier Robert void
271c0b746e5SOllivier Robert filegen_setup(
272c0b746e5SOllivier Robert 	FILEGEN *gen,
273c0b746e5SOllivier Robert 	u_long   now
274c0b746e5SOllivier Robert 	)
275c0b746e5SOllivier Robert {
276c0b746e5SOllivier Robert 	u_long new_gen = ~ (u_long) 0;
277c0b746e5SOllivier Robert 	struct calendar cal;
278c0b746e5SOllivier Robert 
279c0b746e5SOllivier Robert 	if (!(gen->flag & FGEN_FLAG_ENABLED)) {
280c0b746e5SOllivier Robert 		if (gen->fp != NULL)
281c0b746e5SOllivier Robert 		    fclose(gen->fp);
282c0b746e5SOllivier Robert 		return;
283c0b746e5SOllivier Robert 	}
284c0b746e5SOllivier Robert 
285c0b746e5SOllivier Robert 	switch (gen->type) {
286c0b746e5SOllivier Robert 	    case FILEGEN_NONE:
287c0b746e5SOllivier Robert 		if (gen->fp != NULL) return; /* file already open */
288c0b746e5SOllivier Robert 		break;
289c0b746e5SOllivier Robert 
290c0b746e5SOllivier Robert 	    case FILEGEN_PID:
291c0b746e5SOllivier Robert 		new_gen = getpid();
292c0b746e5SOllivier Robert 		break;
293c0b746e5SOllivier Robert 
294c0b746e5SOllivier Robert 	    case FILEGEN_DAY:
295c0b746e5SOllivier Robert 		caljulian(now, &cal);
296c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
297c0b746e5SOllivier Robert 		new_gen = caltontp(&cal);
298c0b746e5SOllivier Robert 		break;
299c0b746e5SOllivier Robert 
300c0b746e5SOllivier Robert 	    case FILEGEN_WEEK:
301c0b746e5SOllivier Robert 		/* Would be nice to have a calweekstart() routine */
302c0b746e5SOllivier Robert 		/* so just use a hack ... */
303c0b746e5SOllivier Robert 		/* just round time to integral 7 day period for actual year  */
304c0b746e5SOllivier Robert 		new_gen = now - (now - calyearstart(now)) % TIMES7(SECSPERDAY)
305c0b746e5SOllivier Robert 			+ 60;
306c0b746e5SOllivier Robert 		/*
307c0b746e5SOllivier Robert 		 * just to be sure -
308c0b746e5SOllivier Robert 		 * the computation above would fail in the presence of leap seconds
309c0b746e5SOllivier Robert 		 * so at least carry the date to the next day (+60 (seconds))
310c0b746e5SOllivier Robert 		 * and go back to the start of the day via calendar computations
311c0b746e5SOllivier Robert 		 */
312c0b746e5SOllivier Robert 		caljulian(new_gen, &cal);
313c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
314c0b746e5SOllivier Robert 		new_gen = caltontp(&cal);
315c0b746e5SOllivier Robert 		break;
316c0b746e5SOllivier Robert 
317c0b746e5SOllivier Robert 	    case FILEGEN_MONTH:
318c0b746e5SOllivier Robert 		caljulian(now, &cal);
3199c2daa00SOllivier Robert 		cal.yearday = (u_short) (cal.yearday - cal.monthday + 1);
320c0b746e5SOllivier Robert 		cal.monthday = 1;
321c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
322c0b746e5SOllivier Robert 		new_gen = caltontp(&cal);
323c0b746e5SOllivier Robert 		break;
324c0b746e5SOllivier Robert 
325c0b746e5SOllivier Robert 	    case FILEGEN_YEAR:
326c0b746e5SOllivier Robert 		new_gen = calyearstart(now);
327c0b746e5SOllivier Robert 		break;
328c0b746e5SOllivier Robert 
329c0b746e5SOllivier Robert 	    case FILEGEN_AGE:
330c0b746e5SOllivier Robert 		new_gen = current_time  - (current_time % FGEN_AGE_SECS);
331c0b746e5SOllivier Robert 		break;
332c0b746e5SOllivier Robert 	}
333c0b746e5SOllivier Robert 	/*
334c0b746e5SOllivier Robert 	 * try to open file if not yet open
335c0b746e5SOllivier Robert 	 * reopen new file generation file on change of generation id
336c0b746e5SOllivier Robert 	 */
337c0b746e5SOllivier Robert 	if (gen->fp == NULL || gen->id != new_gen) {
338c0b746e5SOllivier Robert 		filegen_open(gen, new_gen);
339c0b746e5SOllivier Robert 	}
340c0b746e5SOllivier Robert }
341c0b746e5SOllivier Robert 
342c0b746e5SOllivier Robert 
343c0b746e5SOllivier Robert /*
344c0b746e5SOllivier Robert  * change settings for filegen files
345c0b746e5SOllivier Robert  */
346c0b746e5SOllivier Robert void
347c0b746e5SOllivier Robert filegen_config(
348c0b746e5SOllivier Robert 	FILEGEN *gen,
349c0b746e5SOllivier Robert 	char    *basename,
350c0b746e5SOllivier Robert 	u_int   type,
351c0b746e5SOllivier Robert 	u_int   flag
352c0b746e5SOllivier Robert 	)
353c0b746e5SOllivier Robert {
354c0b746e5SOllivier Robert 	/*
355c0b746e5SOllivier Robert 	 * if nothing would be changed...
356c0b746e5SOllivier Robert 	 */
357c0b746e5SOllivier Robert 	if ((basename == gen->basename || strcmp(basename,gen->basename) == 0) &&
358c0b746e5SOllivier Robert 	    type == gen->type &&
359c0b746e5SOllivier Robert 	    flag == gen->flag)
360c0b746e5SOllivier Robert 	    return;
361c0b746e5SOllivier Robert 
362c0b746e5SOllivier Robert 	/*
363c0b746e5SOllivier Robert 	 * validate parameters
364c0b746e5SOllivier Robert 	 */
365c0b746e5SOllivier Robert 	if (!valid_fileref(gen->prefix,basename))
366c0b746e5SOllivier Robert 	    return;
367c0b746e5SOllivier Robert 
368c0b746e5SOllivier Robert 	if (gen->fp != NULL)
369c0b746e5SOllivier Robert 	    fclose(gen->fp);
370c0b746e5SOllivier Robert 
371c0b746e5SOllivier Robert #ifdef DEBUG
372c0b746e5SOllivier Robert 	if (debug > 2)
373c0b746e5SOllivier Robert 	    printf("configuring filegen:\n\tprefix:\t%s\n\tbasename:\t%s -> %s\n\ttype:\t%d -> %d\n\tflag: %x -> %x\n",
374c0b746e5SOllivier Robert 		   gen->prefix, gen->basename, basename, gen->type, type, gen->flag, flag);
375c0b746e5SOllivier Robert #endif
376c0b746e5SOllivier Robert 	if (gen->basename != basename || strcmp(gen->basename, basename) != 0) {
377c0b746e5SOllivier Robert 		free(gen->basename);
378c0b746e5SOllivier Robert 		gen->basename = (char*)emalloc(strlen(basename) + 1);
379c0b746e5SOllivier Robert 		strcpy(gen->basename, basename);
380c0b746e5SOllivier Robert 	}
3819c2daa00SOllivier Robert 	gen->type = (u_char) type;
3829c2daa00SOllivier Robert 	gen->flag = (u_char) flag;
383c0b746e5SOllivier Robert 
384c0b746e5SOllivier Robert 	/*
385c0b746e5SOllivier Robert 	 * make filegen use the new settings
386c0b746e5SOllivier Robert 	 * special action is only required when a generation file
387c0b746e5SOllivier Robert 	 * is currently open
388c0b746e5SOllivier Robert 	 * otherwise the new settings will be used anyway at the next open
389c0b746e5SOllivier Robert 	 */
390c0b746e5SOllivier Robert 	if (gen->fp != NULL) {
391c0b746e5SOllivier Robert 		l_fp now;
392c0b746e5SOllivier Robert 
393c0b746e5SOllivier Robert 		get_systime(&now);
394c0b746e5SOllivier Robert 		filegen_setup(gen, now.l_ui);
395c0b746e5SOllivier Robert 	}
396c0b746e5SOllivier Robert }
397c0b746e5SOllivier Robert 
398c0b746e5SOllivier Robert 
399c0b746e5SOllivier Robert /*
400c0b746e5SOllivier Robert  * check whether concatenating prefix and basename
401c0b746e5SOllivier Robert  * yields a legal filename
402c0b746e5SOllivier Robert  */
403c0b746e5SOllivier Robert static int
404c0b746e5SOllivier Robert valid_fileref(
405c0b746e5SOllivier Robert 	char *prefix,
406c0b746e5SOllivier Robert 	char *basename
407c0b746e5SOllivier Robert 	)
408c0b746e5SOllivier Robert {
409c0b746e5SOllivier Robert 	/*
410c0b746e5SOllivier Robert 	 * prefix cannot be changed dynamically
411c0b746e5SOllivier Robert 	 * (within the context of filegen)
412c0b746e5SOllivier Robert 	 * so just reject basenames containing '..'
413c0b746e5SOllivier Robert 	 *
414c0b746e5SOllivier Robert 	 * ASSUMPTION:
415c0b746e5SOllivier Robert 	 * 		file system parts 'below' prefix may be
416c0b746e5SOllivier Robert 	 *		specified without infringement of security
417c0b746e5SOllivier Robert 	 *
418c0b746e5SOllivier Robert 	 *              restricing prefix to legal values
419c0b746e5SOllivier Robert 	 *		has to be ensured by other means
420c0b746e5SOllivier Robert 	 * (however, it would be possible to perform some checks here...)
421c0b746e5SOllivier Robert 	 */
422c0b746e5SOllivier Robert 	register char *p = basename;
423c0b746e5SOllivier Robert 
424c0b746e5SOllivier Robert 	/*
425c0b746e5SOllivier Robert 	 * Just to catch, dumb errors opening up the world...
426c0b746e5SOllivier Robert 	 */
427c0b746e5SOllivier Robert 	if (prefix == NULL || *prefix == '\0')
428c0b746e5SOllivier Robert 	    return 0;
429c0b746e5SOllivier Robert 
430c0b746e5SOllivier Robert 	if (basename == NULL)
431c0b746e5SOllivier Robert 	    return 0;
432c0b746e5SOllivier Robert 
433c0b746e5SOllivier Robert 	for (p = basename; p; p = strchr(p, '/')) {
434c0b746e5SOllivier Robert 		if (*p == '.' && *(p+1) == '.' && (*(p+2) == '\0' || *(p+2) == '/'))
435c0b746e5SOllivier Robert 		    return 0;
436c0b746e5SOllivier Robert 	}
437c0b746e5SOllivier Robert 
438c0b746e5SOllivier Robert 	return 1;
439c0b746e5SOllivier Robert }
440c0b746e5SOllivier Robert 
441c0b746e5SOllivier Robert 
442c0b746e5SOllivier Robert /*
443c0b746e5SOllivier Robert  * filegen registry
444c0b746e5SOllivier Robert  */
445c0b746e5SOllivier Robert 
446c0b746e5SOllivier Robert static struct filegen_entry {
447c0b746e5SOllivier Robert 	char *name;
448c0b746e5SOllivier Robert 	FILEGEN *filegen;
449c0b746e5SOllivier Robert 	struct filegen_entry *next;
450c0b746e5SOllivier Robert } *filegen_registry = NULL;
451c0b746e5SOllivier Robert 
452c0b746e5SOllivier Robert 
453c0b746e5SOllivier Robert FILEGEN *
454c0b746e5SOllivier Robert filegen_get(
455c0b746e5SOllivier Robert 	char *name
456c0b746e5SOllivier Robert 	)
457c0b746e5SOllivier Robert {
458c0b746e5SOllivier Robert 	struct filegen_entry *f = filegen_registry;
459c0b746e5SOllivier Robert 
460c0b746e5SOllivier Robert 	while(f) {
461c0b746e5SOllivier Robert 		if (f->name == name || strcmp(name, f->name) == 0) {
462c0b746e5SOllivier Robert #ifdef XXX	/* this gives the Alpha compiler fits */
463c0b746e5SOllivier Robert 			if (debug > 3)
464c0b746e5SOllivier Robert 			    printf("filegen_get(\"%s\") = %x\n", name,
465c0b746e5SOllivier Robert 				   (u_int)f->filegen);
466c0b746e5SOllivier Robert #endif
467c0b746e5SOllivier Robert 			return f->filegen;
468c0b746e5SOllivier Robert 		}
469c0b746e5SOllivier Robert 		f = f->next;
470c0b746e5SOllivier Robert 	}
471c0b746e5SOllivier Robert #ifdef DEBUG
472c0b746e5SOllivier Robert 	if (debug > 3)
473c0b746e5SOllivier Robert 	    printf("filegen_get(\"%s\") = NULL\n", name);
474c0b746e5SOllivier Robert #endif
475c0b746e5SOllivier Robert 	return NULL;
476c0b746e5SOllivier Robert }
477c0b746e5SOllivier Robert 
478c0b746e5SOllivier Robert void
479c0b746e5SOllivier Robert filegen_register(
480c0b746e5SOllivier Robert 	const char *name,
481c0b746e5SOllivier Robert 	FILEGEN *filegen
482c0b746e5SOllivier Robert 	)
483c0b746e5SOllivier Robert {
484c0b746e5SOllivier Robert 	struct filegen_entry **f = &filegen_registry;
485c0b746e5SOllivier Robert 
486c0b746e5SOllivier Robert #ifdef XXX		/* this gives the Alpha compiler fits */
487c0b746e5SOllivier Robert 	if (debug > 3)
488c0b746e5SOllivier Robert 	    printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen);
489c0b746e5SOllivier Robert #endif
490c0b746e5SOllivier Robert 	while (*f) {
491c0b746e5SOllivier Robert 		if ((*f)->name == name || strcmp(name, (*f)->name) == 0) {
492c0b746e5SOllivier Robert #ifdef XXX	 /* this gives the Alpha compiler fits */
493c0b746e5SOllivier Robert 			if (debug > 4) {
494c0b746e5SOllivier Robert 				printf("replacing filegen %x\n", (u_int)(*f)->filegen);
495c0b746e5SOllivier Robert 			}
496c0b746e5SOllivier Robert #endif
497c0b746e5SOllivier Robert 			(*f)->filegen = filegen;
498c0b746e5SOllivier Robert 			return;
499c0b746e5SOllivier Robert 		}
500c0b746e5SOllivier Robert 		f = &((*f)->next);
501c0b746e5SOllivier Robert 	}
502c0b746e5SOllivier Robert 
503c0b746e5SOllivier Robert 	*f = (struct filegen_entry *) emalloc(sizeof(struct filegen_entry));
504c0b746e5SOllivier Robert 	if (*f) {
505c0b746e5SOllivier Robert 		(*f)->next = NULL;
506c0b746e5SOllivier Robert 		(*f)->name = (char*)emalloc(strlen(name) + 1);
507c0b746e5SOllivier Robert 		strcpy((*f)->name, name);
508c0b746e5SOllivier Robert 		(*f)->filegen = filegen;
509c0b746e5SOllivier Robert #ifdef DEBUG
510c0b746e5SOllivier Robert 		if (debug > 5) {
511c0b746e5SOllivier Robert 			printf("adding new filegen\n");
512c0b746e5SOllivier Robert 		}
513c0b746e5SOllivier Robert #endif
514c0b746e5SOllivier Robert 	}
515c0b746e5SOllivier Robert 
516c0b746e5SOllivier Robert 	return;
517c0b746e5SOllivier Robert }
518c0b746e5SOllivier Robert 
519c0b746e5SOllivier Robert #ifdef	UNUSED
520c0b746e5SOllivier Robert static FILEGEN *
521c0b746e5SOllivier Robert filegen_unregister(
522c0b746e5SOllivier Robert 	char *name
523c0b746e5SOllivier Robert 	)
524c0b746e5SOllivier Robert {
525c0b746e5SOllivier Robert 	struct filegen_entry **f = &filegen_registry;
526c0b746e5SOllivier Robert 
527c0b746e5SOllivier Robert #ifdef DEBUG
528c0b746e5SOllivier Robert 	if (debug > 3)
529c0b746e5SOllivier Robert 	    printf("filegen_unregister(\"%s\")\n", name);
530c0b746e5SOllivier Robert #endif
531c0b746e5SOllivier Robert 
532c0b746e5SOllivier Robert 	while (*f) {
533c0b746e5SOllivier Robert 		if (strcmp((*f)->name,name) == 0) {
534c0b746e5SOllivier Robert 			struct filegen_entry *ff = *f;
535c0b746e5SOllivier Robert 			FILEGEN *fg;
536c0b746e5SOllivier Robert 
537c0b746e5SOllivier Robert 			*f = (*f)->next;
538c0b746e5SOllivier Robert 			fg = ff->filegen;
539c0b746e5SOllivier Robert 			free(ff->name);
540c0b746e5SOllivier Robert 			free(ff);
541c0b746e5SOllivier Robert 			return fg;
542c0b746e5SOllivier Robert 		}
543c0b746e5SOllivier Robert 		f = &((*f)->next);
544c0b746e5SOllivier Robert 	}
545c0b746e5SOllivier Robert 	return NULL;
546c0b746e5SOllivier Robert }
547c0b746e5SOllivier Robert #endif	/* UNUSED */
548