diff options
Diffstat (limited to 'usr/src/cmd/logadm')
| -rw-r--r-- | usr/src/cmd/logadm/main.c | 83 | ||||
| -rw-r--r-- | usr/src/cmd/logadm/tester | 25 |
2 files changed, 92 insertions, 16 deletions
diff --git a/usr/src/cmd/logadm/main.c b/usr/src/cmd/logadm/main.c index d1f105f7be..b03782c3c3 100644 --- a/usr/src/cmd/logadm/main.c +++ b/usr/src/cmd/logadm/main.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. * * logadm/main.c -- main routines for logadm * @@ -37,6 +38,7 @@ #include <sys/stat.h> #include <sys/wait.h> #include <sys/filio.h> +#include <sys/sysmacros.h> #include <time.h> #include <utime.h> #include "err.h" @@ -828,7 +830,7 @@ rotateto(struct fn *fnp, struct opts *opts, int n, struct fn *recentlog, fn_free(dirname); /* do the rename */ - if (opts_count(opts, "c") != NULL) { + if (n == 0 && opts_count(opts, "c") != NULL) { docopytruncate(opts, fn_s(fnp), fn_s(newfile)); } else if (n == 0 && opts_count(opts, "M")) { struct fn *rawcmd = fn_new(opts_optarg(opts, "M")); @@ -1100,10 +1102,12 @@ docmd(struct opts *opts, const char *msg, const char *cmd, static void docopytruncate(struct opts *opts, const char *file, const char *file_copy) { - int fi, fo, len; - char buf[4096]; + int fi, fo; + char buf[128 * 1024]; struct stat s; struct utimbuf times; + off_t written = 0, rem, last = 0, thresh = 1024 * 1024; + ssize_t len; /* print info if necessary */ if (opts_count(opts, "vn") != NULL) { @@ -1129,7 +1133,7 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy) } /* create new file for copy destination with correct attributes */ - if ((fo = open(file_copy, O_CREAT|O_APPEND|O_WRONLY, s.st_mode)) < 0) { + if ((fo = open(file_copy, O_CREAT|O_TRUNC|O_WRONLY, s.st_mode)) < 0) { err(EF_SYS, "cannot create file: %s", file_copy); (void) close(fi); return; @@ -1137,6 +1141,77 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy) (void) fchown(fo, s.st_uid, s.st_gid); + /* + * Now we'll loop, reading the log file and writing it to our copy + * until the bytes remaining are beneath our atomicity threshold -- at + * which point we'll lock the file and copy the remainder atomically. + * The body of this loop is non-atomic with respect to writers, the + * rationale being that total atomicity (that is, locking the file for + * the entire duration of the copy) comes at too great a cost for a + * large log file, as the writer (i.e., the daemon whose log is being + * rolled) can be blocked for an unacceptable duration. (For one + * particularly loquacious daemon, this period was observed to be + * several minutes in length -- a time so long that it induced + * additional failures in dependent components.) Note that this means + * that if the log file is not always appended to -- if it is opened + * without O_APPEND or otherwise truncated outside of logadm -- this + * will result in our log snapshot being incorrect. But of course, in + * either of these cases, the use of logadm at all is itself + * suspect... + */ + do { + if (fstat(fi, &s) < 0) { + err(EF_SYS, "cannot stat: %s", file); + (void) close(fi); + (void) close(fo); + (void) remove(file_copy); + return; + } + + if ((rem = s.st_size - written) < thresh) { + if (rem >= 0) + break; + + /* + * If the file became smaller, something fishy is going + * on; we'll truncate our copy, reset our seek offset + * and break into the atomic copy. + */ + (void) ftruncate(fo, 0); + (void) lseek(fo, 0, SEEK_SET); + (void) lseek(fi, 0, SEEK_SET); + break; + } + + if (written != 0 && rem > last) { + /* + * We're falling behind -- this file is getting bigger + * faster than we're able to write it; break out and + * lock the file to block the writer. + */ + break; + } + + last = rem; + + while (rem > 0) { + if ((len = read(fi, buf, MIN(sizeof (buf), rem))) <= 0) + break; + + if (write(fo, buf, len) == len) { + rem -= len; + written += len; + continue; + } + + err(EF_SYS, "cannot write into file %s", file_copy); + (void) close(fi); + (void) close(fo); + (void) remove(file_copy); + return; + } + } while (len >= 0); + /* lock log file so that nobody can write into it before we are done */ if (fchmod(fi, s.st_mode|S_ISGID) < 0) err(EF_SYS, "cannot set mandatory lock bit for: %s", file); diff --git a/usr/src/cmd/logadm/tester b/usr/src/cmd/logadm/tester index 1ff4985e6d..ab7c32cd0b 100644 --- a/usr/src/cmd/logadm/tester +++ b/usr/src/cmd/logadm/tester @@ -21,6 +21,7 @@ # # # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, Joyent, Inc. All rights reserved. # # # tester - run logadm tests @@ -281,7 +282,7 @@ sub set_testconffile { # logadm typically runs early every morning via an entry in # root's crontab (see crontab(1)). # -/var/adm/messages -C 4 -P 'Thu Nov 1 16:56:42 2001' -a 'kill -HUP `cat /var/run/syslog.pid`' +/var/adm/messages -C 4 -P 'Thu Nov 1 16:56:42 2001' -a 'kill -HUP `cat /var/run/*syslog*pid`' /var/cron/log -s 512k -t /var/cron/olog /var/lp/logs/lpsched -C 2 -N -t '$file.$N' # @@ -289,7 +290,7 @@ sub set_testconffile { # /var/adm/pacct -C 0 -a '/usr/lib/acct/accton pacct' -g adm -m 664 -o adm -p never apache -C 24 -a '/usr/apache/bin/apachectl graceful' -p 1m -t '/var/apache/old-logs/$basename.%Y-%m' '/var/apache/logs/*{access,error}_log' -/var/log/syslog -C 8 -P 'Thu Nov 1 09:16:38 2001' -a 'kill -HUP `cat /var/run/syslog.pid`' +/var/log/syslog -C 8 -P 'Thu Nov 1 09:16:38 2001' -a 'kill -HUP `cat /var/run/*syslog*pid`' /var/apache/logs/access_log -P 'Thu Nov 1 08:27:56 2001' /var/apache/logs/error_log -P 'Thu Nov 1 08:27:56 2001' /var/apache/logs/suexec_log -P 'Thu Nov 1 08:27:56 2001' @@ -818,12 +819,12 @@ sub logadmV1 { set_testconffile; set_file('std.out.expect', <<'EOF'); -/var/adm/messages -C 4 -P 'Thu Nov 1 16:56:42 2001' -a 'kill -HUP `cat /var/run/syslog.pid`' +/var/adm/messages -C 4 -P 'Thu Nov 1 16:56:42 2001' -a 'kill -HUP `cat /var/run/*syslog*pid`' /var/cron/log -s 512k -t /var/cron/olog /var/lp/logs/lpsched -C 2 -N -t '$file.$N' /var/adm/pacct -C 0 -a '/usr/lib/acct/accton pacct' -g adm -m 664 -o adm -p never apache -C 24 -a '/usr/apache/bin/apachectl graceful' -p 1m -t '/var/apache/old-logs/$basename.%Y-%m' '/var/apache/logs/*{access,error}_log' -/var/log/syslog -C 8 -P 'Thu Nov 1 09:16:38 2001' -a 'kill -HUP `cat /var/run/syslog.pid`' +/var/log/syslog -C 8 -P 'Thu Nov 1 09:16:38 2001' -a 'kill -HUP `cat /var/run/*syslog*pid`' /var/apache/logs/access_log -P 'Thu Nov 1 08:27:56 2001' /var/apache/logs/error_log -P 'Thu Nov 1 08:27:56 2001' /var/apache/logs/suexec_log -P 'Thu Nov 1 08:27:56 2001' @@ -1179,8 +1180,8 @@ sub logadm7 { # logadm typically runs early every morning via an entry in # root's crontab (see crontab(1)). # -dir1/syslog -C 8 -a 'echo kill -HUP `cat /etc/syslog.pid` >> cmd.out' -dir2/messages -C 4 -a 'echo kill -HUP `cat /etc/syslog.pid` >> cmd.out' +dir1/syslog -C 8 -a 'echo kill -HUP `cat /var/run/*syslog*pid` >> cmd.out' +dir2/messages -C 4 -a 'echo kill -HUP `cat /var/run/*syslog*pid` >> cmd.out' # # The entry below is used by turnacct(1M) # @@ -1189,7 +1190,7 @@ EOF system("/bin/cp logadm.conf logadm.conf.orig"); - $pid=`cat /etc/syslog.pid`; + $pid=`cat /var/run/*syslog*pid`; chomp $pid; set_file('cmd.out.expect', <<"EOF"); kill -HUP $pid @@ -1260,7 +1261,7 @@ $bindir/logadm -f logadm.conf -F logadm.timestamps dir1/syslog dir2/messages >st echo something > dir1/syslog echo something > dir2/messages $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out3 2>std.err3 || exit 1 -exec $bindir/logadm -f logadm.conf -F logadm.timestamps dir2/messages -p now -a 'echo second kill -HUP `cat /etc/syslog.pid` >> cmd.out' >std.out4 2>std.err4 +exec $bindir/logadm -f logadm.conf -F logadm.timestamps dir2/messages -p now -a 'echo second kill -HUP `cat /var/run/*syslog*pid` >> cmd.out' >std.out4 2>std.err4 EOF } @@ -1748,8 +1749,8 @@ sub logadm14 { # logadm typically runs early every morning via an entry in # root's crontab (see crontab(1)). # -dir1/syslog -C 8 -a 'echo kill -HUP `cat /etc/syslog.pid` >> cmd.out' -dir2/messages -C 4 -a 'echo kill -HUP `cat /etc/syslog.pid` >> cmd.out' +dir1/syslog -C 8 -a 'echo kill -HUP `cat /var/run/*syslog*pid` >> cmd.out' +dir2/messages -C 4 -a 'echo kill -HUP `cat /var/run/*syslog*pid` >> cmd.out' # # The entry below is used by turnacct(1M) # @@ -1806,7 +1807,7 @@ EOF chmod 664 dir2/messages # processing logname: /var/adm/pacct # using default template: $file.$n -sh -c echo kill -HUP `cat /etc/syslog.pid` >> cmd.out # -a cmd +sh -c echo kill -HUP `cat /var/run/*syslog*pid` >> cmd.out # -a cmd # logadm.conf and logadm.timestamps unchanged EOF @@ -2082,7 +2083,7 @@ EOF sub logadm20 { set_file('logadm.conf', <<'EOF'); # non-trivial entry -/var/log/syslog -C 8 -a 'kill -HUP `cat /var/run/syslog.pid`' +/var/log/syslog -C 8 -a 'kill -HUP `cat /var/run/*syslog*pid`' EOF set_file('std.err.expect', <<'EOF'); |
