Mercurial > illumos > illumos-gate
changeset 12998:04c3fb904c79
4685009 logadm(1M) should avoid silent updates of /etc/logadm.conf
author | John.Zolnowsky@Sun.COM |
---|---|
date | Mon, 02 Aug 2010 10:54:24 -0700 |
parents | 82a41a56372e |
children | 9e5c3f16523e |
files | usr/src/Targetdirs usr/src/cmd/logadm/Makefile usr/src/cmd/logadm/conf.c usr/src/cmd/logadm/conf.h usr/src/cmd/logadm/err.c usr/src/cmd/logadm/err.h usr/src/cmd/logadm/main.c usr/src/cmd/logadm/opts.c usr/src/cmd/logadm/opts.h usr/src/cmd/logadm/tester usr/src/pkg/manifests/SUNWcs.mf |
diffstat | 11 files changed, 628 insertions(+), 334 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/Targetdirs Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/Targetdirs Mon Aug 02 10:54:24 2010 -0700 @@ -362,6 +362,7 @@ /var/ld \ /var/log \ /var/log/pool \ + /var/logadm \ /var/mail \ /var/news \ /var/opt \
--- a/usr/src/cmd/logadm/Makefile Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/Makefile Mon Aug 02 10:54:24 2010 -0700 @@ -56,7 +56,7 @@ all: $(PROG) test: $(TESTS) $(PROG) - ./tester `pwd` + $(PERL) -w ./tester `pwd` $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
--- a/usr/src/cmd/logadm/conf.c Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/conf.c Mon Aug 02 10:54:24 2010 -0700 @@ -20,12 +20,9 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * logadm/conf.c -- configuration file module */ @@ -40,6 +37,7 @@ #include <strings.h> #include <unistd.h> #include <stdlib.h> +#include <limits.h> #include "err.h" #include "lut.h" #include "fn.h" @@ -47,17 +45,27 @@ #include "conf.h" /* forward declarations of functions private to this module */ -static void fillconflist(int lineno, const char *entry, char **args, +static void fillconflist(int lineno, const char *entry, struct opts *opts, const char *com, int flags); static void fillargs(char *arg); static char *nexttok(char **ptrptr); -static void conf_print(FILE *stream); +static void conf_print(FILE *cstream, FILE *tstream); static const char *Confname; /* name of the confile file */ +static int Conffd = -1; /* file descriptor for config file */ static char *Confbuf; /* copy of the config file (a la mmap()) */ -static int Conflen; /* length of mmap'd area */ -static int Conffd = -1; /* file descriptor for config file */ -static boolean_t Confchanged; /* true if we need to write changes back */ +static int Conflen; /* length of mmap'd config file area */ +static const char *Timesname; /* name of the timestamps file */ +static int Timesfd = -1; /* file descriptor for timestamps file */ +static char *Timesbuf; /* copy of the timestamps file (a la mmap()) */ +static int Timeslen; /* length of mmap'd timestamps area */ +static int Singlefile; /* Conf and Times in the same file */ +static int Changed; /* what changes need to be written back */ +static int Canchange; /* what changes can be written back */ +static int Changing; /* what changes have been requested */ +#define CHG_NONE 0 +#define CHG_TIMES 1 +#define CHG_BOTH 3 /* * our structured representation of the configuration file @@ -67,7 +75,6 @@ struct confinfo *cf_next; int cf_lineno; /* line number in file */ const char *cf_entry; /* name of entry, if line has an entry */ - char **cf_args; /* raw rhs of entry */ struct opts *cf_opts; /* parsed rhs of entry */ const char *cf_com; /* any comment text found */ int cf_flags; @@ -82,7 +89,7 @@ /* allocate & fill in another entry in our list */ static void -fillconflist(int lineno, const char *entry, char **args, +fillconflist(int lineno, const char *entry, struct opts *opts, const char *com, int flags) { struct confinfo *cp = MALLOC(sizeof (*cp)); @@ -90,7 +97,6 @@ cp->cf_next = NULL; cp->cf_lineno = lineno; cp->cf_entry = entry; - cp->cf_args = args; cp->cf_opts = opts; cp->cf_com = com; cp->cf_flags = flags; @@ -163,54 +169,33 @@ } /* - * conf_open -- open the configuration file, lock it if we have write perms + * scan the memory image of a file + * returns: 0: error, 1: ok, 3: -P option found */ -void -conf_open(const char *fname, int needwrite) +static int +conf_scan(const char *fname, char *buf, int buflen, int timescan, + struct opts *cliopts) { - struct stat stbuf; + int ret = 1; int lineno = 0; char *line; char *eline; char *ebuf; - char *comment; + char *entry, *comment; - Confname = fname; - Confentries = fn_list_new(NULL); - - /* special case this so we don't even try locking the file */ - if (strcmp(Confname, "/dev/null") == 0) - return; + ebuf = &buf[buflen]; - if ((Conffd = open(Confname, (needwrite) ? O_RDWR : O_RDONLY)) < 0) - err(EF_SYS, "%s", Confname); - - if (fstat(Conffd, &stbuf) < 0) - err(EF_SYS, "fstat on %s", Confname); - - if (needwrite && lockf(Conffd, F_LOCK, 0) < 0) - err(EF_SYS, "lockf on %s", Confname); + if (buf[buflen - 1] != '\n') + err(EF_WARN|EF_FILE, "file %s doesn't end with newline, " + "last line ignored.", fname); - if (stbuf.st_size == 0) - return; /* empty file, don't bother parsing it */ - - if ((Confbuf = (char *)mmap(0, stbuf.st_size, - PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1) - err(EF_SYS, "mmap on %s", Confname); - - Conflen = stbuf.st_size; - Confchanged = B_FALSE; + for (line = buf; line < ebuf; line = eline) { + char *ap; + struct opts *opts = NULL; + struct confinfo *cp; - ebuf = &Confbuf[Conflen]; - - if (Confbuf[Conflen - 1] != '\n') - err(EF_WARN|EF_FILE, "config file doesn't end with " - "newline, last line ignored."); - - line = Confbuf; - while (line < ebuf) { lineno++; - err_fileline(Confname, lineno); + err_fileline(fname, lineno); eline = line; comment = NULL; for (; eline < ebuf; eline++) { @@ -220,7 +205,7 @@ *eline = ' '; *(eline + 1) = ' '; lineno++; - err_fileline(Confname, lineno); + err_fileline(fname, lineno); continue; } @@ -237,64 +222,213 @@ } if (comment >= ebuf) comment = NULL; - if (eline < ebuf) { - char *entry; + if (eline >= ebuf) { + /* discard trailing unterminated line */ + continue; + } + *eline++ = '\0'; - *eline++ = '\0'; + /* + * now we have the entry, if any, at "line" + * and the comment, if any, at "comment" + */ + /* entry is first token */ + entry = nexttok(&line); + if (entry == NULL) { + /* it's just a comment line */ + if (!timescan) + fillconflist(lineno, entry, NULL, comment, 0); + continue; + } + if (strcmp(entry, "logadm-version") == 0) { /* - * now we have the entry, if any, at "line" - * and the comment, if any, at "comment" + * we somehow opened some future format + * conffile that we likely don't understand. + * if the given version is "1" then go on, + * otherwise someone is mixing versions + * and we can't help them other than to + * print an error and exit. */ - - /* entry is first token */ if ((entry = nexttok(&line)) != NULL && - strcmp(entry, "logadm-version") == 0) { - /* - * we somehow opened some future format - * conffile that we likely don't understand. - * if the given version is "1" then go on, - * otherwise someone is mixing versions - * and we can't help them other than to - * print an error and exit. - */ - if ((entry = nexttok(&line)) != NULL && - strcmp(entry, "1") != 0) - err(0, "%s version not " - "supported by " - "this version of logadm.", - Confname); - } else if (entry) { - char *ap; - char **args; - int i; + strcmp(entry, "1") != 0) + err(0, "%s version not supported " + "by this version of logadm.", + fname); + continue; + } + + /* form an argv array */ + ArgsI = 0; + while (ap = nexttok(&line)) + fillargs(ap); + Args[ArgsI] = NULL; + + LOCAL_ERR_BEGIN { + if (SETJMP) { + err(EF_FILE, "cannot process invalid entry %s", + entry); + ret = 0; + LOCAL_ERR_BREAK; + } + + if (timescan) { + /* append to config options */ + cp = lut_lookup(Conflut, entry); + if (cp == NULL) { + /* orphaned entry */ + if (opts_count(cliopts, "v")) + err(EF_FILE, "stale timestamp " + "for %s", entry); + LOCAL_ERR_BREAK; + } + opts = cp->cf_opts; + } + opts = opts_parse(opts, Args, OPTF_CONF); + if (!timescan) { + fillconflist(lineno, entry, opts, comment, 0); + } + LOCAL_ERR_END } + + if (ret == 1 && opts && opts_optarg(opts, "P") != NULL) + ret = 3; + } + + err_fileline(NULL, 0); + return (ret); +} + +/* + * conf_open -- open the configuration file, lock it if we have write perms + */ +int +conf_open(const char *cfname, const char *tfname, struct opts *cliopts) +{ + struct stat stbuf1, stbuf2, stbuf3; + struct flock flock; + int ret; + + Confname = cfname; + Timesname = tfname; + Confentries = fn_list_new(NULL); + Changed = CHG_NONE; + + Changing = CHG_TIMES; + if (opts_count(cliopts, "Vn") != 0) + Changing = CHG_NONE; + else if (opts_count(cliopts, "rw") != 0) + Changing = CHG_BOTH; + + Singlefile = strcmp(Confname, Timesname) == 0; + if (Singlefile && Changing == CHG_TIMES) + Changing = CHG_BOTH; + + /* special case this so we don't even try locking the file */ + if (strcmp(Confname, "/dev/null") == 0) + return (0); + + while (Conffd == -1) { + Canchange = CHG_BOTH; + if ((Conffd = open(Confname, O_RDWR)) < 0) { + if (Changing == CHG_BOTH) + err(EF_SYS, "open %s", Confname); + Canchange = CHG_TIMES; + if ((Conffd = open(Confname, O_RDONLY)) < 0) + err(EF_SYS, "open %s", Confname); + } - ArgsI = 0; - while (ap = nexttok(&line)) - fillargs(ap); - if (ArgsI == 0) { - /* short entry allowed */ - fillconflist(lineno, entry, - NULL, NULL, comment, 0); - } else { - Args[ArgsI++] = NULL; - args = MALLOC(sizeof (char *) * ArgsI); - for (i = 0; i < ArgsI; i++) - args[i] = Args[i]; - fillconflist(lineno, entry, - args, NULL, comment, 0); - } - } else - fillconflist(lineno, entry, NULL, NULL, - comment, 0); + flock.l_type = (Canchange == CHG_BOTH) ? F_WRLCK : F_RDLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 1; + if (fcntl(Conffd, F_SETLKW, &flock) < 0) + err(EF_SYS, "flock on %s", Confname); + + /* wait until after file is locked to get filesize */ + if (fstat(Conffd, &stbuf1) < 0) + err(EF_SYS, "fstat on %s", Confname); + + /* verify that we've got a lock on the active file */ + if (stat(Confname, &stbuf2) < 0 || + !(stbuf2.st_dev == stbuf1.st_dev && + stbuf2.st_ino == stbuf1.st_ino)) { + /* wrong config file, try again */ + (void) close(Conffd); + Conffd = -1; + } + } + + while (!Singlefile && Timesfd == -1) { + if ((Timesfd = open(Timesname, O_CREAT|O_RDWR, 0644)) < 0) { + if (Changing != CHG_NONE) + err(EF_SYS, "open %s", Timesname); + Canchange = CHG_NONE; + if ((Timesfd = open(Timesname, O_RDONLY)) < 0) + err(EF_SYS, "open %s", Timesname); } - line = eline; + + flock.l_type = (Canchange != CHG_NONE) ? F_WRLCK : F_RDLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 1; + if (fcntl(Timesfd, F_SETLKW, &flock) < 0) + err(EF_SYS, "flock on %s", Timesname); + + /* wait until after file is locked to get filesize */ + if (fstat(Timesfd, &stbuf2) < 0) + err(EF_SYS, "fstat on %s", Timesname); + + /* verify that we've got a lock on the active file */ + if (stat(Timesname, &stbuf3) < 0 || + !(stbuf2.st_dev == stbuf3.st_dev && + stbuf2.st_ino == stbuf3.st_ino)) { + /* wrong timestamp file, try again */ + (void) close(Timesfd); + Timesfd = -1; + continue; + } + + /* check that Timesname isn't an alias for Confname */ + if (stbuf2.st_dev == stbuf1.st_dev && + stbuf2.st_ino == stbuf1.st_ino) + err(0, "Timestamp file %s can't refer to " + "Configuration file %s", Timesname, Confname); } + + Conflen = stbuf1.st_size; + Timeslen = stbuf2.st_size; + + if (Conflen == 0) + return (1); /* empty file, don't bother parsing it */ + + if ((Confbuf = (char *)mmap(0, Conflen, + PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1) + err(EF_SYS, "mmap on %s", Confname); + + ret = conf_scan(Confname, Confbuf, Conflen, 0, cliopts); + if (ret == 3 && !Singlefile && Canchange == CHG_BOTH) { + /* + * arrange to transfer any timestamps + * from conf_file to timestamps_file + */ + Changing = Changed = CHG_BOTH; + } + + if (Timesfd != -1 && Timeslen != 0) { + if ((Timesbuf = (char *)mmap(0, Timeslen, + PROT_READ | PROT_WRITE, MAP_PRIVATE, + Timesfd, 0)) == (char *)-1) + err(EF_SYS, "mmap on %s", Timesname); + ret &= conf_scan(Timesname, Timesbuf, Timeslen, 1, cliopts); + } + /* * possible future enhancement: go through and mark any entries: * logfile -P <date> * as DELETED if the logfile doesn't exist */ + + return (ret); } /* @@ -303,35 +437,100 @@ void conf_close(struct opts *opts) { - FILE *fp; + char cuname[PATH_MAX], tuname[PATH_MAX]; + int cfd, tfd; + FILE *cfp = NULL, *tfp = NULL; + boolean_t safe_update = B_TRUE; - if (Confchanged && opts_count(opts, "n") == 0 && Conffd != -1) { + if (Changed == CHG_NONE || opts_count(opts, "n") != 0) { if (opts_count(opts, "v")) - (void) out("# writing changes to %s\n", Confname); - if (Debug > 1) { - (void) fprintf(stderr, "conf_close, %s changed to:\n", - Confname); - conf_print(stderr); - } - if (lseek(Conffd, (off_t)0, SEEK_SET) < 0) - err(EF_SYS, "lseek on %s", Confname); - if (ftruncate(Conffd, (off_t)0) < 0) - err(EF_SYS, "ftruncate on %s", Confname); - if ((fp = fdopen(Conffd, "w")) == NULL) - err(EF_SYS, "fdopen on %s", Confname); - conf_print(fp); - if (fclose(fp) < 0) - err(EF_SYS, "fclose on %s", Confname); - Conffd = -1; - Confchanged = B_FALSE; - } else if (opts_count(opts, "v")) { - (void) out("# %s unchanged\n", Confname); + (void) out("# %s and %s unchanged\n", + Confname, Timesname); + goto cleanup; + } + + if (Debug > 1) { + (void) fprintf(stderr, "conf_close, saving logadm context:\n"); + conf_print(stderr, NULL); } + cuname[0] = tuname[0] = '\0'; + LOCAL_ERR_BEGIN { + if (SETJMP) { + safe_update = B_FALSE; + LOCAL_ERR_BREAK; + } + if (Changed == CHG_BOTH) { + if (Canchange != CHG_BOTH) + err(EF_JMP, "internal error: attempting " + "to update %s without locking", Confname); + (void) snprintf(cuname, sizeof (cuname), "%sXXXXXX", + Confname); + if ((cfd = mkstemp(cuname)) == -1) + err(EF_SYS|EF_JMP, "open %s replacement", + Confname); + if (opts_count(opts, "v")) + (void) out("# writing changes to %s\n", cuname); + if (fchmod(cfd, 0644) == -1) + err(EF_SYS|EF_JMP, "chmod %s", cuname); + if ((cfp = fdopen(cfd, "w")) == NULL) + err(EF_SYS|EF_JMP, "fdopen on %s", cuname); + } else { + /* just toss away the configuration data */ + cfp = fopen("/dev/null", "w"); + } + if (!Singlefile) { + if (Canchange == CHG_NONE) + err(EF_JMP, "internal error: attempting " + "to update %s without locking", Timesname); + (void) snprintf(tuname, sizeof (tuname), "%sXXXXXX", + Timesname); + if ((tfd = mkstemp(tuname)) == -1) + err(EF_SYS|EF_JMP, "open %s replacement", + Timesname); + if (opts_count(opts, "v")) + (void) out("# writing changes to %s\n", tuname); + if (fchmod(tfd, 0644) == -1) + err(EF_SYS|EF_JMP, "chmod %s", tuname); + if ((tfp = fdopen(tfd, "w")) == NULL) + err(EF_SYS|EF_JMP, "fdopen on %s", tuname); + } + + conf_print(cfp, tfp); + if (fclose(cfp) < 0) + err(EF_SYS|EF_JMP, "fclose on %s", Confname); + if (tfp != NULL && fclose(tfp) < 0) + err(EF_SYS|EF_JMP, "fclose on %s", Timesname); + LOCAL_ERR_END } + + if (!safe_update) { + if (cuname[0] != 0) + (void) unlink(cuname); + if (tuname[0] != 0) + (void) unlink(tuname); + err(EF_JMP, "unsafe to update configuration file " + "or timestamps"); + return; + } + + /* rename updated files into place */ + if (cuname[0] != '\0') + if (rename(cuname, Confname) < 0) + err(EF_SYS, "rename %s to %s", cuname, Confname); + if (tuname[0] != '\0') + if (rename(tuname, Timesname) < 0) + err(EF_SYS, "rename %s to %s", tuname, Timesname); + Changed = CHG_NONE; + +cleanup: if (Conffd != -1) { (void) close(Conffd); Conffd = -1; } + if (Timesfd != -1) { + (void) close(Timesfd); + Timesfd = -1; + } if (Conflut) { lut_free(Conflut, free); Conflut = NULL; @@ -345,16 +544,14 @@ /* * conf_lookup -- lookup an entry in the config file */ -char ** +void * conf_lookup(const char *lhs) { struct confinfo *cp = lut_lookup(Conflut, lhs); - if (cp != NULL) { + if (cp != NULL) err_fileline(Confname, cp->cf_lineno); - return (cp->cf_args); - } else - return (NULL); + return (cp); } /* @@ -365,14 +562,9 @@ { struct confinfo *cp = lut_lookup(Conflut, lhs); - if (cp != NULL) { - if (cp->cf_opts) - return (cp->cf_opts); /* already parsed */ - err_fileline(Confname, cp->cf_lineno); - cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); + if (cp != NULL) return (cp->cf_opts); - } - return (opts_parse(NULL, OPTF_CONF)); + return (opts_parse(NULL, NULL, OPTF_CONF)); } /* @@ -388,12 +580,13 @@ if (cp != NULL) { cp->cf_opts = newopts; - cp->cf_args = NULL; + /* cp->cf_args = NULL; */ if (newopts == NULL) cp->cf_flags |= CONFF_DELETED; } else - fillconflist(0, lhs, NULL, newopts, NULL, 0); - Confchanged = B_TRUE; + fillconflist(0, lhs, newopts, NULL, 0); + + Changed = CHG_BOTH; } /* @@ -408,17 +601,18 @@ return; if (cp != NULL) { - if (cp->cf_opts == NULL) - cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); cp->cf_flags &= ~CONFF_DELETED; } else { - fillconflist(0, STRDUP(entry), NULL, - opts_parse(NULL, OPTF_CONF), NULL, 0); + fillconflist(0, STRDUP(entry), + opts_parse(NULL, NULL, OPTF_CONF), NULL, 0); if ((cp = lut_lookup(Conflut, entry)) == NULL) err(0, "conf_set internal error"); } (void) opts_set(cp->cf_opts, o, optarg); - Confchanged = B_TRUE; + if (strcmp(o, "P") == 0) + Changed |= CHG_TIMES; + else + Changed = CHG_BOTH; } /* @@ -432,33 +626,41 @@ /* print the config file */ static void -conf_print(FILE *stream) +conf_print(FILE *cstream, FILE *tstream) { struct confinfo *cp; + char *exclude_opts = "PFfhnrvVw"; + const char *timestamp; + if (tstream == NULL) { + exclude_opts++; /* -P option goes to config file */ + } else { + (void) fprintf(tstream, gettext( + "# This file holds internal data for logadm(1M).\n" + "# Do not edit.\n")); + } for (cp = Confinfo; cp; cp = cp->cf_next) { if (cp->cf_flags & CONFF_DELETED) continue; if (cp->cf_entry) { - char **p; - - opts_printword(cp->cf_entry, stream); - if (cp->cf_opts) { - /* existence of opts overrides args */ - opts_print(cp->cf_opts, stream, "fhnrvVw"); - } else if (cp->cf_args) { - for (p = cp->cf_args; *p; p++) { - (void) fprintf(stream, " "); - opts_printword(*p, stream); - } + opts_printword(cp->cf_entry, cstream); + if (cp->cf_opts) + opts_print(cp->cf_opts, cstream, exclude_opts); + /* output timestamps to tstream */ + if (tstream != NULL && (timestamp = + opts_optarg(cp->cf_opts, "P")) != NULL) { + opts_printword(cp->cf_entry, tstream); + (void) fprintf(tstream, " -P "); + opts_printword(timestamp, tstream); + (void) fprintf(tstream, "\n"); } } if (cp->cf_com) { if (cp->cf_entry) - (void) fprintf(stream, " "); - (void) fprintf(stream, "#%s", cp->cf_com); + (void) fprintf(cstream, " "); + (void) fprintf(cstream, "#%s", cp->cf_com); } - (void) fprintf(stream, "\n"); + (void) fprintf(cstream, "\n"); } } @@ -470,18 +672,23 @@ int main(int argc, char *argv[]) { + struct opts *opts; + err_init(argv[0]); setbuf(stdout, NULL); + opts_init(Opttable, Opttable_cnt); + + opts = opts_parse(NULL, NULL, 0); if (argc != 2) err(EF_RAW, "usage: %s conffile\n", argv[0]); - conf_open(argv[1], 1); + conf_open(argv[1], argv[1], opts); printf("conffile <%s>:\n", argv[1]); - conf_print(stdout); + conf_print(stdout, NULL); - conf_close(opts_parse(NULL, 0)); + conf_close(opts); err_done(0); /* NOTREACHED */
--- a/usr/src/cmd/logadm/conf.h Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/conf.h Mon Aug 02 10:54:24 2010 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/conf.h -- public definitions for conf module */ @@ -29,15 +27,13 @@ #ifndef _LOGADM_CONF_H #define _LOGADM_CONF_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif -void conf_open(const char *fname, int needwrite); +int conf_open(const char *cfname, const char *tfname, struct opts *opts); void conf_close(struct opts *opts); -char **conf_lookup(const char *lhs); +void *conf_lookup(const char *lhs); struct opts *conf_opts(const char *lhs); void conf_replace(const char *lhs, struct opts *newopts); void conf_set(const char *entry, char *o, const char *optarg);
--- a/usr/src/cmd/logadm/err.c Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/err.c Mon Aug 02 10:54:24 2010 -0700 @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/err.c -- some basic error routines * */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <unistd.h> #include <libintl.h> @@ -37,6 +34,7 @@ #include <errno.h> #include "err.h" +jmp_buf *Err_env_ptr; static const char *Myname; static int Exitcode; static FILE *Errorfile; @@ -143,7 +141,7 @@ va_end(ap); if (jump) - longjmp(Err_env, 1); + longjmp(*Err_env_ptr, 1); if (!warning && !fileline) { err_done(1);
--- a/usr/src/cmd/logadm/err.h Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/err.h Mon Aug 02 10:54:24 2010 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/err.h -- public definitions for error module */ @@ -29,8 +27,6 @@ #ifndef _LOGADM_ERR_H #define _LOGADM_ERR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <setjmp.h> #ifdef __cplusplus @@ -55,8 +51,12 @@ #define EF_RAW 0x10 /* don't prepend/append anything to message */ jmp_buf Err_env; +extern jmp_buf *Err_env_ptr; -#define SETJMP setjmp(Err_env) +#define SETJMP setjmp(*(Err_env_ptr = &Err_env)) +#define LOCAL_ERR_BEGIN { jmp_buf Err_env, *Save_err_env_ptr = Err_env_ptr; { +#define LOCAL_ERR_END } Err_env_break: Err_env_ptr = Save_err_env_ptr; } +#define LOCAL_ERR_BREAK goto Err_env_break #define MALLOC(nbytes) err_malloc(nbytes, __FILE__, __LINE__) void *err_malloc(int nbytes, const char *fname, int line);
--- a/usr/src/cmd/logadm/main.c Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/main.c Mon Aug 02 10:54:24 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/main.c -- main routines for logadm * @@ -66,6 +65,8 @@ /* our configuration file, unless otherwise specified by -f */ static char *Default_conffile = "/etc/logadm.conf"; +/* our timestamps file, unless otherwise specified by -F */ +static char *Default_timestamps = "/var/logadm/timestamps"; /* default pathnames to the commands we invoke */ static char *Sh = "/bin/sh"; @@ -92,40 +93,8 @@ /* A list of names of files to be gzipped */ static struct lut *Gzipnames = NULL; -/* table that drives argument parsing */ -static struct optinfo Opttable[] = { - { "e", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "f", OPTTYPE_STRING, NULL, OPTF_CLI }, - { "h", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, - { "l", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, - { "N", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, - { "n", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, - { "r", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, - { "V", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, - { "v", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, - { "w", OPTTYPE_STRING, NULL, OPTF_CLI }, - { "p", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF }, - { "P", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF }, - { "s", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF }, - { "a", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "b", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "c", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, - { "g", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "m", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, - { "M", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "o", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "R", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "t", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "z", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, - { "A", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF }, - { "C", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, - { "E", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, - { "S", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF }, - { "T", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, -}; - /* - * only the "fhnVv" options are allowed in the first form of this command, + * only the "FfhnVv" options are allowed in the first form of this command, * so this defines the list of options that are an error in they appear * in the first form. In other words, it is not allowed to run logadm * with any of these options unless at least one logname is also provided. @@ -141,6 +110,7 @@ "\n"\ "General options:\n"\ " -e mailaddr mail errors to given address\n"\ +" -F timestamps use timestamps instead of /var/logadm/timestamps\n"\ " -f conffile use conffile instead of /etc/logadm.conf\n"\ " -h display help\n"\ " -N not an error if log file nonexistent\n"\ @@ -188,10 +158,12 @@ { struct opts *clopts; /* from parsing command line */ const char *conffile; /* our configuration file */ + const char *timestamps; /* our timestamps file */ struct fn_list *lognames; /* list of lognames we're processing */ struct fn *fnp; char *val; char *buf; + int status; (void) setlocale(LC_ALL, ""); @@ -201,7 +173,7 @@ (void) textdomain(TEXT_DOMAIN); - /* we only print times into the conffile, so make them uniform */ + /* we only print times into the timestamps file, so make them uniform */ (void) setlocale(LC_TIME, "C"); /* give our name to error routines & skip it for arg parsing */ @@ -221,6 +193,8 @@ /* check for (undocumented) debugging environment variables */ if (val = getenv("_LOGADM_DEFAULT_CONFFILE")) Default_conffile = val; + if (val = getenv("_LOGADM_DEFAULT_TIMESTAMPS")) + Default_timestamps = val; if (val = getenv("_LOGADM_DEBUG")) Debug = atoi(val); if (val = getenv("_LOGADM_SH")) @@ -240,13 +214,13 @@ if (val = getenv("_LOGADM_MKDIR")) Mkdir = val; - opts_init(Opttable, sizeof (Opttable) / sizeof (struct optinfo)); + opts_init(Opttable, Opttable_cnt); /* parse command line arguments */ if (SETJMP) usage("bailing out due to command line errors"); else - clopts = opts_parse(argv, OPTF_CLI); + clopts = opts_parse(NULL, argv, OPTF_CLI); if (Debug) { (void) fprintf(stderr, "command line opts:"); @@ -327,12 +301,16 @@ if (opts_count(clopts, "e")) err_mailto(opts_optarg(clopts, "e")); - /* this implements the default conffile */ + /* this implements the default conffile and timestamps */ if ((conffile = opts_optarg(clopts, "f")) == NULL) conffile = Default_conffile; + if ((timestamps = opts_optarg(clopts, "F")) == NULL) + timestamps = Default_timestamps; if (opts_count(clopts, "v")) (void) out("# loading %s\n", conffile); - conf_open(conffile, opts_count(clopts, "Vn") == 0); + status = conf_open(conffile, timestamps, clopts); + if (!status && opts_count(clopts, "V")) + err_done(0); /* handle conffile write option */ if (opts_count(clopts, "w")) {
--- a/usr/src/cmd/logadm/opts.c Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/opts.c Mon Aug 02 10:54:24 2010 -0700 @@ -20,12 +20,9 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * logadm/opts.c -- options handling routines */ @@ -55,8 +52,48 @@ struct fn_list *op_cmdargs; /* the op_cmdargs */ }; +static off_t opts_parse_ctime(const char *o, const char *optarg); +static off_t opts_parse_bytes(const char *o, const char *optarg); +static off_t opts_parse_atopi(const char *o, const char *optarg); +static off_t opts_parse_seconds(const char *o, const char *optarg); + static struct lut *Info; /* table driving parsing */ +/* table that drives argument parsing */ +struct optinfo Opttable[] = { + { "e", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "F", OPTTYPE_STRING, NULL, OPTF_CLI }, + { "f", OPTTYPE_STRING, NULL, OPTF_CLI }, + { "h", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, + { "l", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, + { "N", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, + { "n", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, + { "r", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, + { "V", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, + { "v", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, + { "w", OPTTYPE_STRING, NULL, OPTF_CLI }, + { "p", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF }, + { "P", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF }, + { "s", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF }, + { "a", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "b", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "c", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF }, + { "g", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "m", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, + { "M", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "o", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "R", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "t", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "z", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, + { "A", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF }, + { "C", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF }, + { "E", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, + { "S", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF }, + { "T", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF }, +}; + +int Opttable_cnt = sizeof (Opttable) / sizeof (struct optinfo); + /* * opts_init -- set current options parsing table */ @@ -87,24 +124,26 @@ * prints a message to stderr and calls err(EF_FILE|EF_JMP, ...) on error */ struct opts * -opts_parse(char **argv, int flags) +opts_parse(struct opts *opts, char **argv, int flags) { - struct opts *ret = MALLOC(sizeof (*ret)); int dashdash = 0; char *ptr; - ret->op_raw = ret->op_ints = NULL; - ret->op_cmdargs = fn_list_new(NULL); + if (opts == NULL) { + opts = MALLOC(sizeof (*opts)); + opts->op_raw = opts->op_ints = NULL; + opts->op_cmdargs = fn_list_new(NULL); + } /* no words to process, just return empty opts struct */ if (argv == NULL) - return (ret); + return (opts); /* foreach word... */ for (; (ptr = *argv) != NULL; argv++) { if (dashdash || *ptr != '-') { /* found a cmdarg */ - opts_setcmdarg(ret, ptr); + opts_setcmdarg(opts, ptr); continue; } if (*++ptr == '\0') @@ -138,7 +177,7 @@ /* for boolean options, we have all the info we need */ if (info->oi_t == OPTTYPE_BOOLEAN) { - (void) opts_set(ret, info->oi_o, ""); + (void) opts_set(opts, info->oi_o, ""); continue; } @@ -148,12 +187,12 @@ err(EF_FILE|EF_JMP, "Option '%c' requires an argument", info->oi_o[0]); - opts_set(ret, info->oi_o, ptr); + opts_set(opts, info->oi_o, ptr); break; } } - return (ret); + return (opts); } /* @@ -277,7 +316,7 @@ /* * opts_parse_ctime -- parse a ctime format optarg */ -off_t +static off_t opts_parse_ctime(const char *o, const char *optarg) { struct tm tm; @@ -297,7 +336,7 @@ /* * opts_parse_atopi -- parse a positive integer format optarg */ -off_t +static off_t opts_parse_atopi(const char *o, const char *optarg) { off_t ret = atoll(optarg); @@ -315,7 +354,7 @@ /* * opts_parse_atopi -- parse a size format optarg into bytes */ -off_t +static off_t opts_parse_bytes(const char *o, const char *optarg) { off_t ret = atoll(optarg); @@ -350,7 +389,7 @@ /* * opts_parse_seconds -- parse a time format optarg into seconds */ -off_t +static off_t opts_parse_seconds(const char *o, const char *optarg) { off_t ret; @@ -436,13 +475,13 @@ strchr(word, '$') || strchr(word, '[') || strchr(word, '?') || strchr(word, '{') || strchr(word, '`') || strchr(word, ';')) { - if (strchr(word, '\'')) + if (strchr(word, '\'') == NULL) + q = "'"; + else if (strchr(word, '"') == NULL) q = "\""; - else if (strchr(word, '"')) + else err(EF_FILE|EF_JMP, "Can't protect quotes in <%s>", word); - else - q = "'"; (void) fprintf(stream, "%s%s%s", q, word, q); } else (void) fprintf(stream, "%s", word); @@ -474,7 +513,7 @@ #ifdef TESTMODULE /* table that drives argument parsing */ -static struct optinfo Opttable[] = { +static struct optinfo Testopttable[] = { { "a", OPTTYPE_BOOLEAN, NULL, OPTF_CLI }, { "b", OPTTYPE_STRING, NULL, OPTF_CLI }, { "c", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF }, @@ -494,14 +533,15 @@ err_init(argv[0]); setbuf(stdout, NULL); - opts_init(Opttable, sizeof (Opttable) / sizeof (struct optinfo)); + opts_init(Testopttable, + sizeof (Testopttable) / sizeof (struct optinfo)); argv++; if (SETJMP) err(0, "opts parsing failed"); else - opts = opts_parse(argv, OPTF_CLI); + opts = opts_parse(NULL, argv, OPTF_CLI); printf("options:"); opts_print(opts, stdout, NULL);
--- a/usr/src/cmd/logadm/opts.h Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/opts.h Mon Aug 02 10:54:24 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/opts.h -- public definitions for opts module */ @@ -28,8 +27,6 @@ #ifndef _LOGADM_OPTS_H #define _LOGADM_OPTS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -57,7 +54,7 @@ #define OPTF_CONF 2 void opts_init(struct optinfo *table, int numentries); -struct opts *opts_parse(char **args, int flags); +struct opts *opts_parse(struct opts *, char **args, int flags); void opts_free(struct opts *opts); void opts_set(struct opts *opts, const char *o, const char *optarg); int opts_count(struct opts *opts, const char *options); @@ -69,14 +66,12 @@ #define OPTP_NOW (-1) #define OPTP_NEVER (-2) -off_t opts_parse_ctime(const char *o, const char *optarg); -off_t opts_parse_bytes(const char *o, const char *optarg); -off_t opts_parse_atopi(const char *o, const char *optarg); -off_t opts_parse_seconds(const char *o, const char *optarg); - void opts_print(struct opts *opts, FILE *stream, char *exclude); void opts_printword(const char *word, FILE *stream); +extern struct optinfo Opttable[]; +extern int Opttable_cnt; + #ifdef __cplusplus } #endif
--- a/usr/src/cmd/logadm/tester Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/cmd/logadm/tester Mon Aug 02 10:54:24 2010 -0700 @@ -20,10 +20,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # # tester - run logadm tests @@ -91,6 +88,7 @@ "logadm17", "logadm18", "logadm19", + "logadm20", ); use Getopt::Std; @@ -191,11 +189,11 @@ print STDERR " to do a fresh setup of this test.\n"; exit 1; } - eval "runner('checktest')"; + eval "runner('checktest', '-x', '> checktest.out 2>&1')"; if ($@) { print " CHECKTEST FAILURE\n"; print STDERR "$myname: ERROR: $@"; - print STDERR "results captured in directory $dir\n"; + print STDERR "results captured in file $dir/checktest.out\n"; print STDERR " or use: $myname -s $testname $bindir\n"; print STDERR " to do a fresh setup of this test.\n"; exit 1; @@ -223,8 +221,9 @@ # is actually checking the program under test and not /bin/sh # sub runner { - my $cmd = shift; - my $fullcmd = "/bin/sh $cmd"; + my ($cmd, $prefix, $suffix) = (@_, '', ''); + + my $fullcmd = "/bin/sh $prefix $cmd $suffix"; my $rc = 0xffff & system("$fullcmd"); if ($rc == 0) { @@ -309,9 +308,9 @@ set_testconffile; set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } /bin/sed '/^conffile <testfile.conf>:$/d' <std.out >sed.out -exec /bin/diff sed.out testfile.conf +exec /bin/diff testfile.conf sed.out EOF set_file('runtest', <<"EOF"); @@ -330,11 +329,11 @@ set_file('testfile.conf', 'line fragment'); set_file('std.err.expect', <<'EOF'); -conftest: Warning: config file doesn't end with newline, last line ignored. +conftest: Warning: file testfile.conf doesn't end with newline, last line ignored. EOF set_file('checktest', <<'EOF'); -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -544,8 +543,8 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -exec /bin/diff std.out std.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +exec /bin/diff std.out.expect std.out EOF $testglobs='\'file{A,B,C}name*\' \'file{A,B,C}name\' \'dir1/dirA/file*\' \'dir[13]/[e-z]*\' \'dir?/dir[AC]/fileBname[2-9]\' -r \'file[A-Z]n.*e([0-9]+)$0\''; @@ -568,7 +567,7 @@ EOF set_file('checktest', <<'EOF'); -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -634,12 +633,12 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } /bin/sed -e '/^ *secs [0-9][0-9]*$/d'\ -e "s/%d/`/bin/env TZ=UTC /bin/date +%d`/g"\ -e "s/%Y/`/bin/env TZ=UTC /bin/date +%Y`/g"\ <std.out >sed.out -exec /bin/diff sed.out sed.out.expect +exec /bin/diff sed.out.expect sed.out EOF $kwtest='kwtest /var/log/syslog \'$file.$n\' \'moose%d.$n\' \'/var/logs-%Y/moose-$isa$#porklips%d.$n\''; @@ -705,12 +704,12 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } /bin/sed -e '/^ *secs [0-9][0-9]*$/d'\ -e "s/%d/`/bin/env TZ=UTC /bin/date +%d`/g"\ -e "s/%Y/`/bin/env TZ=UTC /bin/date +%Y`/g"\ <std.out >sed.out -exec /bin/diff sed.out sed.out.expect +exec /bin/diff sed.out.expect sed.out EOF $kwtest='kwtest /var/log/syslog \'$file.$n\' \'moose%d.$n\' \'/var/logs-%Y/moose-$isa$#porklips%d.$n\''; @@ -723,6 +722,8 @@ export HOME USER= export USER +TZ=UTC +export TZ exec $bindir/$kwtest >std.out 2>std.err EOF } @@ -749,8 +750,8 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -exec /bin/diff std.out std.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +exec /bin/diff std.out.expect std.out EOF set_file('runtest', <<"EOF"); @@ -772,8 +773,8 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -exec /bin/diff std.out std.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +exec /bin/diff std.out.expect std.out EOF set_file('runtest', <<"EOF"); @@ -797,7 +798,7 @@ set_file('checktest', <<'EOF'); [ -s std.out ] && exit 1 -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -831,14 +832,14 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -exec /bin/diff std.out std.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +exec /bin/diff std.out.expect std.out EOF set_file('runtest', <<"EOF"); # test "logadmV1" $envsetup -exec $bindir/logadm -f testfile.conf -V >std.out 2>std.err +exec $bindir/logadm -f testfile.conf -F testfile.conf -V >std.out 2>std.err EOF } @@ -856,14 +857,14 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -exec /bin/diff std.out std.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +exec /bin/diff std.out.expect std.out EOF set_file('runtest', <<"EOF"); # test "logadmV2" $envsetup -exec $bindir/logadm -f testfile.conf -V /var/cron/log /var/adm/pacct >std.out 2>std.err +exec $bindir/logadm -f testfile.conf -F testfile.conf -V /var/cron/log /var/adm/pacct >std.out 2>std.err EOF } @@ -877,22 +878,22 @@ set_testconffile('testfile.conf.orig'); set_file('diff.out.expect', <<'EOF'); -17a18 -> /var/cron/log -s 512k -t /var/cron/olog -21a23 -> /var/adm/pacct -C 0 -a '/usr/lib/acct/accton pacct' -g adm -m 664 -o adm -p never +18d17 +< /var/cron/log -s 512k -t /var/cron/olog +23d21 +< /var/adm/pacct -C 0 -a '/usr/lib/acct/accton pacct' -g adm -m 664 -o adm -p never EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -/bin/diff testfile.conf testfile.conf.orig > diff.out -exec /bin/diff diff.out diff.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +/bin/diff testfile.conf.orig testfile.conf > diff.out +exec /bin/diff diff.out.expect diff.out EOF set_file('runtest', <<"EOF"); # test "logadmr" $envsetup -exec $bindir/logadm -f testfile.conf -r /var/cron/log /var/adm/pacct >std.out 2>std.err +exec $bindir/logadm -f testfile.conf -F testfile.conf -r /var/cron/log /var/adm/pacct >std.out 2>std.err EOF } @@ -906,20 +907,20 @@ set_testconffile('testfile.conf.orig'); set_file('diff.out.expect', <<'EOF'); -31d30 -< moose -C 20 -a moose_after_cmd -g pig -m 664 -o cow -p never /moose/file +30a31 +> moose -C 20 -a moose_after_cmd -g pig -m 664 -o cow -p never /moose/file EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 -/bin/diff testfile.conf testfile.conf.orig > diff.out -exec /bin/diff diff.out diff.out.expect +[ -s std.err ] && { cat std.err; exit 1; } +/bin/diff testfile.conf.orig testfile.conf > diff.out +exec /bin/diff diff.out.expect diff.out EOF set_file('runtest', <<"EOF"); # test "logadmw" $envsetup -exec $bindir/logadm -f testfile.conf -w moose -C 20 -a moose_after_cmd -g pig -m 664 -o cow -p never /moose/file >std.out 2>std.err +exec $bindir/logadm -f testfile.conf -F testfile.conf -w moose -C 20 -a moose_after_cmd -g pig -m 664 -o cow -p never /moose/file >std.out 2>std.err EOF } @@ -936,7 +937,7 @@ lstat 'logfile' or die "lstat logfile: $!\n"; set_file('checktest', <<"EOF"); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 @@ -967,7 +968,7 @@ lstat 'logfile' or die "lstat logfile: $!\n"; set_file('checktest', <<"EOF"); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 @@ -996,7 +997,7 @@ set_file('logfile.1', 'initially logfile.1'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 @@ -1025,7 +1026,7 @@ set_file('logfile.1', 'initially logfile.1'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 @@ -1056,7 +1057,7 @@ set_file('logfile', 'initially logfile'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 TZ=UTC export TZ @@ -1088,14 +1089,14 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 [ "xinitially logfile" = "x`/bin/cat logfile.0`" ] || exit 1 [ -f logfile.1 ] || exit 1 [ "xinitially logfile.0" = "x`/bin/cat logfile.1`" ] || exit 1 -exec /bin/diff cmd.out cmd.out.expect +exec /bin/diff cmd.out.expect cmd.out EOF set_file('runtest', <<"EOF"); @@ -1119,13 +1120,13 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] || exit 1 +[ -s std.err ] || exit 1; [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 [ -f logfile.0 ] || exit 1 [ "xinitially logfile" = "x`/bin/cat logfile.0`" ] || exit 1 [ "`/bin/ls -l logfile | /bin/awk '{ print $1; }'`" = "-r----x--x" ] || exit 1 -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -1195,9 +1196,17 @@ second kill -HUP $pid EOF + set_file('sed.out.expect', <<'EOF'); +# This file holds internal data for logadm(1M). +# Do not edit. +dir1/syslog +dir2/messages +EOF + set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 +[ -s logadm.timestamps ] || exit 1 [ -s std.err2 ] && exit 1 [ -s std.out2 ] && exit 1 [ -s std.err3 ] && exit 1 @@ -1234,8 +1243,9 @@ [ -f dir2/messages.3 ] || exit 1 [ "xinitially dir2/messages.1" = "x`/bin/cat dir2/messages.3`" ] || exit 1 [ -f dir2/messages.4 ] && exit 1 -/bin/sed "s/-P '[^']*' *//" < logadm.conf > sed.out -exec /bin/diff sed.out logadm.conf.orig +/bin/sed "s/ -P '[^']*' *//" < logadm.timestamps > sed.out +/bin/diff sed.out.expect sed.out || exit 1 +exec /bin/diff logadm.conf.orig logadm.conf EOF # first logadm call will rotate both syslog and messages @@ -1245,12 +1255,12 @@ set_file('runtest', <<"EOF"); # test "logadm7" $envsetup -$bindir/logadm -f logadm.conf >std.out 2>std.err || exit 1 -$bindir/logadm -f logadm.conf dir1/syslog dir2/messages >std.out2 2>std.err2 || exit 1 +$bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err || exit 1 +$bindir/logadm -f logadm.conf -F logadm.timestamps dir1/syslog dir2/messages >std.out2 2>std.err2 || exit 1 echo something > dir1/syslog echo something > dir2/messages -$bindir/logadm -f logadm.conf >std.out3 2>std.err3 || exit 1 -exec $bindir/logadm -f logadm.conf dir2/messages -p now -a 'echo second kill -HUP `cat /etc/syslog.pid` >> cmd.out' >std.out4 2>std.err4 +$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 EOF } @@ -1284,7 +1294,7 @@ die "gzip dir1/syslog.7 didn't work\n" unless -f 'dir1/syslog.7.gz'; set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ -s dir1/syslog ] && exit 1 @@ -1332,12 +1342,14 @@ set_file('dir1/syslog.5', 'initially dir1/syslog.5'); set_file('dir1/syslog.6', 'initially dir1/syslog.6'); set_file('dir1/syslog.7', 'initially dir1/syslog.7'); + set_file('dir1/notes', 'initially dir1/notes'); mkdir 'dir2', 0777 or die "mkdir dir2: $!\n"; set_file('dir2/messages', 'initially dir2/messages'); set_file('dir2/messages.0', 'initially dir2/messages.0'); set_file('dir2/messages.1', 'initially dir2/messages.1'); set_file('dir2/messages.2', 'initially dir2/messages.2'); set_file('dir2/messages.3', 'initially dir2/messages.3'); + set_file('dir2/log', 'initially dir2/log'); $now = time; $nowstr = gmtime($now); @@ -1354,12 +1366,27 @@ # now: $nowstr is $now # $closetoweek is $closetoweeksecs dir1/syslog -C 8 -P '$closetoweek' +dir2/log -C 4 # $lessthanweek is $lessthanweeksecs -dir2/messages -C 4 -P '$lessthanweek' +dir1/notes -C 2 -P '$lessthanweek' +dir2/messages -C 4 +EOF + set_file('logadm.timestamps', <<"EOF"); +dir2/log -P '$closetoweek' +dir2/messages -P '$lessthanweek' +EOF + + set_file('sed.out.expect', <<"EOF"); +# This file holds internal data for logadm(1M). +# Do not edit. +dir1/syslog +dir2/log +dir1/notes +dir2/messages EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ -s dir1/syslog ] && exit 1 @@ -1381,6 +1408,10 @@ [ "xinitially dir1/syslog.6" = "x`/bin/cat dir1/syslog.7`" ] || exit 1 [ -f dir1/syslog.8 ] && exit 1 +[ -s dir1/notes ] || exit 1 +[ "xinitially dir1/notes" = "x`/bin/cat dir1/notes`" ] || exit 1 +[ -f dir1/notes.0 ] && exit 1 + [ -f dir2/messages ] || exit 1 [ "xinitially dir2/messages" = "x`/bin/cat dir2/messages`" ] || exit 1 [ -f dir2/messages.0 ] || exit 1 @@ -1392,13 +1423,24 @@ [ -f dir2/messages.3 ] || exit 1 [ "xinitially dir2/messages.3" = "x`/bin/cat dir2/messages.3`" ] || exit 1 [ -f dir2/messages.4 ] && exit 1 + +[ -f dir2/log ] || exit 1 +[ -s dir2/log ] && exit 1 +[ -f dir2/log.0 ] || exit 1 +[ "xinitially dir2/log" = "x`/bin/cat dir2/log.0`" ] || exit 1 +[ -f dir2/log.1 ] && exit 1 + +/bin/sed "s/ -P '[^']*' *//" < logadm.timestamps > sed.out +/bin/diff sed.out.expect sed.out || exit 1 +/bin/sed -n "s/ -P '[^']*' */<&>/p" < logadm.conf > sed.out +[ -s sed.out ] && exit 1 exit 0 EOF set_file('runtest', <<"EOF"); # test "logadm9" $envsetup -exec $bindir/logadm -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -1443,7 +1485,7 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ -s dir1/syslog ] && exit 1 @@ -1482,7 +1524,7 @@ set_file('runtest', <<"EOF"); # test "logadm9d" $envsetup -exec $bindir/logadm -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -1515,7 +1557,7 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ -s dir1/syslog ] && exit 1 @@ -1554,7 +1596,7 @@ set_file('runtest', <<"EOF"); # test "logadm10" $envsetup -exec $bindir/logadm -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -1587,7 +1629,7 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ "xinitially dir1/syslog" = "x`/bin/cat dir1/syslog`" ] || exit 1 @@ -1620,7 +1662,7 @@ set_file('runtest', <<"EOF"); # test "logadm11" $envsetup -exec $bindir/logadm -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -1636,7 +1678,7 @@ set_file('checktest', <<"EOF"); [ -s std.out ] && exit 1 -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -1653,8 +1695,8 @@ ########################################################################### sub logadm13 { set_file('checktest', <<"EOF"); +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 -[ -s std.err ] && exit 1 exit 0 EOF @@ -1765,11 +1807,11 @@ # processing logname: /var/adm/pacct # using default template: $file.$n sh -c echo kill -HUP `cat /etc/syslog.pid` >> cmd.out # -a cmd -# logadm.conf unchanged +# logadm.conf and logadm.timestamps unchanged EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -f std.out ] || exit 1 [ -f dir1/syslog ] || exit 1 [ "xinitially dir1/syslog" = "x`/bin/cat dir1/syslog`" ] || exit 1 @@ -1803,13 +1845,13 @@ [ "xinitially dir2/messages.3" = "x`/bin/cat dir2/messages.3`" ] || exit 1 [ -f dir2/messages.4 ] && exit 1 /bin/grep -v 'recording rotation date' std.out > grep.out -exec /bin/diff grep.out grep.out.expect +exec /bin/diff grep.out.expect grep.out EOF set_file('runtest', <<"EOF"); # test "logadm14" $envsetup -exec $bindir/logadm -nv -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -nv -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -1832,7 +1874,7 @@ set_file('logfile.9', 'initially logfile.9'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f logfile ] || exit 1 [ "x" = "x`/bin/cat logfile`" ] || exit 1 @@ -1877,6 +1919,7 @@ General options: -e mailaddr mail errors to given address + -F timestamps use timestamps instead of /var/logadm/timestamps -f conffile use conffile instead of /etc/logadm.conf -h display help -N not an error if log file nonexistent @@ -1917,7 +1960,7 @@ set_file('checktest', <<'EOF'); [ -s std.out ] && exit 1 -exec /bin/diff std.err std.err.expect +exec /bin/diff std.err.expect std.err EOF set_file('runtest', <<"EOF"); @@ -1936,7 +1979,7 @@ set_file('logfile', 'initially logfile'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/dir2/logfile ] || exit 1 [ -f logfile ] || exit 1 @@ -1973,7 +2016,7 @@ EOF set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -f dir1/syslog ] || exit 1 [ -s dir1/syslog ] && exit 1 @@ -2001,7 +2044,7 @@ set_file('runtest', <<"EOF"); # test "logadm18" $envsetup -exec $bindir/logadm -f logadm.conf >std.out 2>std.err +exec $bindir/logadm -f logadm.conf -F logadm.timestamps >std.out 2>std.err EOF } @@ -2014,7 +2057,7 @@ set_file('logfile', 'initially logfile'); set_file('checktest', <<'EOF'); -[ -s std.err ] && exit 1 +[ -s std.err ] && { cat std.err; exit 1; } [ -s std.out ] && exit 1 [ -s logfile ] && exit 1 TZ= export TZ @@ -2025,8 +2068,43 @@ EOF set_file('runtest', <<"EOF"); -# test "logadm4" +# test "logadm19" $envsetup exec $bindir/logadm -f /dev/null -l -p now logfile -t '\$file.\%d\%H\%M' >std.out 2>std.err EOF } + +############################################################################# +# +# logadm20 -- test of unquotables/error handling +# +############################################################################# +sub logadm20 { + set_file('logadm.conf', <<'EOF'); +# non-trivial entry +/var/log/syslog -C 8 -a 'kill -HUP `cat /var/run/syslog.pid`' +EOF + + set_file('std.err.expect', <<'EOF'); +logadm: Error: Can't protect quotes in </bin/echo "She can't take anymore, Cap'n!"> +logadm: Error: unsafe to update configuration file or timestamps +logadm: Error: bailing out due to command line errors +Use "logadm -h" for help. +exit=1 +EOF + + set_file('checktest', <<'EOF'); +[ -s std.err ] || exit 1 +[ -s std.out ] && exit 1 +[ -f logadm.conf????? ] && exit 1 +[ -f logadm.timestamps????? ] && exit 1 +exec /bin/diff std.err.expect std.err +EOF + + set_file('runtest', <<"EOF"); +# test "logadm20" +$envsetup +$bindir/logadm -f logadm.conf -F logadm.timestamps -w /a/b/c -p 1w -l -b "/bin/echo \\"She can't take anymore, Cap'n!\\"" >std.out 2>std.err +echo exit=\$? >>std.err +EOF +}
--- a/usr/src/pkg/manifests/SUNWcs.mf Mon Aug 02 08:40:07 2010 -0400 +++ b/usr/src/pkg/manifests/SUNWcs.mf Mon Aug 02 10:54:24 2010 -0700 @@ -289,6 +289,7 @@ dir path=var/ld dir path=var/ld/$(ARCH64) dir path=var/log group=sys +dir path=var/logadm dir path=var/mail group=mail mode=1777 dir path=var/mail/:saved group=mail mode=0775 dir path=var/news