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