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