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
9*2b15cb3dSCy Schubert * 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
47*2b15cb3dSCy Schubert static void filegen_open (FILEGEN *, u_int32, const time_t*);
48*2b15cb3dSCy Schubert static int valid_fileref (const char *, const char *);
49*2b15cb3dSCy Schubert static void filegen_init (const char *, const char *, FILEGEN *);
50*2b15cb3dSCy Schubert #ifdef DEBUG
51*2b15cb3dSCy Schubert static void filegen_uninit (FILEGEN *);
52*2b15cb3dSCy Schubert #endif /* DEBUG */
53c0b746e5SOllivier Robert
54ea906c41SOllivier Robert
55ea906c41SOllivier Robert /*
56ea906c41SOllivier Robert * filegen_init
57ea906c41SOllivier Robert */
58ea906c41SOllivier Robert
59ea906c41SOllivier Robert static void
filegen_init(const char * dir,const char * fname,FILEGEN * fgp)60*2b15cb3dSCy Schubert filegen_init(
61*2b15cb3dSCy Schubert const char * dir,
62*2b15cb3dSCy Schubert const char * fname,
63*2b15cb3dSCy Schubert FILEGEN * fgp
64*2b15cb3dSCy Schubert )
65ea906c41SOllivier Robert {
66*2b15cb3dSCy Schubert fgp->fp = NULL;
67*2b15cb3dSCy Schubert fgp->dir = estrdup(dir);
68*2b15cb3dSCy Schubert fgp->fname = estrdup(fname);
69*2b15cb3dSCy Schubert fgp->id_lo = 0;
70*2b15cb3dSCy Schubert fgp->id_hi = 0;
71*2b15cb3dSCy Schubert fgp->type = FILEGEN_DAY;
72*2b15cb3dSCy Schubert fgp->flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
73ea906c41SOllivier Robert }
74ea906c41SOllivier Robert
75ea906c41SOllivier Robert
76c0b746e5SOllivier Robert /*
77*2b15cb3dSCy Schubert * filegen_uninit - free memory allocated by filegen_init
78*2b15cb3dSCy Schubert */
79*2b15cb3dSCy Schubert #ifdef DEBUG
80*2b15cb3dSCy Schubert static void
filegen_uninit(FILEGEN * fgp)81*2b15cb3dSCy Schubert filegen_uninit(
82*2b15cb3dSCy Schubert FILEGEN *fgp
83*2b15cb3dSCy Schubert )
84*2b15cb3dSCy Schubert {
85*2b15cb3dSCy Schubert free(fgp->dir);
86*2b15cb3dSCy Schubert free(fgp->fname);
87*2b15cb3dSCy Schubert }
88*2b15cb3dSCy Schubert #endif
89*2b15cb3dSCy Schubert
90*2b15cb3dSCy Schubert
91*2b15cb3dSCy Schubert /*
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,
99*2b15cb3dSCy Schubert u_int32 stamp,
100*2b15cb3dSCy Schubert const time_t * pivot
101c0b746e5SOllivier Robert )
102c0b746e5SOllivier Robert {
103*2b15cb3dSCy Schubert char *savename; /* temp store for name collision handling */
104*2b15cb3dSCy Schubert char *fullname; /* name with any designation extension */
105*2b15cb3dSCy Schubert char *filename; /* name without designation extension */
106*2b15cb3dSCy Schubert char *suffix; /* where to print suffix extension */
107*2b15cb3dSCy Schubert u_int len, suflen;
108c0b746e5SOllivier Robert FILE *fp;
109c0b746e5SOllivier Robert struct calendar cal;
110*2b15cb3dSCy Schubert struct isodate iso;
111c0b746e5SOllivier Robert
112*2b15cb3dSCy Schubert /* get basic filename in buffer, leave room for extensions */
113*2b15cb3dSCy Schubert len = strlen(gen->dir) + strlen(gen->fname) + 65;
114*2b15cb3dSCy Schubert filename = emalloc(len);
115*2b15cb3dSCy Schubert fullname = emalloc(len);
116*2b15cb3dSCy Schubert savename = NULL;
117*2b15cb3dSCy Schubert snprintf(filename, len, "%s%s", gen->dir, gen->fname);
118*2b15cb3dSCy Schubert
119*2b15cb3dSCy Schubert /* where to place suffix */
120*2b15cb3dSCy Schubert suflen = strlcpy(fullname, filename, len);
121*2b15cb3dSCy Schubert suffix = fullname + suflen;
122*2b15cb3dSCy Schubert suflen = len - suflen;
123*2b15cb3dSCy Schubert
124*2b15cb3dSCy Schubert /* last octet of fullname set to '\0' for truncation check */
125*2b15cb3dSCy Schubert fullname[len - 1] = '\0';
126c0b746e5SOllivier Robert
127c0b746e5SOllivier Robert switch (gen->type) {
128c0b746e5SOllivier Robert
129*2b15cb3dSCy Schubert default:
130*2b15cb3dSCy Schubert msyslog(LOG_ERR,
131*2b15cb3dSCy Schubert "unsupported file generations type %d for "
132*2b15cb3dSCy Schubert "\"%s\" - reverting to FILEGEN_NONE",
133*2b15cb3dSCy Schubert gen->type, filename);
134*2b15cb3dSCy Schubert gen->type = FILEGEN_NONE;
135*2b15cb3dSCy Schubert break;
136*2b15cb3dSCy Schubert
137c0b746e5SOllivier Robert case FILEGEN_NONE:
138*2b15cb3dSCy Schubert /* no suffix, all set */
139c0b746e5SOllivier Robert break;
140c0b746e5SOllivier Robert
141c0b746e5SOllivier Robert case FILEGEN_PID:
142*2b15cb3dSCy Schubert gen->id_lo = getpid();
143*2b15cb3dSCy Schubert gen->id_hi = 0;
144*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%c#%ld",
145*2b15cb3dSCy Schubert SUFFIX_SEP, gen->id_lo);
146c0b746e5SOllivier Robert break;
147c0b746e5SOllivier Robert
148c0b746e5SOllivier Robert case FILEGEN_DAY:
149*2b15cb3dSCy Schubert /*
150*2b15cb3dSCy Schubert * You can argue here in favor of using MJD, but I
151*2b15cb3dSCy Schubert * would assume it to be easier for humans to interpret
152*2b15cb3dSCy Schubert * dates in a format they are used to in everyday life.
153c0b746e5SOllivier Robert */
154*2b15cb3dSCy Schubert ntpcal_ntp_to_date(&cal, stamp, pivot);
155*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%c%04d%02d%02d",
156*2b15cb3dSCy Schubert SUFFIX_SEP, cal.year, cal.month, cal.monthday);
157*2b15cb3dSCy Schubert cal.hour = cal.minute = cal.second = 0;
158*2b15cb3dSCy Schubert gen->id_lo = ntpcal_date_to_ntp(&cal);
159*2b15cb3dSCy Schubert gen->id_hi = (u_int32)(gen->id_lo + SECSPERDAY);
160c0b746e5SOllivier Robert break;
161c0b746e5SOllivier Robert
162c0b746e5SOllivier Robert case FILEGEN_WEEK:
163*2b15cb3dSCy Schubert isocal_ntp_to_date(&iso, stamp, pivot);
164*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%c%04dw%02d",
165*2b15cb3dSCy Schubert SUFFIX_SEP, iso.year, iso.week);
166*2b15cb3dSCy Schubert iso.hour = iso.minute = iso.second = 0;
167*2b15cb3dSCy Schubert iso.weekday = 1;
168*2b15cb3dSCy Schubert gen->id_lo = isocal_date_to_ntp(&iso);
169*2b15cb3dSCy Schubert gen->id_hi = (u_int32)(gen->id_lo + 7 * SECSPERDAY);
170c0b746e5SOllivier Robert break;
171c0b746e5SOllivier Robert
172c0b746e5SOllivier Robert case FILEGEN_MONTH:
173*2b15cb3dSCy Schubert ntpcal_ntp_to_date(&cal, stamp, pivot);
174*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%c%04d%02d",
175*2b15cb3dSCy Schubert SUFFIX_SEP, cal.year, cal.month);
176*2b15cb3dSCy Schubert cal.hour = cal.minute = cal.second = 0;
177*2b15cb3dSCy Schubert cal.monthday = 1;
178*2b15cb3dSCy Schubert gen->id_lo = ntpcal_date_to_ntp(&cal);
179*2b15cb3dSCy Schubert cal.month++;
180*2b15cb3dSCy Schubert gen->id_hi = ntpcal_date_to_ntp(&cal);
181c0b746e5SOllivier Robert break;
182c0b746e5SOllivier Robert
183c0b746e5SOllivier Robert case FILEGEN_YEAR:
184*2b15cb3dSCy Schubert ntpcal_ntp_to_date(&cal, stamp, pivot);
185*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%c%04d",
186*2b15cb3dSCy Schubert SUFFIX_SEP, cal.year);
187*2b15cb3dSCy Schubert cal.hour = cal.minute = cal.second = 0;
188*2b15cb3dSCy Schubert cal.month = cal.monthday = 1;
189*2b15cb3dSCy Schubert gen->id_lo = ntpcal_date_to_ntp(&cal);
190*2b15cb3dSCy Schubert cal.year++;
191*2b15cb3dSCy Schubert gen->id_hi = ntpcal_date_to_ntp(&cal);
192c0b746e5SOllivier Robert break;
193c0b746e5SOllivier Robert
194c0b746e5SOllivier Robert case FILEGEN_AGE:
195*2b15cb3dSCy Schubert gen->id_lo = current_time - (current_time % SECSPERDAY);
196*2b15cb3dSCy Schubert gen->id_hi = gen->id_lo + SECSPERDAY;
197*2b15cb3dSCy Schubert snprintf(suffix, suflen, "%ca%08ld",
198*2b15cb3dSCy Schubert SUFFIX_SEP, gen->id_lo);
199c0b746e5SOllivier Robert }
200c0b746e5SOllivier Robert
201*2b15cb3dSCy Schubert /* check possible truncation */
202*2b15cb3dSCy Schubert if ('\0' != fullname[len - 1]) {
203*2b15cb3dSCy Schubert fullname[len - 1] = '\0';
204*2b15cb3dSCy Schubert msyslog(LOG_ERR, "logfile name truncated: \"%s\"",
205*2b15cb3dSCy Schubert fullname);
206*2b15cb3dSCy Schubert }
207*2b15cb3dSCy Schubert
208*2b15cb3dSCy Schubert 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
217c0b746e5SOllivier 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
223*2b15cb3dSCy Schubert 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 */
230*2b15cb3dSCy Schubert savename = emalloc(len);
231*2b15cb3dSCy Schubert snprintf(savename, len,
232*2b15cb3dSCy Schubert "%s%c%dC%lu",
233*2b15cb3dSCy Schubert filename, SUFFIX_SEP,
234*2b15cb3dSCy Schubert (int)getpid(), conflicts++);
235*2b15cb3dSCy Schubert
236*2b15cb3dSCy Schubert if (rename(filename, savename) != 0)
237*2b15cb3dSCy Schubert msyslog(LOG_ERR,
238*2b15cb3dSCy Schubert "couldn't save %s: %m",
239*2b15cb3dSCy Schubert filename);
240c0b746e5SOllivier Robert free(savename);
241c0b746e5SOllivier Robert } else {
242c0b746e5SOllivier Robert /*
243ea906c41SOllivier Robert * there is at least a second link to
244ea906c41SOllivier Robert * this file.
245c0b746e5SOllivier Robert * just remove the conflicting one
246c0b746e5SOllivier Robert */
247c0b746e5SOllivier Robert if (
248c0b746e5SOllivier Robert #if !defined(VMS)
249*2b15cb3dSCy Schubert unlink(filename) != 0
250c0b746e5SOllivier Robert #else
251*2b15cb3dSCy Schubert delete(filename) != 0
252c0b746e5SOllivier Robert #endif
253c0b746e5SOllivier Robert )
254*2b15cb3dSCy Schubert msyslog(LOG_ERR,
255*2b15cb3dSCy Schubert "couldn't unlink %s: %m",
256*2b15cb3dSCy Schubert filename);
257c0b746e5SOllivier Robert }
258c0b746e5SOllivier Robert } else {
259c0b746e5SOllivier Robert /*
260c0b746e5SOllivier Robert * Ehh? Not a regular file ?? strange !!!!
261c0b746e5SOllivier Robert */
262*2b15cb3dSCy Schubert msyslog(LOG_ERR,
263*2b15cb3dSCy Schubert "expected regular file for %s "
264*2b15cb3dSCy Schubert "(found mode 0%lo)",
265*2b15cb3dSCy Schubert filename,
266*2b15cb3dSCy Schubert (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 */
273*2b15cb3dSCy Schubert if (ENOENT != errno)
274*2b15cb3dSCy Schubert msyslog(LOG_ERR, "stat(%s) failed: %m",
275*2b15cb3dSCy Schubert filename);
276c0b746e5SOllivier Robert }
277c0b746e5SOllivier Robert }
278c0b746e5SOllivier Robert
279c0b746e5SOllivier Robert /*
280c0b746e5SOllivier Robert * now, try to open new file generation...
281c0b746e5SOllivier Robert */
282*2b15cb3dSCy Schubert DPRINTF(4, ("opening filegen (type=%d/stamp=%u) \"%s\"\n",
283*2b15cb3dSCy Schubert gen->type, stamp, fullname));
284c0b746e5SOllivier Robert
285*2b15cb3dSCy Schubert fp = fopen(fullname, "a");
286c0b746e5SOllivier Robert
287*2b15cb3dSCy Schubert 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,
2929c2daa00SOllivier 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
297*2b15cb3dSCy Schubert if (ENOENT != errno)
298*2b15cb3dSCy Schubert msyslog(LOG_ERR, "can't open %s: %m", fullname);
299c0b746e5SOllivier Robert } else {
300*2b15cb3dSCy Schubert if (NULL != gen->fp) {
301c0b746e5SOllivier Robert fclose(gen->fp);
302*2b15cb3dSCy Schubert 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
312*2b15cb3dSCy Schubert * 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 */
319c0b746e5SOllivier Robert
320*2b15cb3dSCy Schubert #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) */
325*2b15cb3dSCy Schubert if (link(fullname, filename) != 0)
326*2b15cb3dSCy Schubert if (EEXIST != errno)
327*2b15cb3dSCy Schubert msyslog(LOG_ERR,
328*2b15cb3dSCy Schubert "can't link(%s, %s): %m",
329*2b15cb3dSCy Schubert 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);
335*2b15cb3dSCy Schubert 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,
350*2b15cb3dSCy Schubert u_int32 now
351c0b746e5SOllivier Robert )
352c0b746e5SOllivier Robert {
353*2b15cb3dSCy Schubert int current;
354*2b15cb3dSCy Schubert time_t pivot;
355c0b746e5SOllivier Robert
356c0b746e5SOllivier Robert if (!(gen->flag & FGEN_FLAG_ENABLED)) {
357*2b15cb3dSCy Schubert if (NULL != gen->fp) {
358c0b746e5SOllivier Robert fclose(gen->fp);
359*2b15cb3dSCy Schubert gen->fp = NULL;
360*2b15cb3dSCy Schubert }
361c0b746e5SOllivier Robert return;
362c0b746e5SOllivier Robert }
363c0b746e5SOllivier Robert
364c0b746e5SOllivier Robert switch (gen->type) {
365*2b15cb3dSCy Schubert
366*2b15cb3dSCy Schubert default:
367c0b746e5SOllivier Robert case FILEGEN_NONE:
368*2b15cb3dSCy Schubert current = TRUE;
369c0b746e5SOllivier Robert break;
370c0b746e5SOllivier Robert
371c0b746e5SOllivier Robert case FILEGEN_PID:
372*2b15cb3dSCy Schubert current = ((int)gen->id_lo == getpid());
373c0b746e5SOllivier Robert break;
374c0b746e5SOllivier Robert
375c0b746e5SOllivier Robert case FILEGEN_AGE:
376*2b15cb3dSCy Schubert current = (gen->id_lo <= current_time) &&
377*2b15cb3dSCy Schubert (gen->id_hi > current_time);
378*2b15cb3dSCy Schubert break;
379*2b15cb3dSCy Schubert
380*2b15cb3dSCy Schubert case FILEGEN_DAY:
381*2b15cb3dSCy Schubert case FILEGEN_WEEK:
382*2b15cb3dSCy Schubert case FILEGEN_MONTH:
383*2b15cb3dSCy Schubert case FILEGEN_YEAR:
384*2b15cb3dSCy Schubert current = (gen->id_lo <= now) &&
385*2b15cb3dSCy Schubert (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 */
392*2b15cb3dSCy Schubert if (NULL == gen->fp || !current) {
393*2b15cb3dSCy Schubert DPRINTF(1, ("filegen %0x %u\n", gen->type, now));
394*2b15cb3dSCy Schubert pivot = time(NULL);
395*2b15cb3dSCy Schubert 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,
406*2b15cb3dSCy Schubert const char * dir,
407*2b15cb3dSCy Schubert const char * fname,
408c0b746e5SOllivier Robert u_int type,
409c0b746e5SOllivier Robert u_int flag
410c0b746e5SOllivier Robert )
411c0b746e5SOllivier Robert {
412*2b15cb3dSCy Schubert int file_existed;
413*2b15cb3dSCy Schubert l_fp now;
414*2b15cb3dSCy Schubert
415*2b15cb3dSCy Schubert
416c0b746e5SOllivier Robert /*
417c0b746e5SOllivier Robert * if nothing would be changed...
418c0b746e5SOllivier Robert */
419*2b15cb3dSCy Schubert if (strcmp(dir, gen->dir) == 0 && strcmp(fname, gen->fname) == 0
420*2b15cb3dSCy Schubert && type == gen->type && flag == gen->flag)
421c0b746e5SOllivier Robert return;
422c0b746e5SOllivier Robert
423c0b746e5SOllivier Robert /*
424c0b746e5SOllivier Robert * validate parameters
425c0b746e5SOllivier Robert */
426*2b15cb3dSCy Schubert if (!valid_fileref(dir, fname))
427c0b746e5SOllivier Robert return;
428c0b746e5SOllivier Robert
429*2b15cb3dSCy Schubert if (NULL != gen->fp) {
430c0b746e5SOllivier Robert fclose(gen->fp);
431*2b15cb3dSCy Schubert gen->fp = NULL;
432*2b15cb3dSCy Schubert file_existed = TRUE;
433*2b15cb3dSCy Schubert } else {
434*2b15cb3dSCy Schubert file_existed = FALSE;
435*2b15cb3dSCy Schubert }
436c0b746e5SOllivier Robert
437*2b15cb3dSCy Schubert DPRINTF(3, ("configuring filegen:\n"
438*2b15cb3dSCy Schubert "\tdir:\t%s -> %s\n"
439*2b15cb3dSCy Schubert "\tfname:\t%s -> %s\n"
440*2b15cb3dSCy Schubert "\ttype:\t%d -> %d\n"
441*2b15cb3dSCy Schubert "\tflag: %x -> %x\n",
442*2b15cb3dSCy Schubert gen->dir, dir,
443*2b15cb3dSCy Schubert gen->fname, fname,
444*2b15cb3dSCy Schubert gen->type, type,
445*2b15cb3dSCy Schubert gen->flag, flag));
446*2b15cb3dSCy Schubert
447*2b15cb3dSCy Schubert if (strcmp(gen->dir, dir) != 0) {
448*2b15cb3dSCy Schubert free(gen->dir);
449*2b15cb3dSCy Schubert gen->dir = estrdup(dir);
450*2b15cb3dSCy Schubert }
451*2b15cb3dSCy Schubert
452*2b15cb3dSCy Schubert if (strcmp(gen->fname, fname) != 0) {
453*2b15cb3dSCy Schubert free(gen->fname);
454*2b15cb3dSCy Schubert gen->fname = estrdup(fname);
455c0b746e5SOllivier Robert }
4569c2daa00SOllivier Robert gen->type = (u_char)type;
4579c2daa00SOllivier 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 */
465*2b15cb3dSCy Schubert 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(
478*2b15cb3dSCy Schubert const char * dir,
479*2b15cb3dSCy Schubert const char * fname
480c0b746e5SOllivier Robert )
481c0b746e5SOllivier Robert {
482c0b746e5SOllivier Robert /*
483*2b15cb3dSCy Schubert * dir cannot be changed dynamically
484c0b746e5SOllivier Robert * (within the context of filegen)
485c0b746e5SOllivier Robert * so just reject basenames containing '..'
486c0b746e5SOllivier Robert *
487c0b746e5SOllivier Robert * ASSUMPTION:
488*2b15cb3dSCy Schubert * file system parts 'below' dir may be
489c0b746e5SOllivier Robert * specified without infringement of security
490c0b746e5SOllivier Robert *
491*2b15cb3dSCy Schubert * 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 */
495*2b15cb3dSCy Schubert const char *p;
496c0b746e5SOllivier Robert
497c0b746e5SOllivier Robert /*
498c0b746e5SOllivier Robert * Just to catch, dumb errors opening up the world...
499c0b746e5SOllivier Robert */
500*2b15cb3dSCy Schubert if (NULL == dir || '\0' == dir[0])
501*2b15cb3dSCy Schubert return FALSE;
502c0b746e5SOllivier Robert
503*2b15cb3dSCy Schubert if (NULL == fname)
504*2b15cb3dSCy Schubert return FALSE;
505c0b746e5SOllivier Robert
506*2b15cb3dSCy Schubert #ifdef SYS_WINNT
507*2b15cb3dSCy Schubert /*
508*2b15cb3dSCy Schubert * Windows treats / equivalent to \, reject any / to ensure
509*2b15cb3dSCy Schubert * check below for DIR_SEP (\ on windows) are adequate.
510*2b15cb3dSCy Schubert */
511*2b15cb3dSCy Schubert if (strchr(fname, '/')) {
512*2b15cb3dSCy Schubert msyslog(LOG_ERR,
513*2b15cb3dSCy Schubert "filegen filenames must not contain '/': %s",
514*2b15cb3dSCy Schubert fname);
515*2b15cb3dSCy Schubert return FALSE;
516*2b15cb3dSCy Schubert }
517*2b15cb3dSCy Schubert #endif
518*2b15cb3dSCy Schubert
519*2b15cb3dSCy Schubert for (p = fname; p != NULL; p = strchr(p, DIR_SEP)) {
520*2b15cb3dSCy Schubert if ('.' == p[0] && '.' == p[1]
521*2b15cb3dSCy Schubert && ('\0' == p[2] || DIR_SEP == p[2]))
522*2b15cb3dSCy Schubert return FALSE;
523c0b746e5SOllivier Robert }
524c0b746e5SOllivier Robert
525*2b15cb3dSCy Schubert 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(
542*2b15cb3dSCy Schubert const char * name
543c0b746e5SOllivier Robert )
544c0b746e5SOllivier Robert {
545c0b746e5SOllivier Robert struct filegen_entry *f = filegen_registry;
546c0b746e5SOllivier Robert
547c0b746e5SOllivier Robert while (f) {
548c0b746e5SOllivier Robert if (f->name == name || strcmp(name, f->name) == 0) {
549*2b15cb3dSCy Schubert DPRINTF(4, ("filegen_get(%s) = %p\n",
550*2b15cb3dSCy Schubert name, f->filegen));
551c0b746e5SOllivier Robert return f->filegen;
552c0b746e5SOllivier Robert }
553c0b746e5SOllivier Robert f = f->next;
554c0b746e5SOllivier Robert }
555*2b15cb3dSCy Schubert DPRINTF(4, ("filegen_get(%s) = NULL\n", name));
556c0b746e5SOllivier Robert return NULL;
557c0b746e5SOllivier Robert }
558c0b746e5SOllivier Robert
559*2b15cb3dSCy Schubert
560c0b746e5SOllivier Robert void
filegen_register(const char * dir,const char * name,FILEGEN * filegen)561c0b746e5SOllivier Robert filegen_register(
562*2b15cb3dSCy Schubert const char * dir,
563c0b746e5SOllivier Robert const char * name,
564c0b746e5SOllivier Robert FILEGEN * filegen
565c0b746e5SOllivier Robert )
566c0b746e5SOllivier Robert {
567*2b15cb3dSCy Schubert struct filegen_entry **ppfe;
568c0b746e5SOllivier Robert
569*2b15cb3dSCy Schubert DPRINTF(4, ("filegen_register(%s, %p)\n", name, filegen));
570ea906c41SOllivier Robert
571*2b15cb3dSCy Schubert filegen_init(dir, name, filegen);
572ea906c41SOllivier Robert
573*2b15cb3dSCy Schubert ppfe = &filegen_registry;
574*2b15cb3dSCy Schubert while (NULL != *ppfe) {
575*2b15cb3dSCy Schubert if ((*ppfe)->name == name
576*2b15cb3dSCy Schubert || !strcmp((*ppfe)->name, name)) {
577*2b15cb3dSCy Schubert
578*2b15cb3dSCy Schubert DPRINTF(5, ("replacing filegen %p\n",
579*2b15cb3dSCy Schubert (*ppfe)->filegen));
580*2b15cb3dSCy Schubert
581*2b15cb3dSCy Schubert (*ppfe)->filegen = filegen;
582c0b746e5SOllivier Robert return;
583c0b746e5SOllivier Robert }
584*2b15cb3dSCy Schubert ppfe = &((*ppfe)->next);
585c0b746e5SOllivier Robert }
586c0b746e5SOllivier Robert
587*2b15cb3dSCy Schubert *ppfe = emalloc(sizeof **ppfe);
588*2b15cb3dSCy Schubert
589*2b15cb3dSCy Schubert (*ppfe)->next = NULL;
590*2b15cb3dSCy Schubert (*ppfe)->name = estrdup(name);
591*2b15cb3dSCy Schubert (*ppfe)->filegen = filegen;
592*2b15cb3dSCy Schubert
593*2b15cb3dSCy Schubert DPRINTF(6, ("adding new filegen\n"));
594*2b15cb3dSCy Schubert
595*2b15cb3dSCy Schubert return;
596*2b15cb3dSCy Schubert }
597*2b15cb3dSCy Schubert
598*2b15cb3dSCy Schubert
599*2b15cb3dSCy Schubert /*
600*2b15cb3dSCy Schubert * filegen_statsdir() - reset each filegen entry's dir to statsdir.
601*2b15cb3dSCy Schubert */
602*2b15cb3dSCy Schubert void
filegen_statsdir(void)603*2b15cb3dSCy Schubert filegen_statsdir(void)
604*2b15cb3dSCy Schubert {
605*2b15cb3dSCy Schubert struct filegen_entry *f;
606*2b15cb3dSCy Schubert
607*2b15cb3dSCy Schubert for (f = filegen_registry; f != NULL; f = f->next)
608*2b15cb3dSCy Schubert filegen_config(f->filegen, statsdir, f->filegen->fname,
609*2b15cb3dSCy Schubert f->filegen->type, f->filegen->flag);
610*2b15cb3dSCy Schubert }
611*2b15cb3dSCy Schubert
612*2b15cb3dSCy Schubert
613*2b15cb3dSCy Schubert /*
614*2b15cb3dSCy Schubert * filegen_unregister frees memory allocated by filegen_register for
615*2b15cb3dSCy Schubert * name.
616*2b15cb3dSCy Schubert */
617c0b746e5SOllivier Robert #ifdef DEBUG
618*2b15cb3dSCy Schubert void
filegen_unregister(const char * name)619c0b746e5SOllivier Robert filegen_unregister(
620*2b15cb3dSCy Schubert const char *name
621c0b746e5SOllivier Robert )
622c0b746e5SOllivier Robert {
623*2b15cb3dSCy Schubert struct filegen_entry ** ppfe;
624*2b15cb3dSCy Schubert struct filegen_entry * pfe;
625c0b746e5SOllivier Robert FILEGEN * fg;
626c0b746e5SOllivier Robert
627*2b15cb3dSCy Schubert DPRINTF(4, ("filegen_unregister(%s)\n", name));
628*2b15cb3dSCy Schubert
629*2b15cb3dSCy Schubert ppfe = &filegen_registry;
630*2b15cb3dSCy Schubert
631*2b15cb3dSCy Schubert while (NULL != *ppfe) {
632*2b15cb3dSCy Schubert if ((*ppfe)->name == name
633*2b15cb3dSCy Schubert || !strcmp((*ppfe)->name, name)) {
634*2b15cb3dSCy Schubert pfe = *ppfe;
635*2b15cb3dSCy Schubert *ppfe = (*ppfe)->next;
636*2b15cb3dSCy Schubert fg = pfe->filegen;
637*2b15cb3dSCy Schubert free(pfe->name);
638*2b15cb3dSCy Schubert free(pfe);
639*2b15cb3dSCy Schubert filegen_uninit(fg);
640*2b15cb3dSCy Schubert break;
641c0b746e5SOllivier Robert }
642*2b15cb3dSCy Schubert ppfe = &((*ppfe)->next);
643c0b746e5SOllivier Robert }
644c0b746e5SOllivier Robert }
645*2b15cb3dSCy Schubert #endif /* DEBUG */
646