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>
