Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Feb 2003 15:48:41 -0800
From:      Wesley Peters <wes@softweyr.com>
To:        Thomas Quinot <thomas@freebsd.org>, arch@freebsd.org
Subject:   Re: syslog.conf syntax change (multiple program/host specifications)
Message-ID:  <200302111548.41114.wes@softweyr.com>
In-Reply-To: <200302111430.03156.wes@softweyr.com>
References:  <20030210114930.GB90800@melusine.cuivre.fr.eu.org> <200302111430.03156.wes@softweyr.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
On Tuesday 11 February 2003 14:30, Wesley Peters wrote:
>
> This mod has been running on my 4.7R workstation for a month now, and on
> a (4.4 + security fixes) appliance in our test lab as well.  We've
> noticed no problems.  Attached is a diff against 4.7R.
>

Duh.  Here's the diff:



-- 
         "Where am I, and what am I doing in this handbasket?"

Wes Peters                                                   Softweyr LLC
wes@softweyr.com                                     http://softweyr.com/


[-- Attachment #2 --]
--- syslogd.c.orig	Tue Jan 14 10:31:10 2003
+++ syslogd.c	Tue Feb 11 15:46:42 2003
@@ -144,6 +144,20 @@
 #define ISKERNEL	0x010	/* kernel generated message */
 
 /*
+ * File I/O and permission flags.
+ */
+#define	OPEN_FLAGS	O_WRONLY|O_APPEND
+#define	BACKUP_FLAGS	O_WRONLY|O_APPEND|O_CREAT|O_TRUNC
+#define	REOPEN_FLAGS	O_WRONLY|O_APPEND|O_CREAT|O_EXCL
+
+/*
+ * Action types for file size limiting.  Not all are implemented at this
+ * time.
+ */
+enum f_limit { LIM_NONE = '0', LIM_BZIP = 'B', LIM_GZIP = 'G',
+	       LIM_MAX = 'M', LIM_RM = 'R' };
+
+/*
  * This structure represents the files that will have log
  * copies printed.
  */
@@ -167,7 +181,14 @@
 			struct addrinfo *f_addr;
 
 		} f_forw;		/* forwarding address */
+		struct {
 		char	f_fname[MAXPATHLEN];
+			off_t	f_fsize;
+			uid_t	f_uid;
+			gid_t	f_gid;
+			mode_t	f_mode;
+			enum f_limit f_flimit;
+		} f_logfile;
 		struct {
 			char	f_pname[MAXPATHLEN];
 			pid_t	f_pid;
@@ -253,6 +274,19 @@
 	"FORW",		"USERS",	"WALL",		"PIPE"
 };
 
+/* types of compressors we support for compressing rolled logfiles */
+
+struct zipper {
+	char *binpath;
+	char *extension;
+} zipper[] = {
+	{ "/usr/bin/bzip2", ".bz2" },
+	{ "/usr/bin/gzip",  ".gz" }
+};
+
+#define BZIPPER 0
+#define GZIPPER 1
+
 struct	filed *Files;
 struct	filed consfile;
 
@@ -287,7 +321,7 @@
 volatile sig_atomic_t MarkSet, WantDie;
 
 int	allowaddr __P((char *));
-void	cfline __P((const char *, struct filed *, const char *, const char *));
+void	cfline __P((char *, struct filed *, const char *, const char *));
 const char	*cvthname __P((struct sockaddr *));
 void	deadq_enter __P((pid_t, const char *));
 int	deadq_remove __P((pid_t));
@@ -411,8 +445,9 @@
 		endservent();
 
 	consfile.f_type = F_CONSOLE;
-	(void)strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1,
-	    sizeof(consfile.f_un.f_fname));
+	(void)strlcpy(consfile.f_un.f_logfile.f_fname,
+	    ctty + sizeof _PATH_DEV - 1,
+	    sizeof(consfile.f_un.f_logfile.f_fname));
 	(void)strlcpy(bootfile, getbootfile(), sizeof(bootfile));
 	(void)signal(SIGTERM, dodie);
 	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
@@ -894,7 +929,8 @@
 			    sizeof(f->f_prevhost));
 			if (msglen < MAXSVLINE) {
 				f->f_prevlen = msglen;
-				(void)strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
+				(void)strlcpy(f->f_prevline, msg,
+				    sizeof(f->f_prevline));
 				fprintlog(f, flags, (char *)NULL);
 			} else {
 				f->f_prevline[0] = 0;
@@ -906,6 +942,148 @@
 	(void)sigsetmask(omask);
 }
 
+/*
+ * Reopen the logfile described by f.  Assume the logfile no longer exists;
+ * the caller is supposed to have removed it before calling us.
+ */
+static void
+reopen(struct filed *f)
+{
+	short oldfd = f->f_file;
+
+	f->f_file = open(f->f_un.f_logfile.f_fname, REOPEN_FLAGS,
+			 f->f_un.f_logfile.f_mode);
+	if (f->f_file < 0) {
+		f->f_type = F_UNUSED;
+		logerror(f->f_un.f_logfile.f_fname);
+	}
+	fchown(f->f_file, f->f_un.f_logfile.f_uid, f->f_un.f_logfile.f_gid);
+	dprintf("reopen(\"%s\", %o, %d:%d) fd was %d is %d\n",
+		f->f_un.f_logfile.f_fname,
+		f->f_un.f_logfile.f_mode,
+		f->f_un.f_logfile.f_uid,
+		f->f_un.f_logfile.f_gid,
+		oldfd, f->f_file);
+}
+
+static void
+backup(struct filed *f)
+{
+	char backup[MAXPATHLEN];
+
+	strlcpy(backup, f->f_un.f_logfile.f_fname, sizeof(backup));
+	strlcat(backup, ".old", sizeof(backup));
+	dprintf("backup(\"%s\") -> \"%s\"\n", f->f_un.f_logfile.f_fname,
+	    backup);
+	rename(f->f_un.f_logfile.f_fname, backup);
+}
+
+/*
+ * Compress the logfile f.  Call this routine after closing the file, so the
+ * buffers have been flushed, but before unlinking the file.  This function
+ * re-opens the log file for input in the parent process, before forking, so
+ * once this routine has returned to the caller it is safe to unlink the
+ * file.
+ */
+static void
+compress(struct filed *f, struct zipper compressor)
+{
+	pid_t pid;
+	char backup[MAXPATHLEN];
+	int in, out;
+	
+	strlcpy(backup, f->f_un.f_logfile.f_fname, sizeof(backup));
+	strlcat(backup, compressor.extension, sizeof(backup));
+	
+	dprintf("compress(\"%s\")\n", f->f_un.f_logfile.f_fname, backup);
+	
+	in = open(f->f_un.f_logfile.f_fname, O_RDONLY);
+	if (in < 0) {
+		logerror("reopening log file for input");
+		return;
+	}
+	dprintf("compress: reopened %s for input on %d\n",
+		f->f_un.f_logfile.f_fname, in);
+	out = open(backup, BACKUP_FLAGS, f->f_un.f_logfile.f_mode);
+	if (out < 0) {
+		logerror("opening compressed logfile for output");
+		close(in);
+		return;
+	}
+	fchown(out, f->f_un.f_logfile.f_uid, f->f_un.f_logfile.f_gid);
+	dprintf("compress: opened %s %o %d:%d for output on %d\n",
+		f->f_un.f_logfile.f_fname,
+		f->f_un.f_logfile.f_mode,
+		f->f_un.f_logfile.f_uid,
+		f->f_un.f_logfile.f_gid,
+		in);
+	
+	if ((pid = fork()) < 0) {
+		logerror("bzip2 fork");
+		return;
+	} else if (pid == 0) {
+		dprintf("compress: %sing now...\n", compressor.binpath);
+
+		dup2(in, STDIN_FILENO);
+		dup2(out, STDOUT_FILENO);
+		execl(compressor.binpath, "-f", NULL);
+		err(1, compressor.binpath);
+	} else {
+		/* Only in the parent process here, let bzip2 crank up. */
+		dprintf("compress: Letting %s crank up...\n",
+			compressor.binpath);
+		usleep(10);
+	}
+	dprintf("compress: removing %s\n", f->f_un.f_logfile.f_fname);
+	close(in);
+	close(out);
+	unlink(f->f_un.f_logfile.f_fname);
+}
+
+static void
+roll(struct filed *f)
+{
+	struct stat s;
+
+	if (f->f_un.f_logfile.f_flimit == LIM_NONE)
+		return;
+
+	dprintf("roll(\"%s\")\n", f->f_un.f_logfile.f_fname);
+
+	if (fstat(f->f_file, &s) == -1) {
+		logerror("fstat");
+		return;
+	}
+	dprintf("roll: size %lld max %lld\n", s.st_size,
+	    f->f_un.f_logfile.f_fsize);
+	if (s.st_size < f->f_un.f_logfile.f_fsize)
+		return;
+
+	/* This logfile has grown too big, roll it per our instructions. */
+	f->f_un.f_logfile.f_uid = s.st_uid;
+	f->f_un.f_logfile.f_gid = s.st_gid;
+	f->f_un.f_logfile.f_mode = s.st_mode;
+	close(f->f_file);
+	switch (f->f_un.f_logfile.f_flimit) {
+	case LIM_RM:
+		dprintf("roll: remove %s\n", f->f_un.f_logfile.f_fname);
+		unlink(f->f_un.f_logfile.f_fname);
+		break;
+	case LIM_MAX:
+		backup(f);
+		break;
+	case LIM_BZIP:
+		compress(f, zipper[BZIPPER]);
+		break;
+	case LIM_GZIP:
+		compress(f, zipper[GZIPPER]);
+		break;
+	case LIM_NONE:	/* Can't happen, but keep compiler from whining. */
+		break;
+	}
+	reopen(f);
+}
+
 void
 fprintlog(f, flags, msg)
 	struct filed *f;
@@ -1060,7 +1238,7 @@
 		break;
 
 	case F_FILE:
-		dprintf(" %s\n", f->f_un.f_fname);
+		dprintf(" %s\n", f->f_un.f_logfile.f_fname);
 		v->iov_base = "\n";
 		v->iov_len = 1;
 		if (writev(f->f_file, iov, 7) < 0) {
@@ -1068,9 +1246,11 @@
 			(void)close(f->f_file);
 			f->f_type = F_UNUSED;
 			errno = e;
-			logerror(f->f_un.f_fname);
+			logerror(f->f_un.f_logfile.f_fname);
 		} else if (flags & SYNC_FILE)
 			(void)fsync(f->f_file);
+		if (f->f_un.f_logfile.f_flimit != LIM_NONE)
+			roll(f);
 		break;
 
 	case F_PIPE:
@@ -1105,12 +1285,12 @@
 		/* FALLTHROUGH */
 
 	case F_TTY:
-		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
+		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_logfile.f_fname);
 		v->iov_base = "\r\n";
 		v->iov_len = 2;
 
 		errno = 0;	/* ttymsg() only sometimes returns an errno */
-		if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
+		if ((msgret = ttymsg(iov, 7, f->f_un.f_logfile.f_fname, 10))) {
 			f->f_type = F_UNUSED;
 			logerror(msgret);
 		}
@@ -1492,12 +1672,15 @@
 			printf("%s: ", TypeNames[f->f_type]);
 			switch (f->f_type) {
 			case F_FILE:
-				printf("%s", f->f_un.f_fname);
+				printf("%s", f->f_un.f_logfile.f_fname);
+				if (f->f_un.f_logfile.f_flimit != LIM_NONE)
+					printf(" %c %lld", f->f_un.f_logfile.f_flimit,
+					    f->f_un.f_logfile.f_fsize);
 				break;
 
 			case F_CONSOLE:
 			case F_TTY:
-				printf("%s%s", _PATH_DEV, f->f_un.f_fname);
+				printf("%s%s", _PATH_DEV, f->f_un.f_logfile.f_fname);
 				break;
 
 			case F_FORW:
@@ -1509,7 +1692,9 @@
 				break;
 
 			case F_USERS:
-				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
+				for (i = 0;
+				    i < MAXUNAMES && *f->f_un.f_uname[i];
+				    i++)
 					printf("%s, ", f->f_un.f_uname[i]);
 				break;
 			}
@@ -1538,13 +1723,13 @@
  */
 void
 cfline(line, f, prog, host)
-	const char *line;
+	char *line;
 	struct filed *f;
 	const char *prog;
 	const char *host;
 {
 	struct addrinfo hints, *res;
-	int error, i, pri;
+	int error, i, pri, scale;
 	const char *p, *q;
 	char *bp;
 	char buf[MAXLINE], ebuf[100];
@@ -1701,7 +1886,44 @@
 		break;
 
 	case '/':
-		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
+		/*
+		 * find end of filename, terminate, leave q pointing at file
+		 * options.
+		 */
+		f->f_un.f_logfile.f_flimit = LIM_NONE;
+		if ((q = strpbrk(p, "\t ")) != NULL) {
+			*q++ = '\0';
+			while (*q == '\t' || *q == ' ')
+				q++;
+			/* determine filesize limiting action, if specified */
+			switch (*q) {
+			case LIM_BZIP: case LIM_GZIP:
+			case LIM_MAX:  case LIM_RM:
+				f->f_un.f_logfile.f_flimit = *q++;
+				break;
+			case '0'...'9':
+				/* implied action is LIM_MAX */
+				f->f_un.f_logfile.f_flimit = LIM_MAX;
+				break;
+			}
+			/* file size is being limited, get the size */
+			if (f->f_un.f_logfile.f_flimit != LIM_NONE) {
+				f->f_un.f_logfile.f_fsize = strtol(q, &bp, 0);
+				scale = 0;
+				switch (toupper(*bp)) {
+				case 'E': scale += 10;	/* Exabyte */
+				case 'P': scale += 10;	/* Petabyte */
+				case 'T': scale += 10;	/* get the idea... */
+				case 'G': scale += 10;
+				case 'M': scale += 10;
+				case 'K': scale += 5;
+				case 'B': scale += 5;	/* blocks */
+				}
+				f->f_un.f_logfile.f_fsize <<= scale;
+			}
+		}
+		
+		if ((f->f_file = open(p, OPEN_FLAGS, 0)) < 0) {
 			f->f_type = F_UNUSED;
 			logerror(p);
 			break;
@@ -1711,17 +1933,20 @@
 				f->f_type = F_CONSOLE;
 			else
 				f->f_type = F_TTY;
-			(void)strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1,
-			    sizeof(f->f_un.f_fname));
+			(void)strlcpy(f->f_un.f_logfile.f_fname,
+			    p + sizeof(_PATH_DEV) - 1,
+			    sizeof(f->f_un.f_logfile.f_fname));
 		} else {
-			(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
+			(void)strlcpy(f->f_un.f_logfile.f_fname, p,
+			    sizeof(f->f_un.f_logfile.f_fname));
 			f->f_type = F_FILE;
 		}
 		break;
 
 	case '|':
 		f->f_un.f_pipe.f_pid = 0;
-		(void)strlcpy(f->f_un.f_fname, p + 1, sizeof(f->f_un.f_fname));
+		(void)strlcpy(f->f_un.f_pipe.f_pname, p + 1,
+		    sizeof(f->f_un.f_pipe.f_pname));
 		f->f_type = F_PIPE;
 		break;
 

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200302111548.41114.wes>