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