xref: /freebsd/contrib/ntp/ntpd/ntp_filegen.c (revision 9c2daa00)
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 Universitaet Erlangen-Nuernberg, 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 static	void	filegen_open	(FILEGEN *, u_int32, const time_t*);
48c0b746e5SOllivier Robert static	int	valid_fileref	(const char *, const char *);
49c0b746e5SOllivier Robert static	void	filegen_init	(const char *, const char *, FILEGEN *);
50c0b746e5SOllivier Robert #ifdef	DEBUG
51c0b746e5SOllivier Robert static	void	filegen_uninit		(FILEGEN *);
52c0b746e5SOllivier Robert #endif	/* DEBUG */
53c0b746e5SOllivier Robert 
54c0b746e5SOllivier Robert 
55c0b746e5SOllivier Robert /*
56c0b746e5SOllivier Robert  * filegen_init
57c0b746e5SOllivier Robert  */
58c0b746e5SOllivier Robert 
59c0b746e5SOllivier Robert static void
filegen_init(const char * dir,const char * fname,FILEGEN * fgp)60c0b746e5SOllivier Robert filegen_init(
61c0b746e5SOllivier Robert 	const char *	dir,
62c0b746e5SOllivier Robert 	const char *	fname,
63c0b746e5SOllivier Robert 	FILEGEN *	fgp
64c0b746e5SOllivier Robert 	)
65c0b746e5SOllivier Robert {
66c0b746e5SOllivier Robert 	fgp->fp = NULL;
67c0b746e5SOllivier Robert 	fgp->dir = estrdup(dir);
68c0b746e5SOllivier Robert 	fgp->fname = estrdup(fname);
69c0b746e5SOllivier Robert 	fgp->id_lo = 0;
70c0b746e5SOllivier Robert 	fgp->id_hi = 0;
71c0b746e5SOllivier Robert 	fgp->type = FILEGEN_DAY;
72c0b746e5SOllivier Robert 	fgp->flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
73c0b746e5SOllivier Robert }
74c0b746e5SOllivier Robert 
75c0b746e5SOllivier Robert 
76c0b746e5SOllivier Robert /*
77c0b746e5SOllivier Robert  * filegen_uninit - free memory allocated by filegen_init
78c0b746e5SOllivier Robert  */
79c0b746e5SOllivier Robert #ifdef DEBUG
80c0b746e5SOllivier Robert static void
filegen_uninit(FILEGEN * fgp)81c0b746e5SOllivier Robert filegen_uninit(
82c0b746e5SOllivier Robert 	FILEGEN *fgp
83c0b746e5SOllivier Robert 	)
84c0b746e5SOllivier Robert {
85c0b746e5SOllivier Robert 	free(fgp->dir);
86c0b746e5SOllivier Robert 	free(fgp->fname);
87c0b746e5SOllivier Robert }
88c0b746e5SOllivier Robert #endif
89c0b746e5SOllivier Robert 
90c0b746e5SOllivier Robert 
91c0b746e5SOllivier Robert /*
92c0b746e5SOllivier Robert  * open a file generation according to the current settings of gen
93c0b746e5SOllivier Robert  * will also provide a link to basename if requested to do so
94c0b746e5SOllivier Robert  */
95c0b746e5SOllivier Robert 
96c0b746e5SOllivier Robert static void
filegen_open(FILEGEN * gen,u_int32 stamp,const time_t * pivot)97c0b746e5SOllivier Robert filegen_open(
98c0b746e5SOllivier Robert 	FILEGEN *	gen,
99c0b746e5SOllivier Robert 	u_int32		stamp,
100c0b746e5SOllivier Robert 	const time_t *	pivot
101c0b746e5SOllivier Robert 	)
102c0b746e5SOllivier Robert {
103c0b746e5SOllivier Robert 	char *savename;	/* temp store for name collision handling */
104c0b746e5SOllivier Robert 	char *fullname;	/* name with any designation extension */
105c0b746e5SOllivier Robert 	char *filename;	/* name without designation extension */
106c0b746e5SOllivier Robert 	char *suffix;	/* where to print suffix extension */
107c0b746e5SOllivier Robert 	u_int len, suflen;
108c0b746e5SOllivier Robert 	FILE *fp;
109c0b746e5SOllivier Robert 	struct calendar cal;
110c0b746e5SOllivier Robert 	struct isodate	iso;
111c0b746e5SOllivier Robert 
112c0b746e5SOllivier Robert 	/* get basic filename in buffer, leave room for extensions */
113c0b746e5SOllivier Robert 	len = strlen(gen->dir) + strlen(gen->fname) + 65;
114c0b746e5SOllivier Robert 	filename = emalloc(len);
115c0b746e5SOllivier Robert 	fullname = emalloc(len);
116c0b746e5SOllivier Robert 	savename = NULL;
117c0b746e5SOllivier Robert 	snprintf(filename, len, "%s%s", gen->dir, gen->fname);
118c0b746e5SOllivier Robert 
119c0b746e5SOllivier Robert 	/* where to place suffix */
120c0b746e5SOllivier Robert 	suflen = strlcpy(fullname, filename, len);
121c0b746e5SOllivier Robert 	suffix = fullname + suflen;
122c0b746e5SOllivier Robert 	suflen = len - suflen;
123c0b746e5SOllivier Robert 
124c0b746e5SOllivier Robert 	/* last octet of fullname set to '\0' for truncation check */
125c0b746e5SOllivier Robert 	fullname[len - 1] = '\0';
126c0b746e5SOllivier Robert 
127c0b746e5SOllivier Robert 	switch (gen->type) {
128c0b746e5SOllivier Robert 
129c0b746e5SOllivier Robert 	default:
130c0b746e5SOllivier Robert 		msyslog(LOG_ERR,
131c0b746e5SOllivier Robert 			"unsupported file generations type %d for "
132c0b746e5SOllivier Robert 			"\"%s\" - reverting to FILEGEN_NONE",
133c0b746e5SOllivier Robert 			gen->type, filename);
134c0b746e5SOllivier Robert 		gen->type = FILEGEN_NONE;
135c0b746e5SOllivier Robert 		break;
136c0b746e5SOllivier Robert 
137c0b746e5SOllivier Robert 	case FILEGEN_NONE:
138c0b746e5SOllivier Robert 		/* no suffix, all set */
139c0b746e5SOllivier Robert 		break;
140c0b746e5SOllivier Robert 
141c0b746e5SOllivier Robert 	case FILEGEN_PID:
142c0b746e5SOllivier Robert 		gen->id_lo = getpid();
143c0b746e5SOllivier Robert 		gen->id_hi = 0;
144c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%c#%ld",
145c0b746e5SOllivier Robert 			 SUFFIX_SEP, gen->id_lo);
146c0b746e5SOllivier Robert 		break;
147c0b746e5SOllivier Robert 
148c0b746e5SOllivier Robert 	case FILEGEN_DAY:
149c0b746e5SOllivier Robert 		/*
150c0b746e5SOllivier Robert 		 * You can argue here in favor of using MJD, but I
151c0b746e5SOllivier Robert 		 * would assume it to be easier for humans to interpret
152c0b746e5SOllivier Robert 		 * dates in a format they are used to in everyday life.
153c0b746e5SOllivier Robert 		 */
154c0b746e5SOllivier Robert 		ntpcal_ntp_to_date(&cal, stamp, pivot);
155c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%c%04d%02d%02d",
156c0b746e5SOllivier Robert 			 SUFFIX_SEP, cal.year, cal.month, cal.monthday);
157c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
158c0b746e5SOllivier Robert 		gen->id_lo = ntpcal_date_to_ntp(&cal);
159c0b746e5SOllivier Robert 		gen->id_hi = (u_int32)(gen->id_lo + SECSPERDAY);
160c0b746e5SOllivier Robert 		break;
161c0b746e5SOllivier Robert 
162c0b746e5SOllivier Robert 	case FILEGEN_WEEK:
163c0b746e5SOllivier Robert 		isocal_ntp_to_date(&iso, stamp, pivot);
164c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%c%04dw%02d",
165c0b746e5SOllivier Robert 			 SUFFIX_SEP, iso.year, iso.week);
166c0b746e5SOllivier Robert 		iso.hour = iso.minute = iso.second = 0;
167c0b746e5SOllivier Robert 		iso.weekday = 1;
168c0b746e5SOllivier Robert 		gen->id_lo = isocal_date_to_ntp(&iso);
169c0b746e5SOllivier Robert 		gen->id_hi = (u_int32)(gen->id_lo + 7 * SECSPERDAY);
170c0b746e5SOllivier Robert 		break;
171c0b746e5SOllivier Robert 
172c0b746e5SOllivier Robert 	case FILEGEN_MONTH:
173c0b746e5SOllivier Robert 		ntpcal_ntp_to_date(&cal, stamp, pivot);
174c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%c%04d%02d",
175c0b746e5SOllivier Robert 			 SUFFIX_SEP, cal.year, cal.month);
176c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
177c0b746e5SOllivier Robert 		cal.monthday = 1;
178c0b746e5SOllivier Robert 		gen->id_lo = ntpcal_date_to_ntp(&cal);
179c0b746e5SOllivier Robert 		cal.month++;
180c0b746e5SOllivier Robert 		gen->id_hi = ntpcal_date_to_ntp(&cal);
181c0b746e5SOllivier Robert 		break;
182c0b746e5SOllivier Robert 
183c0b746e5SOllivier Robert 	case FILEGEN_YEAR:
184c0b746e5SOllivier Robert 		ntpcal_ntp_to_date(&cal, stamp, pivot);
185c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%c%04d",
186c0b746e5SOllivier Robert 			 SUFFIX_SEP, cal.year);
187c0b746e5SOllivier Robert 		cal.hour = cal.minute = cal.second = 0;
188c0b746e5SOllivier Robert 		cal.month = cal.monthday = 1;
189c0b746e5SOllivier Robert 		gen->id_lo = ntpcal_date_to_ntp(&cal);
190c0b746e5SOllivier Robert 		cal.year++;
191c0b746e5SOllivier Robert 		gen->id_hi = ntpcal_date_to_ntp(&cal);
192c0b746e5SOllivier Robert 		break;
193c0b746e5SOllivier Robert 
194c0b746e5SOllivier Robert 	case FILEGEN_AGE:
195c0b746e5SOllivier Robert 		gen->id_lo = current_time - (current_time % SECSPERDAY);
196c0b746e5SOllivier Robert 		gen->id_hi = gen->id_lo + SECSPERDAY;
197c0b746e5SOllivier Robert 		snprintf(suffix, suflen, "%ca%08ld",
198c0b746e5SOllivier Robert 			 SUFFIX_SEP, gen->id_lo);
199c0b746e5SOllivier Robert 	}
200c0b746e5SOllivier Robert 
201c0b746e5SOllivier Robert 	/* check possible truncation */
202c0b746e5SOllivier Robert 	if ('\0' != fullname[len - 1]) {
203c0b746e5SOllivier Robert 		fullname[len - 1] = '\0';
204c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "logfile name truncated: \"%s\"",
205c0b746e5SOllivier Robert 			fullname);
206c0b746e5SOllivier Robert 	}
207c0b746e5SOllivier Robert 
208c0b746e5SOllivier Robert 	if (FILEGEN_NONE != gen->type) {
209c0b746e5SOllivier Robert 		/*
210c0b746e5SOllivier Robert 		 * check for existence of a file with name 'basename'
211c0b746e5SOllivier Robert 		 * as we disallow such a file
212c0b746e5SOllivier Robert 		 * if FGEN_FLAG_LINK is set create a link
213c0b746e5SOllivier Robert 		 */
214c0b746e5SOllivier Robert 		struct stat stats;
215c0b746e5SOllivier Robert 		/*
216c0b746e5SOllivier Robert 		 * try to resolve name collisions
2179c2daa00SOllivier Robert 		 */
218c0b746e5SOllivier Robert 		static u_long conflicts = 0;
219c0b746e5SOllivier Robert 
220c0b746e5SOllivier Robert #ifndef	S_ISREG
221c0b746e5SOllivier Robert #define	S_ISREG(mode)	(((mode) & S_IFREG) == S_IFREG)
222c0b746e5SOllivier Robert #endif
223c0b746e5SOllivier Robert 		if (stat(filename, &stats) == 0) {
224c0b746e5SOllivier Robert 			/* Hm, file exists... */
225c0b746e5SOllivier Robert 			if (S_ISREG(stats.st_mode)) {
226c0b746e5SOllivier Robert 				if (stats.st_nlink <= 1)	{
227c0b746e5SOllivier Robert 					/*
228c0b746e5SOllivier Robert 					 * Oh, it is not linked - try to save it
229c0b746e5SOllivier Robert 					 */
230c0b746e5SOllivier Robert 					savename = emalloc(len);
231c0b746e5SOllivier Robert 					snprintf(savename, len,
232c0b746e5SOllivier Robert 						"%s%c%dC%lu",
233c0b746e5SOllivier Robert 						filename, SUFFIX_SEP,
234c0b746e5SOllivier Robert 						(int)getpid(), conflicts++);
235c0b746e5SOllivier Robert 
236c0b746e5SOllivier Robert 					if (rename(filename, savename) != 0)
237c0b746e5SOllivier Robert 						msyslog(LOG_ERR,
238c0b746e5SOllivier Robert 							"couldn't save %s: %m",
239c0b746e5SOllivier Robert 							filename);
240c0b746e5SOllivier Robert 					free(savename);
241c0b746e5SOllivier Robert 				} else {
242c0b746e5SOllivier Robert 					/*
243c0b746e5SOllivier Robert 					 * there is at least a second link to
244c0b746e5SOllivier Robert 					 * this file.
245c0b746e5SOllivier Robert 					 * just remove the conflicting one
246c0b746e5SOllivier Robert 					 */
247c0b746e5SOllivier Robert 					if (
248c0b746e5SOllivier Robert #if !defined(VMS)
249c0b746e5SOllivier Robert 						unlink(filename) != 0
250c0b746e5SOllivier Robert #else
251c0b746e5SOllivier Robert 						delete(filename) != 0
252c0b746e5SOllivier Robert #endif
253c0b746e5SOllivier Robert 						)
254c0b746e5SOllivier Robert 						msyslog(LOG_ERR,
255c0b746e5SOllivier Robert 							"couldn't unlink %s: %m",
256c0b746e5SOllivier Robert 							filename);
257c0b746e5SOllivier Robert 				}
258c0b746e5SOllivier Robert 			} else {
259c0b746e5SOllivier Robert 				/*
260c0b746e5SOllivier Robert 				 * Ehh? Not a regular file ?? strange !!!!
261c0b746e5SOllivier Robert 				 */
262c0b746e5SOllivier Robert 				msyslog(LOG_ERR,
263c0b746e5SOllivier Robert 					"expected regular file for %s "
264c0b746e5SOllivier Robert 					"(found mode 0%lo)",
265c0b746e5SOllivier Robert 					filename,
266c0b746e5SOllivier Robert 					(unsigned long)stats.st_mode);
267c0b746e5SOllivier Robert 			}
268c0b746e5SOllivier Robert 		} else {
269c0b746e5SOllivier Robert 			/*
270c0b746e5SOllivier Robert 			 * stat(..) failed, but it is absolutely correct for
271c0b746e5SOllivier Robert 			 * 'basename' not to exist
272c0b746e5SOllivier Robert 			 */
273c0b746e5SOllivier Robert 			if (ENOENT != errno)
274c0b746e5SOllivier Robert 				msyslog(LOG_ERR, "stat(%s) failed: %m",
275c0b746e5SOllivier Robert 						 filename);
276c0b746e5SOllivier Robert 		}
277c0b746e5SOllivier Robert 	}
278c0b746e5SOllivier Robert 
279c0b746e5SOllivier Robert 	/*
280c0b746e5SOllivier Robert 	 * now, try to open new file generation...
281c0b746e5SOllivier Robert 	 */
282c0b746e5SOllivier Robert 	DPRINTF(4, ("opening filegen (type=%d/stamp=%u) \"%s\"\n",
283c0b746e5SOllivier Robert 		    gen->type, stamp, fullname));
284c0b746e5SOllivier Robert 
285c0b746e5SOllivier Robert 	fp = fopen(fullname, "a");
286c0b746e5SOllivier Robert 
287c0b746e5SOllivier Robert 	if (NULL == fp)	{
288c0b746e5SOllivier Robert 		/* open failed -- keep previous state
289c0b746e5SOllivier Robert 		 *
290c0b746e5SOllivier Robert 		 * If the file was open before keep the previous generation.
291c0b746e5SOllivier Robert 		 * This will cause output to end up in the 'wrong' file,
292c0b746e5SOllivier Robert 		 * but I think this is still better than losing output
293c0b746e5SOllivier Robert 		 *
294c0b746e5SOllivier Robert 		 * ignore errors due to missing directories
295c0b746e5SOllivier Robert 		 */
296c0b746e5SOllivier Robert 
297c0b746e5SOllivier Robert 		if (ENOENT != errno)
298c0b746e5SOllivier Robert 			msyslog(LOG_ERR, "can't open %s: %m", fullname);
299c0b746e5SOllivier Robert 	} else {
300c0b746e5SOllivier Robert 		if (NULL != gen->fp) {
301c0b746e5SOllivier Robert 			fclose(gen->fp);
302c0b746e5SOllivier Robert 			gen->fp = NULL;
303c0b746e5SOllivier Robert 		}
304c0b746e5SOllivier Robert 		gen->fp = fp;
305c0b746e5SOllivier Robert 
306c0b746e5SOllivier Robert 		if (gen->flag & FGEN_FLAG_LINK) {
307c0b746e5SOllivier Robert 			/*
308c0b746e5SOllivier Robert 			 * need to link file to basename
309c0b746e5SOllivier Robert 			 * have to use hardlink for now as I want to allow
310c0b746e5SOllivier Robert 			 * gen->basename spanning directory levels
311c0b746e5SOllivier Robert 			 * this would make it more complex to get the correct
312c0b746e5SOllivier Robert 			 * fullname for symlink
313c0b746e5SOllivier Robert 			 *
314c0b746e5SOllivier Robert 			 * Ok, it would just mean taking the part following
315c0b746e5SOllivier Robert 			 * the last '/' in the name.... Should add it later....
316c0b746e5SOllivier Robert 			 */
317c0b746e5SOllivier Robert 
318c0b746e5SOllivier Robert 			/* Windows NT does not support file links -Greg Schueman 1/18/97 */
3199c2daa00SOllivier Robert 
320c0b746e5SOllivier Robert #if defined(SYS_WINNT) || defined(SYS_VXWORKS)
321c0b746e5SOllivier Robert 			SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */
322c0b746e5SOllivier Robert #elif defined(VMS)
323c0b746e5SOllivier Robert 			errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */
324c0b746e5SOllivier Robert #else  /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */
325c0b746e5SOllivier Robert 			if (link(fullname, filename) != 0)
326c0b746e5SOllivier Robert 				if (EEXIST != errno)
327c0b746e5SOllivier Robert 					msyslog(LOG_ERR,
328c0b746e5SOllivier Robert 						"can't link(%s, %s): %m",
329c0b746e5SOllivier Robert 						fullname, filename);
330c0b746e5SOllivier Robert #endif /* SYS_WINNT || VXWORKS */
331c0b746e5SOllivier Robert 		}		/* flags & FGEN_FLAG_LINK */
332c0b746e5SOllivier Robert 	}			/* else fp == NULL */
333c0b746e5SOllivier Robert 
334c0b746e5SOllivier Robert 	free(filename);
335c0b746e5SOllivier Robert 	free(fullname);
336c0b746e5SOllivier Robert 	return;
337c0b746e5SOllivier Robert }
338c0b746e5SOllivier Robert 
339c0b746e5SOllivier Robert /*
340c0b746e5SOllivier Robert  * this function sets up gen->fp to point to the correct
341c0b746e5SOllivier Robert  * generation of the file for the time specified by 'now'
342c0b746e5SOllivier Robert  *
343c0b746e5SOllivier Robert  * 'now' usually is interpreted as second part of a l_fp as is in the cal...
344c0b746e5SOllivier Robert  * library routines
345c0b746e5SOllivier Robert  */
346c0b746e5SOllivier Robert 
347c0b746e5SOllivier Robert void
filegen_setup(FILEGEN * gen,u_int32 now)348c0b746e5SOllivier Robert filegen_setup(
349c0b746e5SOllivier Robert 	FILEGEN *	gen,
350c0b746e5SOllivier Robert 	u_int32		now
351c0b746e5SOllivier Robert 	)
352c0b746e5SOllivier Robert {
353c0b746e5SOllivier Robert 	int	current;
354c0b746e5SOllivier Robert 	time_t	pivot;
355c0b746e5SOllivier Robert 
356c0b746e5SOllivier Robert 	if (!(gen->flag & FGEN_FLAG_ENABLED)) {
357c0b746e5SOllivier Robert 		if (NULL != gen->fp) {
358c0b746e5SOllivier Robert 			fclose(gen->fp);
359c0b746e5SOllivier Robert 			gen->fp = NULL;
360c0b746e5SOllivier Robert 		}
361c0b746e5SOllivier Robert 		return;
362c0b746e5SOllivier Robert 	}
363c0b746e5SOllivier Robert 
364c0b746e5SOllivier Robert 	switch (gen->type) {
365c0b746e5SOllivier Robert 
366c0b746e5SOllivier Robert 	default:
367c0b746e5SOllivier Robert 	case FILEGEN_NONE:
368c0b746e5SOllivier Robert 		current = TRUE;
369c0b746e5SOllivier Robert 		break;
370c0b746e5SOllivier Robert 
371c0b746e5SOllivier Robert 	case FILEGEN_PID:
372c0b746e5SOllivier Robert 		current = ((int)gen->id_lo == getpid());
373c0b746e5SOllivier Robert 		break;
374c0b746e5SOllivier Robert 
375c0b746e5SOllivier Robert 	case FILEGEN_AGE:
376c0b746e5SOllivier Robert 		current = (gen->id_lo <= current_time) &&
377c0b746e5SOllivier Robert 			  (gen->id_hi > current_time);
378c0b746e5SOllivier Robert 		break;
379c0b746e5SOllivier Robert 
380c0b746e5SOllivier Robert 	case FILEGEN_DAY:
3819c2daa00SOllivier Robert 	case FILEGEN_WEEK:
3829c2daa00SOllivier Robert 	case FILEGEN_MONTH:
383c0b746e5SOllivier Robert 	case FILEGEN_YEAR:
384c0b746e5SOllivier Robert 		current = (gen->id_lo <= now) &&
385c0b746e5SOllivier Robert 			  (gen->id_hi > now);
386c0b746e5SOllivier Robert 		break;
387c0b746e5SOllivier Robert 	}
388c0b746e5SOllivier Robert 	/*
389c0b746e5SOllivier Robert 	 * try to open file if not yet open
390c0b746e5SOllivier Robert 	 * reopen new file generation file on change of generation id
391c0b746e5SOllivier Robert 	 */
392c0b746e5SOllivier Robert 	if (NULL == gen->fp || !current) {
393c0b746e5SOllivier Robert 		DPRINTF(1, ("filegen  %0x %u\n", gen->type, now));
394c0b746e5SOllivier Robert 		pivot = time(NULL);
395c0b746e5SOllivier Robert 		filegen_open(gen, now, &pivot);
396c0b746e5SOllivier Robert 	}
397c0b746e5SOllivier Robert }
398c0b746e5SOllivier Robert 
399c0b746e5SOllivier Robert 
400c0b746e5SOllivier Robert /*
401c0b746e5SOllivier Robert  * change settings for filegen files
402c0b746e5SOllivier Robert  */
403c0b746e5SOllivier Robert void
filegen_config(FILEGEN * gen,const char * dir,const char * fname,u_int type,u_int flag)404c0b746e5SOllivier Robert filegen_config(
405c0b746e5SOllivier Robert 	FILEGEN *	gen,
406c0b746e5SOllivier Robert 	const char *	dir,
407c0b746e5SOllivier Robert 	const char *	fname,
408c0b746e5SOllivier Robert 	u_int		type,
409c0b746e5SOllivier Robert 	u_int		flag
410c0b746e5SOllivier Robert 	)
411c0b746e5SOllivier Robert {
412c0b746e5SOllivier Robert 	int file_existed;
413c0b746e5SOllivier Robert 	l_fp now;
414c0b746e5SOllivier Robert 
415c0b746e5SOllivier Robert 
416c0b746e5SOllivier Robert 	/*
417c0b746e5SOllivier Robert 	 * if nothing would be changed...
418c0b746e5SOllivier Robert 	 */
419c0b746e5SOllivier Robert 	if (strcmp(dir, gen->dir) == 0 && strcmp(fname, gen->fname) == 0
420c0b746e5SOllivier Robert 	    && type == gen->type && flag == gen->flag)
421c0b746e5SOllivier Robert 		return;
422c0b746e5SOllivier Robert 
423c0b746e5SOllivier Robert 	/*
424c0b746e5SOllivier Robert 	 * validate parameters
425c0b746e5SOllivier Robert 	 */
426c0b746e5SOllivier Robert 	if (!valid_fileref(dir, fname))
427c0b746e5SOllivier Robert 		return;
428c0b746e5SOllivier Robert 
429c0b746e5SOllivier Robert 	if (NULL != gen->fp) {
430c0b746e5SOllivier Robert 		fclose(gen->fp);
431c0b746e5SOllivier Robert 		gen->fp = NULL;
432c0b746e5SOllivier Robert 		file_existed = TRUE;
433c0b746e5SOllivier Robert 	} else {
434c0b746e5SOllivier Robert 		file_existed = FALSE;
435c0b746e5SOllivier Robert 	}
436c0b746e5SOllivier Robert 
437c0b746e5SOllivier Robert 	DPRINTF(3, ("configuring filegen:\n"
438c0b746e5SOllivier Robert 		    "\tdir:\t%s -> %s\n"
439c0b746e5SOllivier Robert 		    "\tfname:\t%s -> %s\n"
440c0b746e5SOllivier Robert 		    "\ttype:\t%d -> %d\n"
441c0b746e5SOllivier Robert 		    "\tflag: %x -> %x\n",
442c0b746e5SOllivier Robert 		    gen->dir, dir,
443c0b746e5SOllivier Robert 		    gen->fname, fname,
444c0b746e5SOllivier Robert 		    gen->type, type,
445c0b746e5SOllivier Robert 		    gen->flag, flag));
446c0b746e5SOllivier Robert 
447c0b746e5SOllivier Robert 	if (strcmp(gen->dir, dir) != 0) {
448c0b746e5SOllivier Robert 		free(gen->dir);
449c0b746e5SOllivier Robert 		gen->dir = estrdup(dir);
450c0b746e5SOllivier Robert 	}
451c0b746e5SOllivier Robert 
452c0b746e5SOllivier Robert 	if (strcmp(gen->fname, fname) != 0) {
453c0b746e5SOllivier Robert 		free(gen->fname);
454c0b746e5SOllivier Robert 		gen->fname = estrdup(fname);
455c0b746e5SOllivier Robert 	}
456c0b746e5SOllivier Robert 	gen->type = (u_char)type;
457c0b746e5SOllivier Robert 	gen->flag = (u_char)flag;
458c0b746e5SOllivier Robert 
459c0b746e5SOllivier Robert 	/*
460c0b746e5SOllivier Robert 	 * make filegen use the new settings
461c0b746e5SOllivier Robert 	 * special action is only required when a generation file
462c0b746e5SOllivier Robert 	 * is currently open
463c0b746e5SOllivier Robert 	 * otherwise the new settings will be used anyway at the next open
464c0b746e5SOllivier Robert 	 */
465c0b746e5SOllivier Robert 	if (file_existed) {
466c0b746e5SOllivier Robert 		get_systime(&now);
467c0b746e5SOllivier Robert 		filegen_setup(gen, now.l_ui);
468c0b746e5SOllivier Robert 	}
469c0b746e5SOllivier Robert }
470c0b746e5SOllivier Robert 
471c0b746e5SOllivier Robert 
472c0b746e5SOllivier Robert /*
473c0b746e5SOllivier Robert  * check whether concatenating prefix and basename
474c0b746e5SOllivier Robert  * yields a legal filename
475c0b746e5SOllivier Robert  */
476c0b746e5SOllivier Robert static int
valid_fileref(const char * dir,const char * fname)477c0b746e5SOllivier Robert valid_fileref(
478c0b746e5SOllivier Robert 	const char *	dir,
479c0b746e5SOllivier Robert 	const char *	fname
480c0b746e5SOllivier Robert 	)
481c0b746e5SOllivier Robert {
482c0b746e5SOllivier Robert 	/*
483c0b746e5SOllivier Robert 	 * dir cannot be changed dynamically
484c0b746e5SOllivier Robert 	 * (within the context of filegen)
485c0b746e5SOllivier Robert 	 * so just reject basenames containing '..'
486c0b746e5SOllivier Robert 	 *
487c0b746e5SOllivier Robert 	 * ASSUMPTION:
488c0b746e5SOllivier Robert 	 *		file system parts 'below' dir may be
489c0b746e5SOllivier Robert 	 *		specified without infringement of security
490c0b746e5SOllivier Robert 	 *
491c0b746e5SOllivier Robert 	 *		restricting dir to legal values
492c0b746e5SOllivier Robert 	 *		has to be ensured by other means
493c0b746e5SOllivier Robert 	 * (however, it would be possible to perform some checks here...)
494c0b746e5SOllivier Robert 	 */
495c0b746e5SOllivier Robert 	const char *p;
496c0b746e5SOllivier Robert 
497c0b746e5SOllivier Robert 	/*
498c0b746e5SOllivier Robert 	 * Just to catch, dumb errors opening up the world...
499c0b746e5SOllivier Robert 	 */
500c0b746e5SOllivier Robert 	if (NULL == dir || '\0' == dir[0])
501c0b746e5SOllivier Robert 		return FALSE;
502c0b746e5SOllivier Robert 
503c0b746e5SOllivier Robert 	if (NULL == fname)
504c0b746e5SOllivier Robert 		return FALSE;
505c0b746e5SOllivier Robert 
506c0b746e5SOllivier Robert #ifdef SYS_WINNT
507c0b746e5SOllivier Robert 	/*
508c0b746e5SOllivier Robert 	 * Windows treats / equivalent to \, reject any / to ensure
509c0b746e5SOllivier Robert 	 * check below for DIR_SEP (\ on windows) are adequate.
510c0b746e5SOllivier Robert 	 */
511c0b746e5SOllivier Robert 	if (strchr(fname, '/')) {
512c0b746e5SOllivier Robert 		msyslog(LOG_ERR,
513c0b746e5SOllivier Robert 			"filegen filenames must not contain '/': %s",
514c0b746e5SOllivier Robert 			fname);
515c0b746e5SOllivier Robert 		return FALSE;
516c0b746e5SOllivier Robert 	}
517c0b746e5SOllivier Robert #endif
518c0b746e5SOllivier Robert 
519c0b746e5SOllivier Robert 	for (p = fname; p != NULL; p = strchr(p, DIR_SEP)) {
520c0b746e5SOllivier Robert 		if ('.' == p[0] && '.' == p[1]
521c0b746e5SOllivier Robert 		    && ('\0' == p[2] || DIR_SEP == p[2]))
522c0b746e5SOllivier Robert 			return FALSE;
523c0b746e5SOllivier Robert 	}
524c0b746e5SOllivier Robert 
525c0b746e5SOllivier Robert 	return TRUE;
526c0b746e5SOllivier Robert }
527c0b746e5SOllivier Robert 
528c0b746e5SOllivier Robert 
529c0b746e5SOllivier Robert /*
530c0b746e5SOllivier Robert  * filegen registry
531c0b746e5SOllivier Robert  */
532c0b746e5SOllivier Robert 
533c0b746e5SOllivier Robert static struct filegen_entry {
534c0b746e5SOllivier Robert 	char *			name;
535c0b746e5SOllivier Robert 	FILEGEN *		filegen;
536c0b746e5SOllivier Robert 	struct filegen_entry *	next;
537c0b746e5SOllivier Robert } *filegen_registry = NULL;
538c0b746e5SOllivier Robert 
539c0b746e5SOllivier Robert 
540c0b746e5SOllivier Robert FILEGEN *
filegen_get(const char * name)541c0b746e5SOllivier Robert filegen_get(
542c0b746e5SOllivier Robert 	const char *	name
543c0b746e5SOllivier Robert 	)
544c0b746e5SOllivier Robert {
545c0b746e5SOllivier Robert 	struct filegen_entry *f = filegen_registry;
546c0b746e5SOllivier Robert 
547c0b746e5SOllivier Robert 	while (f) {
548 		if (f->name == name || strcmp(name, f->name) == 0) {
549 			DPRINTF(4, ("filegen_get(%s) = %p\n",
550 				    name, f->filegen));
551 			return f->filegen;
552 		}
553 		f = f->next;
554 	}
555 	DPRINTF(4, ("filegen_get(%s) = NULL\n", name));
556 	return NULL;
557 }
558 
559 
560 void
filegen_register(const char * dir,const char * name,FILEGEN * filegen)561 filegen_register(
562 	const char *	dir,
563 	const char *	name,
564 	FILEGEN *	filegen
565 	)
566 {
567 	struct filegen_entry **ppfe;
568 
569 	DPRINTF(4, ("filegen_register(%s, %p)\n", name, filegen));
570 
571 	filegen_init(dir, name, filegen);
572 
573 	ppfe = &filegen_registry;
574 	while (NULL != *ppfe) {
575 		if ((*ppfe)->name == name
576 		    || !strcmp((*ppfe)->name, name)) {
577 
578 			DPRINTF(5, ("replacing filegen %p\n",
579 				    (*ppfe)->filegen));
580 
581 			(*ppfe)->filegen = filegen;
582 			return;
583 		}
584 		ppfe = &((*ppfe)->next);
585 	}
586 
587 	*ppfe = emalloc(sizeof **ppfe);
588 
589 	(*ppfe)->next = NULL;
590 	(*ppfe)->name = estrdup(name);
591 	(*ppfe)->filegen = filegen;
592 
593 	DPRINTF(6, ("adding new filegen\n"));
594 
595 	return;
596 }
597 
598 
599 /*
600  * filegen_statsdir() - reset each filegen entry's dir to statsdir.
601  */
602 void
filegen_statsdir(void)603 filegen_statsdir(void)
604 {
605 	struct filegen_entry *f;
606 
607 	for (f = filegen_registry; f != NULL; f = f->next)
608 		filegen_config(f->filegen, statsdir, f->filegen->fname,
609 			       f->filegen->type, f->filegen->flag);
610 }
611 
612 
613 /*
614  * filegen_unregister frees memory allocated by filegen_register for
615  * name.
616  */
617 #ifdef DEBUG
618 void
filegen_unregister(const char * name)619 filegen_unregister(
620 	const char *name
621 	)
622 {
623 	struct filegen_entry **	ppfe;
624 	struct filegen_entry *	pfe;
625 	FILEGEN *		fg;
626 
627 	DPRINTF(4, ("filegen_unregister(%s)\n", name));
628 
629 	ppfe = &filegen_registry;
630 
631 	while (NULL != *ppfe) {
632 		if ((*ppfe)->name == name
633 		    || !strcmp((*ppfe)->name, name)) {
634 			pfe = *ppfe;
635 			*ppfe = (*ppfe)->next;
636 			fg = pfe->filegen;
637 			free(pfe->name);
638 			free(pfe);
639 			filegen_uninit(fg);
640 			break;
641 		}
642 		ppfe = &((*ppfe)->next);
643 	}
644 }
645 #endif	/* DEBUG */
646