From owner-freebsd-arch Tue Feb 11 15:48:57 2003 Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E3A3A37B401; Tue, 11 Feb 2003 15:48:46 -0800 (PST) Received: from smtp-relay.omnis.com (smtp-relay.omnis.com [216.239.128.27]) by mx1.FreeBSD.org (Postfix) with ESMTP id C2A7443FA3; Tue, 11 Feb 2003 15:48:43 -0800 (PST) (envelope-from wes@softweyr.com) Received: from salty.rapid.stbernard.com (corp-2.ipinc.com [199.245.188.2]) by smtp-relay.omnis.com (Postfix) with ESMTP id 2DEEC434BC; Tue, 11 Feb 2003 15:48:41 -0800 (PST) From: Wesley Peters Organization: Softweyr To: Thomas Quinot , arch@freebsd.org Subject: Re: syslog.conf syntax change (multiple program/host specifications) Date: Tue, 11 Feb 2003 15:48:41 -0800 User-Agent: KMail/1.5 References: <20030210114930.GB90800@melusine.cuivre.fr.eu.org> <200302111430.03156.wes@softweyr.com> In-Reply-To: <200302111430.03156.wes@softweyr.com> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_ZvYS+aFCBwL+8hZ" Message-Id: <200302111548.41114.wes@softweyr.com> Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG --Boundary-00=_ZvYS+aFCBwL+8hZ Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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/ --Boundary-00=_ZvYS+aFCBwL+8hZ Content-Type: text/x-diff; charset="iso-8859-1"; name="syslogd.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="syslogd.diff" --- 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; --Boundary-00=_ZvYS+aFCBwL+8hZ-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message