⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntp_filegen.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
字号:
/* * ntp_filegen.c,v 3.12 1994/01/25 19:06:11 kardel Exp * *  implements file generations support for NTP *  logfiles and statistic files * * * Copyright (C) 1992, 1996 by Rainer Pruy * Friedrich-Alexander Universit鋞 Erlangen-N黵nberg, Germany * * This code may be modified and used freely * provided credits remain intact. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include "ntpd.h"#include "ntp_io.h"#include "ntp_string.h"#include "ntp_calendar.h"#include "ntp_filegen.h"#include "ntp_stdlib.h"/* * NTP is intended to run long periods of time without restart. * Thus log and statistic files generated by NTP will grow large. * * this set of routines provides a central interface  * to generating files using file generations * * the generation of a file is changed according to file generation type *//* * redefine this if your system dislikes filename suffixes like * X.19910101 or X.1992W50 or .... */#define SUFFIX_SEP '.'/* * other constants */#define FGEN_AGE_SECS   (24*60*60) /* life time of FILEGEN_AGE in seconds */static	void	filegen_open	P((FILEGEN *, u_long));static	int	valid_fileref	P((char *, char *));#ifdef	UNUSEDstatic	FILEGEN *filegen_unregister P((char *));#endif	/* UNUSED */static void	filegen_init	P((char *, const char *, FILEGEN *));/* * filegen_init */static voidfilegen_init(char *prefix, const char *basename, FILEGEN *fp){	fp->fp       = NULL;	fp->prefix   = prefix;		/* Yes, this is TOTALLY lame! */	fp->basename = (char*)emalloc(strlen(basename) + 1);	strcpy(fp->basename, basename);	fp->id       = 0;	fp->type     = FILEGEN_DAY;	fp->flag     = FGEN_FLAG_LINK; /* not yet enabled !!*/}/* * open a file generation according to the current settings of gen * will also provide a link to basename if requested to do so */static voidfilegen_open(	FILEGEN *gen,	u_long  newid	){	char *filename;	char *basename;	u_int len;	FILE *fp;	struct calendar cal;	len = strlen(gen->prefix) + strlen(gen->basename) + 1;	basename = (char*)emalloc(len);	sprintf(basename, "%s%s", gen->prefix, gen->basename);  	switch(gen->type) {	    default:		msyslog(LOG_ERR, "unsupported file generations type %d for \"%s\" - reverting to FILEGEN_NONE",			gen->type, basename);		gen->type = FILEGEN_NONE;      		/*FALLTHROUGH*/	    case FILEGEN_NONE:		filename = (char*)emalloc(len);		sprintf(filename,"%s", basename);		break;	    case FILEGEN_PID:		filename = (char*)emalloc(len + 1 + 1 + 10);		sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid);		break;      	    case FILEGEN_DAY:		/* You can argue here in favor of using MJD, but		 * I would assume it to be easier for humans to interpret dates		 * in a format they are used to in everyday life.		 */		caljulian(newid,&cal);		filename = (char*)emalloc(len + 1 + 4 + 2 + 2);		sprintf(filename, "%s%c%04d%02d%02d",			basename, SUFFIX_SEP, cal.year, cal.month, cal.monthday);		break;      	    case FILEGEN_WEEK:		/*		 * This is still a hack		 * - the term week is not correlated to week as it is used		 *   normally - it just refers to a period of 7 days		 *   starting at Jan 1 - 'weeks' are counted starting from zero		 */		caljulian(newid,&cal);		filename = (char*)emalloc(len + 1 + 4 + 1 + 2);		sprintf(filename, "%s%c%04dw%02d",			basename, SUFFIX_SEP, cal.year, cal.yearday / 7);		break;	    case FILEGEN_MONTH:		caljulian(newid,&cal);		filename = (char*)emalloc(len + 1 + 4 + 2);		sprintf(filename, "%s%c%04d%02d",			basename, SUFFIX_SEP, cal.year, cal.month);		break;	    case FILEGEN_YEAR:		caljulian(newid,&cal);		filename = (char*)emalloc(len + 1 + 4);		sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year);		break;	    case FILEGEN_AGE:		filename = (char*)emalloc(len + 1 + 2 + 10);		sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid);		break;	}  	if (gen->type != FILEGEN_NONE) {		/*		 * check for existence of a file with name 'basename'		 * as we disallow such a file		 * if FGEN_FLAG_LINK is set create a link		 */		struct stat stats;		/*		 * try to resolve name collisions		 */		static u_long conflicts = 0;#ifndef	S_ISREG#define	S_ISREG(mode)	(((mode) & S_IFREG) == S_IFREG)#endif		if (stat(basename, &stats) == 0) {			/* Hm, file exists... */			if (S_ISREG(stats.st_mode)) {				if (stats.st_nlink <= 1)	{					/*					 * Oh, it is not linked - try to save it					 */					char *savename = (char*)emalloc(len + 1 + 1 + 10 + 10);					sprintf(savename, "%s%c%dC%lu",						basename,						SUFFIX_SEP,						(int) getpid(),						(u_long)conflicts++);					if (rename(basename, savename) != 0)					    msyslog(LOG_ERR," couldn't save %s: %m", basename);					free(savename);				} else {					/*					 * there is at least a second link to					 * this file.					 * just remove the conflicting one					 */					if (#if !defined(VMS)						unlink(basename) != 0#else						delete(basename) != 0#endif						)					    msyslog(LOG_ERR, "couldn't unlink %s: %m", basename);				}			} else {				/*				 * Ehh? Not a regular file ?? strange !!!!				 */				msyslog(LOG_ERR, "expected regular file for %s (found mode 0%lo)",					basename, (unsigned long)stats.st_mode);			}		} else {			/*			 * stat(..) failed, but it is absolutely correct for			 * 'basename' not to exist			 */			if (errno != ENOENT)			    msyslog(LOG_ERR,"stat(%s) failed: %m", basename);		}	}	/*	 * now, try to open new file generation...	 */	fp = fopen(filename, "a");  #ifdef DEBUG	if (debug > 3)	    printf("opening filegen (type=%d/id=%lu) \"%s\"\n",		   gen->type, (u_long)newid, filename);#endif	if (fp == NULL)	{		/* open failed -- keep previous state		 *		 * If the file was open before keep the previous generation.		 * This will cause output to end up in the 'wrong' file,		 * but I think this is still better than losing output		 *		 * ignore errors due to missing directories		 */		if (errno != ENOENT)		    msyslog(LOG_ERR, "can't open %s: %m", filename);	} else {		if (gen->fp != NULL) {			fclose(gen->fp);		}		gen->fp = fp;		gen->id = newid;		if (gen->flag & FGEN_FLAG_LINK) {			/*			 * need to link file to basename			 * have to use hardlink for now as I want to allow			 * gen->basename spanning directory levels			 * this would make it more complex to get the correct			 * filename for symlink			 *			 * Ok, it would just mean taking the part following			 * the last '/' in the name.... Should add it later....			 */			/* Windows NT does not support file links -Greg Schueman 1/18/97 */#if defined SYS_WINNT || defined SYS_VXWORKS			SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */#elif defined(VMS)			errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */#else  /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */			if (link(filename, basename) != 0)			    if (errno != EEXIST)				msyslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename);#endif /* SYS_WINNT || VXWORKS */		}		/* flags & FGEN_FLAG_LINK */	}			/* else fp == NULL */		free(basename);	free(filename);	return;}/* * this function sets up gen->fp to point to the correct * generation of the file for the time specified by 'now' * * 'now' usually is interpreted as second part of a l_fp as is in the cal... * library routines */voidfilegen_setup(	FILEGEN *gen,	u_long   now	){	u_long new_gen = ~ (u_long) 0;	struct calendar cal;	if (!(gen->flag & FGEN_FLAG_ENABLED)) {		if (gen->fp != NULL)		    fclose(gen->fp);		return;	}		switch (gen->type) {	    case FILEGEN_NONE:		if (gen->fp != NULL) return; /* file already open */		break;      	    case FILEGEN_PID:		new_gen = getpid();		break;	    case FILEGEN_DAY:		caljulian(now, &cal);		cal.hour = cal.minute = cal.second = 0;		new_gen = caltontp(&cal);		break;      	    case FILEGEN_WEEK:		/* Would be nice to have a calweekstart() routine */		/* so just use a hack ... */		/* just round time to integral 7 day period for actual year  */		new_gen = now - (now - calyearstart(now)) % TIMES7(SECSPERDAY)			+ 60;		/*		 * just to be sure -		 * the computation above would fail in the presence of leap seconds		 * so at least carry the date to the next day (+60 (seconds))		 * and go back to the start of the day via calendar computations		 */		caljulian(new_gen, &cal);		cal.hour = cal.minute = cal.second = 0;		new_gen = caltontp(&cal);		break;      	    case FILEGEN_MONTH:		caljulian(now, &cal);		cal.yearday = (u_short) (cal.yearday - cal.monthday + 1);		cal.monthday = 1;		cal.hour = cal.minute = cal.second = 0;		new_gen = caltontp(&cal);		break;      	    case FILEGEN_YEAR:		new_gen = calyearstart(now);		break;	    case FILEGEN_AGE:		new_gen = current_time  - (current_time % FGEN_AGE_SECS);		break;	}	/*	 * try to open file if not yet open	 * reopen new file generation file on change of generation id	 */	if (gen->fp == NULL || gen->id != new_gen) {#if DEBUG	if (debug)		printf("filegen  %0x %lu %lu %lu\n", gen->type, now,		    gen->id, new_gen); #endif		filegen_open(gen, new_gen);	}}/* * change settings for filegen files */voidfilegen_config(	FILEGEN *gen,	char    *basename,	u_int   type,	u_int   flag	){	/*	 * if nothing would be changed...	 */	if ((basename == gen->basename || strcmp(basename,gen->basename) == 0) &&	    type == gen->type &&	    flag == gen->flag)	    return;  	/*	 * validate parameters	 */	if (!valid_fileref(gen->prefix,basename))	    return;  	if (gen->fp != NULL)	    fclose(gen->fp);#ifdef DEBUG	if (debug > 2)	    printf("configuring filegen:\n\tprefix:\t%s\n\tbasename:\t%s -> %s\n\ttype:\t%d -> %d\n\tflag: %x -> %x\n",		   gen->prefix, gen->basename, basename, gen->type, type, gen->flag, flag);#endif	if (gen->basename != basename || strcmp(gen->basename, basename) != 0) {		free(gen->basename);		gen->basename = (char*)emalloc(strlen(basename) + 1);		strcpy(gen->basename, basename);	}	gen->type = (u_char) type;	gen->flag = (u_char) flag;	/*	 * make filegen use the new settings	 * special action is only required when a generation file	 * is currently open	 * otherwise the new settings will be used anyway at the next open	 */	if (gen->fp != NULL) {		l_fp now;		get_systime(&now);		filegen_setup(gen, now.l_ui);	}}/* * check whether concatenating prefix and basename * yields a legal filename */static intvalid_fileref(	char *prefix,	char *basename	){	/*	 * prefix cannot be changed dynamically	 * (within the context of filegen)	 * so just reject basenames containing '..'	 *	 * ASSUMPTION:	 * 		file system parts 'below' prefix may be	 *		specified without infringement of security	 *	 *              restricing prefix to legal values	 *		has to be ensured by other means	 * (however, it would be possible to perform some checks here...)	 */	register char *p = basename;  	/*	 * Just to catch, dumb errors opening up the world...	 */	if (prefix == NULL || *prefix == '\0')	    return 0;	if (basename == NULL)	    return 0;  	for (p = basename; p; p = strchr(p, '/')) {		if (*p == '.' && *(p+1) == '.' && (*(p+2) == '\0' || *(p+2) == '/'))		    return 0;	}  	return 1;}/* * filegen registry */static struct filegen_entry {	char *name;	FILEGEN *filegen;	struct filegen_entry *next;} *filegen_registry = NULL;FILEGEN *filegen_get(	char *name	){	struct filegen_entry *f = filegen_registry;	while(f) {		if (f->name == name || strcmp(name, f->name) == 0) {#ifdef XXX	/* this gives the Alpha compiler fits */			if (debug > 3)			    printf("filegen_get(\"%s\") = %x\n", name,				   (u_int)f->filegen);#endif			return f->filegen;		}		f = f->next;	}#ifdef DEBUG	if (debug > 3)	    printf("filegen_get(\"%s\") = NULL\n", name);#endif	return NULL;}voidfilegen_register(	char *prefix,	const char *name,	FILEGEN *filegen	){	struct filegen_entry **f = &filegen_registry;#ifdef XXX		/* this gives the Alpha compiler fits */	if (debug > 3)	    printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen);#endif	filegen_init(prefix, name, filegen);	while (*f) {		if ((*f)->name == name || strcmp(name, (*f)->name) == 0) {#ifdef XXX	 /* this gives the Alpha compiler fits */			if (debug > 4) {				printf("replacing filegen %x\n", (u_int)(*f)->filegen);			}#endif			(*f)->filegen = filegen;			return;		}		f = &((*f)->next);	}	*f = (struct filegen_entry *) emalloc(sizeof(struct filegen_entry));	if (*f) {		(*f)->next = NULL;		(*f)->name = (char*)emalloc(strlen(name) + 1);		strcpy((*f)->name, name);		(*f)->filegen = filegen;#ifdef DEBUG		if (debug > 5) {			printf("adding new filegen\n");		}#endif	}		return;}#ifdef	UNUSEDstatic FILEGEN *filegen_unregister(	char *name	){	struct filegen_entry **f = &filegen_registry;  #ifdef DEBUG	if (debug > 3)	    printf("filegen_unregister(\"%s\")\n", name);#endif	while (*f) {		if (strcmp((*f)->name,name) == 0) {			struct filegen_entry *ff = *f;			FILEGEN *fg;						*f = (*f)->next;			fg = ff->filegen;			free(ff->name);			free(ff);			return fg;		}		f = &((*f)->next);	}	return NULL;}	#endif	/* UNUSED */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -