summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn.Zolnowsky@Sun.COM <none@none>2010-08-02 10:54:24 -0700
committerJohn.Zolnowsky@Sun.COM <none@none>2010-08-02 10:54:24 -0700
commite9a193fce9f1bf8520f55929577e0175e1e7625b (patch)
tree2a9d532ee63263a71458d9b3754a6323a66a0e84
parentfff7ec1d8ce71b3d8a998ac4391a99860ce07180 (diff)
downloadillumos-joyent-e9a193fce9f1bf8520f55929577e0175e1e7625b.tar.gz
4685009 logadm(1M) should avoid silent updates of /etc/logadm.conf
-rw-r--r--usr/src/Targetdirs1
-rw-r--r--usr/src/cmd/logadm/Makefile2
-rw-r--r--usr/src/cmd/logadm/conf.c515
-rw-r--r--usr/src/cmd/logadm/conf.h14
-rw-r--r--usr/src/cmd/logadm/err.c8
-rw-r--r--usr/src/cmd/logadm/err.h16
-rw-r--r--usr/src/cmd/logadm/main.c58
-rw-r--r--usr/src/cmd/logadm/opts.c88
-rw-r--r--usr/src/cmd/logadm/opts.h15
-rw-r--r--usr/src/cmd/logadm/tester244
-rw-r--r--usr/src/pkg/manifests/SUNWcs.mf1
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