[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: syslogd config patch
From:       Sergey Naumov <sknaumov () gmail ! com>
Date:       2010-12-30 12:53:00
Message-ID: AANLkTimZyJDCsSAr1yPaw8CGVY4FYX5rzT3UQBxhLMo9 () mail ! gmail ! com
[Download RAW message or body]

Hello.

Denys, here is new version of syslog.conf patch.
I had stable version, but then decided to integrate my patch more
deeply to the existent syslog code, for example - to split logFile_t
struct to logRule_t and logFile_t and to slightly change
ROTATE_LOGFILE feature to support rotation of files that are specified
in syslog.conf.
The next step is to integrate REMOTE_LOG feature too.


Format of syslog.conf:
rule1
rule2
.
.
ruleN

Where:
rule = selector[;selector]*  /file/name
selector = facility[,facility]*.[!][=]priority
facility = kern user ... *
priority = emerg ... *

"none" priority is supported
"mark" facility is not suppored

Example:
kern,user.*;kern.!=info;user.!err       /var/log/1.log
*.err;user.none;kern.!=debug          /dev/console

Any recommendations are welcomed.

Happy New Year,

Sergey Naumov.

["busybox-1.18.1-syslog.conf-v4.0.patch" (application/octet-stream)]

diff -uNr busybox-1.18.1-orig/sysklogd/Config.src busybox-1.18.1/sysklogd/Config.src
--- busybox-1.18.1-orig/sysklogd/Config.src	2010-12-20 03:41:27.000000000 +0300
+++ busybox-1.18.1/sysklogd/Config.src	2010-12-29 15:10:36.000000000 +0300
@@ -52,6 +52,13 @@
 	  Option -D instructs syslogd to drop consecutive messages
 	  which are totally the same.
 
+config FEATURE_SYSLOGD_CFG
+	bool "Support syslog.conf"
+	default y
+	depends on SYSLOGD
+	help
+	  Supports restricted syslogd config.
+
 config FEATURE_SYSLOGD_READ_BUFFER_SIZE
 	int "Read buffer size in bytes"
 	default 256
diff -uNr busybox-1.18.1-orig/sysklogd/syslogd.c busybox-1.18.1/sysklogd/syslogd.c
--- busybox-1.18.1-orig/sysklogd/syslogd.c	2010-12-20 03:41:27.000000000 +0300
+++ busybox-1.18.1/sysklogd/syslogd.c	2010-12-30 18:07:33.000000000 +0300
@@ -66,10 +66,26 @@
 } remoteHost_t;
 #endif
 
+typedef struct logFile_t {
+	const char *path;
+	int fd;
+#if ENABLE_FEATURE_ROTATE_LOGFILE
+	long size;
+	uint8_t isReg;
+#endif
+} logFile_t;
+
+#if ENABLE_FEATURE_SYSLOGD_CFG
+typedef struct logRule_t {
+	uint8_t fpmap[LOG_NFACILITIES];
+	struct logFile_t *file;
+	struct logRule_t *next;
+} logRule_t;
+#endif
+
 /* Allows us to have smaller initializer. Ugly. */
 #define GLOBALS \
-	const char *logFilePath;                \
-	int logFD;                              \
+	logFile_t logFile;                      \
 	/* interval between marks in seconds */ \
 	/*int markInterval;*/                   \
 	/* level of messages to be logged */    \
@@ -79,8 +95,6 @@
 	unsigned logFileSize;                   \
 	/* number of rotated message files */   \
 	unsigned logFileRotate;                 \
-	unsigned curFileSize;                   \
-	smallint isRegular;                     \
 ) \
 IF_FEATURE_IPC_SYSLOG( \
 	int shmid; /* ipc shared memory id */   \
@@ -88,6 +102,9 @@
 	int shm_size;                           \
 	struct sembuf SMwup[1];                 \
 	struct sembuf SMwdn[3];                 \
+) \
+IF_FEATURE_SYSLOGD_CFG( \
+	logRule_t *pLogR; \
 )
 
 struct init_globals {
@@ -119,8 +136,11 @@
 };
 
 static const struct init_globals init_data = {
-	.logFilePath = "/var/log/messages",
-	.logFD = -1,
+	.logFile = {
+		.path = "/var/log/messages",
+		.fd = -1,
+//fields for ENABLE_FEATURE_ROTATE_LOGFILE will be initialized later
+	},
 #ifdef SYSLOGD_MARK
 	.markInterval = 20 * 60,
 #endif
@@ -157,6 +177,7 @@
 	IF_FEATURE_REMOTE_LOG(    OPTBIT_locallog   ,)	// -L
 	IF_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)	// -C
 	IF_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)	// -D
+	IF_FEATURE_SYSLOGD_CFG(   OPTBIT_cfg        ,)	// -f
 
 	OPT_mark        = 1 << OPTBIT_mark    ,
 	OPT_nofork      = 1 << OPTBIT_nofork  ,
@@ -169,6 +190,7 @@
 	OPT_locallog    = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_locallog   )) + 0,
 	OPT_circularlog = IF_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
 	OPT_dup         = IF_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
+	OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(   (1 << OPTBIT_cfg        )) + 0,
 };
 #define OPTION_STR "m:nO:l:S" \
 	IF_FEATURE_ROTATE_LOGFILE("s:" ) \
@@ -176,17 +198,186 @@
 	IF_FEATURE_REMOTE_LOG(    "R:" ) \
 	IF_FEATURE_REMOTE_LOG(    "L"  ) \
 	IF_FEATURE_IPC_SYSLOG(    "C::") \
-	IF_FEATURE_SYSLOGD_DUP(   "D"  )
+	IF_FEATURE_SYSLOGD_DUP(   "D"  ) \
+	IF_FEATURE_SYSLOGD_CFG(   "f:"  )
 #define OPTION_DECL *opt_m, *opt_l \
 	IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
 	IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
-	IF_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL)
-#define OPTION_PARAM &opt_m, &G.logFilePath, &opt_l \
+	IF_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL) \
+	IF_FEATURE_SYSLOGD_CFG(,*opt_f = NULL)
+#define OPTION_PARAM &opt_m, &(G.logFile.path), &opt_l \
 	IF_FEATURE_ROTATE_LOGFILE(,&opt_s) \
 	IF_FEATURE_ROTATE_LOGFILE(,&opt_b) \
 	IF_FEATURE_REMOTE_LOG(	  ,&remoteAddrList) \
-	IF_FEATURE_IPC_SYSLOG(    ,&opt_C)
+	IF_FEATURE_IPC_SYSLOG(    ,&opt_C) \
+	IF_FEATURE_SYSLOGD_CFG(,&opt_f)
+
 
+/*
+ * find name by value (then name == NULL) or value by name (then val == -1)
+ * in the set of CODEs and return pointer to appropriate CODE struct.
+ * Ex:
+ * find_fac_prio(LOG_KERN, NULL, facilitynames);
+ * find_fac_prio(LOG_ERR, NULL, prioritynames);
+ * find_fac_prio(-1, "kern", facilitynames);
+ */
+static const CODE* find_fac_prio(int val, char *name, const CODE* c_set)
+{
+	if (!c_set) return NULL;
+	for (; c_set->c_name; c_set++) {
+		if ( (name && strcmp(name, c_set->c_name) == 0)
+			 || (c_set->c_val == val) ) {
+			return c_set;
+		}
+	}
+	return NULL;
+}
+
+#if ENABLE_FEATURE_SYSLOGD_CFG
+#define cfgbuf bb_common_bufsiz1
+static void syslogdcfg_parse(const char * file)
+{
+	char *t;
+	char *sel; //pointer to the current selector
+	char *nsel; //pointer to the next selector
+	uint8_t fl_neg; //indicates that selector has negation (kern.!err)
+	uint8_t fl_eq; //indicates that selector has equality (kern.=err)
+	uint32_t facmap; //bitmap of enabled facilities
+	uint8_t primap; //bitmap of enabled priorities
+	uint8_t pri; //priority code
+	uint8_t i; //counter for iteration through facilities/priorities
+	// use double pointer to avoid checking whether head was initialized
+	logRule_t **ppLogR = &(G.pLogR);
+	logRule_t *pLogR;
+	const CODE *code;
+
+	// the first token is selectors set
+	// the second one is file name
+	// the third one have to be NULL
+	char *tok[3];
+	parser_t *parser;
+
+	parser = config_open2(file ? file : "/etc/syslog.conf",
+						file ? xfopen_for_read : fopen_or_warn_stdin);
+	if (!parser)
+		return; //didn't find default /etc/syslog.conf => proceed as if we
+				//built busybox without config support.
+
+	//iterate through lines of config, skipping comments
+	while (config_read(parser, tok, 3, 2,
+			"# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
+		if (tok[2]) { //unexpected trailing token
+			t = tok[2];
+			goto cfgerr;
+		}
+		*ppLogR = xmalloc(sizeof(logRule_t));
+		pLogR = *ppLogR;
+		memset(pLogR, 0, sizeof(logRule_t));
+	//- first step for each selector in line is to determine
+	//if rule has negation
+	//- second one is to get priority mask.
+	//- third one is to apply this mask to each of listed facility
+	//or to all of them if *
+		sel = tok[0];
+		do { //iterate through selectors
+			nsel = strchr(sel, ';');
+			if (nsel != NULL)
+				*nsel++ = '\0';
+			//process selector
+			fl_neg = 0;
+			fl_eq = 0;
+			facmap = 0;
+			primap = 0;
+			pri = 0;
+			t = strchr(sel, '.');
+			if (t == NULL) {
+				t = sel;
+				goto cfgerr;
+			}
+			*t++ = '\0'; // separate facility from priority
+			if (*t == '!') {
+				fl_neg = 1;
+				++t;
+			}
+			if (*t == '=') {
+				fl_eq = 1;
+				++t;
+			}
+			// priority
+			if (*t == '*')
+				primap = 255; //all 8 log levels enabled
+			else {
+				code = find_fac_prio(-1, t, prioritynames);
+				if (code == NULL) goto cfgerr;
+				pri = code->c_val;
+				if (pri == INTERNAL_NOPRI) {
+					primap = 0;
+					fl_neg = 1; //so fpmap[fac] &= 0
+				} else {
+					primap = (1<<pri);
+					if (!fl_eq) {
+						for (i = 0; i < pri; ++i) primap |= (1<<i);
+					}
+					if (fl_neg)
+						primap = ~primap;
+				}
+			}
+			//facility
+			if (*sel == '*')
+				facmap = (1<<LOG_NFACILITIES) - 1;
+			else {
+				char * nfac;
+				t = sel;
+				do { //iterate through facilities
+					nfac = strchr(t, ',');
+					if (nfac != NULL)
+						*nfac++ = '\0';
+					code = find_fac_prio(-1, t, facilitynames);
+					if (code == NULL)
+						goto cfgerr;
+					if (code->c_val != INTERNAL_MARK) { //discard mark
+						facmap |= 1<<(LOG_FAC(code->c_val));
+					}
+					t = nfac;
+				} while (t != NULL);
+			}
+			//merge result with previous selectors
+			for (i = 0; i < LOG_NFACILITIES; ++i) {
+				if ((facmap & (1<<i)) == 0) 
+					continue;
+				if (fl_neg)
+					pLogR->fpmap[i] &= primap;
+				else
+					pLogR->fpmap[i] |= primap;
+			}
+			//process next selector
+			sel = nsel;
+		} while (sel != NULL);
+		//temporarily use pLogR as iterator, but *ppLogR still points to
+		//currently processing rule entry.
+		//check whether current file name was mentioned in previous rules.
+		//NOTE: *ppLogR points to the current (and last in the list) rule.
+		for (pLogR = G.pLogR; pLogR != *ppLogR; pLogR = pLogR->next) {
+			if (strcmp(pLogR->file->path, tok[1]) == 0) {
+				(*ppLogR)->file = pLogR->file;
+				break;
+			}
+		}
+		if (pLogR == *ppLogR) { //new file
+			pLogR->file = xmalloc(sizeof(logFile_t));
+			pLogR->file->fd = -1;
+			pLogR->file->path = xstrdup(tok[1]);
+			//fields for ENABLE_FEATURE_ROTATE_LOGFILE will be initialized later
+		}
+		ppLogR = &((*ppLogR)->next);
+	}
+	config_close(parser);
+	return;
+cfgerr:
+	bb_error_msg_and_die("bad line %d: wrong token \"%s\".",
+	                     parser->lineno, t);
+}
+#endif
 
 /* circular buffer variables/structures */
 #if ENABLE_FEATURE_IPC_SYSLOG
@@ -288,9 +479,8 @@
 void log_to_shmem(const char *msg);
 #endif /* FEATURE_IPC_SYSLOG */
 
-
 /* Print a message to the log file. */
-static void log_locally(time_t now, char *msg)
+static void log_locally(time_t now, char *msg, logFile_t *logF)
 {
 #ifdef SYSLOGD_WRLOCK
 	struct flock fl;
@@ -303,7 +493,7 @@
 		return;
 	}
 #endif
-	if (G.logFD >= 0) {
+	if (logF->fd >= 0) {
 		/* Reopen log file every second. This allows admin
 		 * to delete the file and not worry about restarting us.
 		 * This costs almost nothing since it happens
@@ -313,15 +503,15 @@
 			now = time(NULL);
 		if (G.last_log_time != now) {
 			G.last_log_time = now;
-			close(G.logFD);
+			close(logF->fd);
 			goto reopen;
 		}
 	} else {
  reopen:
-		G.logFD = open(G.logFilePath, O_WRONLY | O_CREAT
+		logF->fd = open(logF->path, O_WRONLY | O_CREAT
 					| O_NOCTTY | O_APPEND | O_NONBLOCK,
 					0666);
-		if (G.logFD < 0) {
+		if (logF->fd < 0) {
 			/* cannot open logfile? - print to /dev/console then */
 			int fd = device_open(DEV_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
 			if (fd < 0)
@@ -334,9 +524,10 @@
 #if ENABLE_FEATURE_ROTATE_LOGFILE
 		{
 			struct stat statf;
-			G.isRegular = (fstat(G.logFD, &statf) == 0 && S_ISREG(statf.st_mode));
+			logF->isReg =
+			  (fstat(logF->fd, &statf) == 0 && S_ISREG(statf.st_mode));
 			/* bug (mostly harmless): can wrap around if file > 4gb */
-			G.curFileSize = statf.st_size;
+			logF->size = statf.st_size;
 		}
 #endif
 	}
@@ -346,41 +537,41 @@
 	fl.l_start = 0;
 	fl.l_len = 1;
 	fl.l_type = F_WRLCK;
-	fcntl(G.logFD, F_SETLKW, &fl);
+	fcntl(logF->fd, F_SETLKW, &fl);
 #endif
 
 #if ENABLE_FEATURE_ROTATE_LOGFILE
-	if (G.logFileSize && G.isRegular && G.curFileSize > G.logFileSize) {
+	if (G.logFileSize && logF->isReg && logF->size > G.logFileSize) {
 		if (G.logFileRotate) { /* always 0..99 */
-			int i = strlen(G.logFilePath) + 3 + 1;
+			int i = strlen(logF->path) + 3 + 1;
 			char oldFile[i];
 			char newFile[i];
 			i = G.logFileRotate - 1;
 			/* rename: f.8 -> f.9; f.7 -> f.8; ... */
 			while (1) {
-				sprintf(newFile, "%s.%d", G.logFilePath, i);
+				sprintf(newFile, "%s.%d", logF->path, i);
 				if (i == 0) break;
-				sprintf(oldFile, "%s.%d", G.logFilePath, --i);
+				sprintf(oldFile, "%s.%d", logF->path, --i);
 				/* ignore errors - file might be missing */
 				rename(oldFile, newFile);
 			}
 			/* newFile == "f.0" now */
-			rename(G.logFilePath, newFile);
+			rename(logF->path, newFile);
 #ifdef SYSLOGD_WRLOCK
 			fl.l_type = F_UNLCK;
-			fcntl(G.logFD, F_SETLKW, &fl);
+			fcntl(logF->fd, F_SETLKW, &fl);
 #endif
-			close(G.logFD);
+			close(logF->fd);
 			goto reopen;
 		}
-		ftruncate(G.logFD, 0);
+		ftruncate(logF->fd, 0);
 	}
-	G.curFileSize +=
+	logF->size +=
 #endif
-			full_write(G.logFD, msg, len);
+			full_write(logF->fd, msg, len);
 #ifdef SYSLOGD_WRLOCK
 	fl.l_type = F_UNLCK;
-	fcntl(G.logFD, F_SETLKW, &fl);
+	fcntl(logF->fd, F_SETLKW, &fl);
 #endif
 }
 
@@ -389,27 +580,13 @@
 	const CODE *c_pri, *c_fac;
 
 	if (pri != 0) {
-		c_fac = facilitynames;
-		while (c_fac->c_name) {
-			if (c_fac->c_val != (LOG_FAC(pri) << 3)) {
-				c_fac++;
-				continue;
-			}
-			/* facility is found, look for prio */
-			c_pri = prioritynames;
-			while (c_pri->c_name) {
-				if (c_pri->c_val != LOG_PRI(pri)) {
-					c_pri++;
-					continue;
-				}
-				snprintf(res20, 20, "%s.%s",
-						c_fac->c_name, c_pri->c_name);
-				return;
-			}
-			/* prio not found, bail out */
-			break;
+		c_fac = find_fac_prio(LOG_FAC(pri) << 3, NULL, facilitynames);
+		c_pri = find_fac_prio(LOG_PRI(pri), NULL, prioritynames);
+		if (c_fac && c_pri) {
+			snprintf(res20, 20, "%s.%s", c_fac->c_name, c_pri->c_name);
+		} else {
+			snprintf(res20, 20, "<%d>", pri);
 		}
-		snprintf(res20, 20, "<%d>", pri);
 	}
 }
 
@@ -444,7 +621,26 @@
 	}
 
 	/* Log message locally (to file or shared mem) */
-	log_locally(now, G.printbuf);
+#if ENABLE_FEATURE_SYSLOGD_CFG
+	{
+		uint8_t match = 0;
+		logRule_t *pLogR;
+		uint8_t mfac = LOG_FAC(pri);
+		uint8_t mpri = LOG_PRI(pri);
+		
+		for (pLogR = G.pLogR; pLogR != NULL; pLogR = pLogR->next)
+		{
+			if ((pLogR->fpmap[mfac] & (1<<mpri))) {
+				log_locally(now, G.printbuf, pLogR->file);
+				match = 1;
+			}
+		}
+		if (match) return;
+	}
+#endif
+	if (LOG_PRI(pri) < G.logLevel) { //moved from split_escape_and_log
+		log_locally(now, G.printbuf, &(G.logFile));
+	}
 }
 
 static void timestamp_and_log_internal(const char *msg)
@@ -489,8 +685,8 @@
 		*q = '\0';
 
 		/* Now log it */
-		if (LOG_PRI(pri) < G.logLevel)
-			timestamp_and_log(pri, G.parsebuf, q - G.parsebuf);
+//		if (LOG_PRI(pri) < G.logLevel) //moved inside timestamp_and_log()
+		timestamp_and_log(pri, G.parsebuf, q - G.parsebuf);
 	}
 }
 
@@ -715,6 +911,10 @@
 		G.shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024;
 #endif
 
+#if ENABLE_FEATURE_SYSLOGD_CFG
+	syslogdcfg_parse(opt_f);
+#endif
+
 	/* If they have not specified remote logging, then log locally */
 	if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R
 		option_mask32 |= OPT_locallog;


_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic