diff options
author | John.Zolnowsky@Sun.COM <none@none> | 2010-08-02 10:54:24 -0700 |
---|---|---|
committer | John.Zolnowsky@Sun.COM <none@none> | 2010-08-02 10:54:24 -0700 |
commit | e9a193fce9f1bf8520f55929577e0175e1e7625b (patch) | |
tree | 2a9d532ee63263a71458d9b3754a6323a66a0e84 | |
parent | fff7ec1d8ce71b3d8a998ac4391a99860ce07180 (diff) | |
download | illumos-joyent-e9a193fce9f1bf8520f55929577e0175e1e7625b.tar.gz |
4685009 logadm(1M) should avoid silent updates of /etc/logadm.conf
-rw-r--r-- | usr/src/Targetdirs | 1 | ||||
-rw-r--r-- | usr/src/cmd/logadm/Makefile | 2 | ||||
-rw-r--r-- | usr/src/cmd/logadm/conf.c | 515 | ||||
-rw-r--r-- | usr/src/cmd/logadm/conf.h | 14 | ||||
-rw-r--r-- | usr/src/cmd/logadm/err.c | 8 | ||||
-rw-r--r-- | usr/src/cmd/logadm/err.h | 16 | ||||
-rw-r--r-- | usr/src/cmd/logadm/main.c | 58 | ||||
-rw-r--r-- | usr/src/cmd/logadm/opts.c | 88 | ||||
-rw-r--r-- | usr/src/cmd/logadm/opts.h | 15 | ||||
-rw-r--r-- | usr/src/cmd/logadm/tester | 244 | ||||
-rw-r--r-- | usr/src/pkg/manifests/SUNWcs.mf | 1 |
11 files changed, 628 insertions, 334 deletions
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index 592002817e..d73e5fc95d 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -362,6 +362,7 @@ DIRS= \ /var/ld \ /var/log \ /var/log/pool \ + /var/logadm \ /var/mail \ /var/news \ /var/opt \ diff --git a/usr/src/cmd/logadm/Makefile b/usr/src/cmd/logadm/Makefile index 818483159e..b997fe6ead 100644 --- a/usr/src/cmd/logadm/Makefile +++ b/usr/src/cmd/logadm/Makefile @@ -56,7 +56,7 @@ $(METHOD) := FILEMODE = 0555 all: $(PROG) test: $(TESTS) $(PROG) - ./tester `pwd` + $(PERL) -w ./tester `pwd` $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) diff --git a/usr/src/cmd/logadm/conf.c b/usr/src/cmd/logadm/conf.c index 936238e848..5e0f053333 100644 --- a/usr/src/cmd/logadm/conf.c +++ b/usr/src/cmd/logadm/conf.c @@ -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 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 char *Confbuf; /* copy of the config file (a la mmap()) */ +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 { 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 @@ static struct fn_list *Confentries; /* list of valid entry names */ /* 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 @@ fillconflist(int lineno, const char *entry, char **args, 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 @@ nexttok(char **ptrptr) } /* - * 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; - - 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; - - if ((Conffd = open(Confname, (needwrite) ? O_RDWR : O_RDONLY)) < 0) - err(EF_SYS, "%s", Confname); + char *entry, *comment; - if (fstat(Conffd, &stbuf) < 0) - err(EF_SYS, "fstat on %s", Confname); + ebuf = &buf[buflen]; - 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 */ + for (line = buf; line < ebuf; line = eline) { + char *ap; + struct opts *opts = NULL; + struct confinfo *cp; - 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; - - 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 @@ conf_open(const char *fname, int needwrite) *eline = ' '; *(eline + 1) = ' '; lineno++; - err_fileline(Confname, lineno); + err_fileline(fname, lineno); continue; } @@ -237,64 +222,213 @@ conf_open(const char *fname, int needwrite) } if (comment >= ebuf) comment = NULL; - if (eline < ebuf) { - char *entry; - - *eline++ = '\0'; - + if (eline >= ebuf) { + /* discard trailing unterminated line */ + continue; + } + *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; - - 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); + 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; } - } else - fillconflist(lineno, entry, NULL, NULL, - comment, 0); + 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); + } + + 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); + } + + 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; } - line = eline; + + /* 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 @@ conf_open(const char *fname, int needwrite) 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", + (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); - conf_print(stderr); + 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 (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); + 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_close(struct opts *opts) /* * 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 @@ conf_opts(const char *lhs) { 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 @@ conf_replace(const char *lhs, struct opts *newopts) 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 @@ conf_set(const char *entry, char *o, const char *optarg) 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 @@ conf_entries(void) /* 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 @@ conf_print(FILE *stream) 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 */ diff --git a/usr/src/cmd/logadm/conf.h b/usr/src/cmd/logadm/conf.h index fc6c11a249..71cbd71afb 100644 --- a/usr/src/cmd/logadm/conf.h +++ b/usr/src/cmd/logadm/conf.h @@ -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); diff --git a/usr/src/cmd/logadm/err.c b/usr/src/cmd/logadm/err.c index 32b3a4ce9a..5663232ec2 100644 --- a/usr/src/cmd/logadm/err.c +++ b/usr/src/cmd/logadm/err.c @@ -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 @@ err(int flags, const char *fmt, ...) va_end(ap); if (jump) - longjmp(Err_env, 1); + longjmp(*Err_env_ptr, 1); if (!warning && !fileline) { err_done(1); diff --git a/usr/src/cmd/logadm/err.h b/usr/src/cmd/logadm/err.h index 679f632e9a..de2abd9300 100644 --- a/usr/src/cmd/logadm/err.h +++ b/usr/src/cmd/logadm/err.h @@ -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 @@ void err_mailto(const char *recipient); #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); diff --git a/usr/src/cmd/logadm/main.c b/usr/src/cmd/logadm/main.c index 15d551cef4..d1f105f7be 100644 --- a/usr/src/cmd/logadm/main.c +++ b/usr/src/cmd/logadm/main.c @@ -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 @@ static void docopytruncate(struct opts *opts, const char *file, /* 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 @@ static struct lut *Donenames; /* 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 @@ static struct optinfo Opttable[] = { "\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 @@ main(int argc, char *argv[]) { 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 @@ main(int argc, char *argv[]) (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 @@ main(int argc, char *argv[]) /* 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 @@ main(int argc, char *argv[]) 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 @@ main(int argc, char *argv[]) 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")) { diff --git a/usr/src/cmd/logadm/opts.c b/usr/src/cmd/logadm/opts.c index 40b8f42cfc..6de73a599a 100644 --- a/usr/src/cmd/logadm/opts.c +++ b/usr/src/cmd/logadm/opts.c @@ -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 opts { 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 @@ opt_info(int c) * 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 @@ opts_parse(char **argv, int flags) /* 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 @@ opts_parse(char **argv, int flags) 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_merge(struct opts *back, struct opts *front) /* * 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_ctime(const char *o, const char *optarg) /* * 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(const char *o, const char *optarg) /* * 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_bytes(const char *o, const char *optarg) /* * 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 @@ opts_printword(const char *word, FILE *stream) 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 @@ opts_print(struct opts *opts, FILE *stream, char *exclude) #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 @@ main(int argc, char *argv[]) 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); diff --git a/usr/src/cmd/logadm/opts.h b/usr/src/cmd/logadm/opts.h index 32857b5540..d28581bc49 100644 --- a/usr/src/cmd/logadm/opts.h +++ b/usr/src/cmd/logadm/opts.h @@ -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 @@ struct optinfo { #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 @@ struct opts *opts_merge(struct opts *back, struct opts *front); #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 diff --git a/usr/src/cmd/logadm/tester b/usr/src/cmd/logadm/tester index 1c88ce5bbd..1ff4985e6d 100644 --- a/usr/src/cmd/logadm/tester +++ b/usr/src/cmd/logadm/tester @@ -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 @@ umask 002; "logadm17", "logadm18", "logadm19", + "logadm20", ); use Getopt::Std; @@ -191,11 +189,11 @@ if ($opt_s) { 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 @@ exit 0; # 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 @@ sub conftest1 { 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 @@ sub conftest2 { 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 @@ total size: 0 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 @@ globtest: Error: Missing } 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 @@ $secondblob 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 @@ $secondblob 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 @@ HOME= export HOME USER= export USER +TZ=UTC +export TZ exec $bindir/$kwtest >std.out 2>std.err EOF } @@ -749,8 +750,8 @@ dup lut contains: 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 @@ options: $options 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 @@ EOF 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 @@ apache -C 24 -a '/usr/apache/bin/apachectl graceful' -p 1m -t '/var/apache/old-l 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 @@ sub logadmV2 { 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 @@ sub logadmr { 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 @@ sub logadmw { 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 @@ sub logadm1 { 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 @@ sub logadm1c { 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 @@ sub logadm2 { 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 @@ sub logadm3 { 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 @@ sub logadm4 { 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 @@ just expired: initially logfile.0 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 @@ chown: unknown group id _nonexistentgroup_ 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 @@ kill -HUP $pid 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 @@ EOF [ -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 @@ EOF 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 @@ sub logadm8 { 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 @@ sub logadm9 { 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 @@ sub logadm9 { # 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 @@ EOF [ "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 @@ EOF [ -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 @@ dir2/messages -p 1d -C 4 -P '$lessthanday' 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 @@ EOF 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 @@ dir2/messages -C 4 -s 30b 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 @@ EOF 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 @@ dir2/messages -C 4 -s 30b -S 75b 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 @@ EOF 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 @@ EOF 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 @@ EOF ########################################################################### 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 @@ 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 -# 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 @@ EOF [ "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 @@ sub logadm15 { 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 @@ Usage: logadm [options] 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 @@ EOF 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 @@ sub logadm17 { 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 @@ dir1/syslog -C 8 -s 1b -M '/bin/tr [a-z] [A-Z] < \$file > \$nfile; /bin/rm -f \$ 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 @@ EOF 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 @@ sub logadm19 { 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 @@ exit 0 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 +} diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf index 16e3fe3e73..71eef6e9e4 100644 --- a/usr/src/pkg/manifests/SUNWcs.mf +++ b/usr/src/pkg/manifests/SUNWcs.mf @@ -289,6 +289,7 @@ dir path=var/inet group=sys 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 |