diff options
author | gad <gad@FreeBSD.org> | 2003-03-09 03:19:52 +0000 |
---|---|---|
committer | gad <gad@FreeBSD.org> | 2003-03-09 03:19:52 +0000 |
commit | cb92a79e4c40edd2ec78f17a9894efc9d43df6b3 (patch) | |
tree | 55f21ce74dfdca7d652ba50ae540aa61a9eaac5d /usr.sbin/newsyslog | |
parent | 519d3ae8c736355c05986ec123095e911e3e7b1e (diff) | |
download | FreeBSD-src-cb92a79e4c40edd2ec78f17a9894efc9d43df6b3.zip FreeBSD-src-cb92a79e4c40edd2ec78f17a9894efc9d43df6b3.tar.gz |
Fix interactions between entries for a specific file vs entries for
a filename pattern, and also wrt filenames given on the command line.
Now if a file is listed as a specific entry, it will not *also* be
processed by an entry specifying a pattern. And filename-patterns
will now only match existing files (ignoring directories, etc).
MFC after: 3 weeks
Diffstat (limited to 'usr.sbin/newsyslog')
-rw-r--r-- | usr.sbin/newsyslog/newsyslog.c | 239 |
1 files changed, 177 insertions, 62 deletions
diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c index 643536b..2b9c71e 100644 --- a/usr.sbin/newsyslog/newsyslog.c +++ b/usr.sbin/newsyslog/newsyslog.c @@ -119,11 +119,14 @@ char daytime[16]; /* timenow in human readable form */ static struct conf_entry *get_worklist(char **files); static void parse_file(FILE *cf, const char *cfname, struct conf_entry **work_p, - struct conf_entry **defconf_p); + struct conf_entry **glob_p, struct conf_entry **defconf_p); static char *sob(char *p); static char *son(char *p); static char *missing_field(char *p, char *errline); static void do_entry(struct conf_entry * ent); +static void expand_globs(struct conf_entry **work_p, + struct conf_entry **glob_p); +static void free_clist(struct conf_entry **firstent); static void free_entry(struct conf_entry *ent); static struct conf_entry *init_entry(const char *fname, struct conf_entry *src_entry); @@ -156,9 +159,6 @@ int main(int argc, char **argv) { struct conf_entry *p, *q; - char *savglob; - glob_t pglob; - int i; parse_args(argc, argv); argc -= optind; @@ -169,25 +169,7 @@ main(int argc, char **argv) p = q = get_worklist(argv); while (p) { - if ((p->flags & CE_GLOB) == 0) { - do_entry(p); - } else { - if (verbose > 2) - printf("\t+ Processing pattern %s\n", p->log); - if (glob(p->log, GLOB_NOCHECK, NULL, &pglob) != 0) { - warn("can't expand pattern: %s", p->log); - } else { - savglob = p->log; - for (i = 0; i < pglob.gl_matchc; i++) { - p->log = pglob.gl_pathv[i]; - do_entry(p); - } - globfree(&pglob); - p->log = savglob; - if (verbose > 2) - printf("\t+ Done with pattern\n"); - } - } + do_entry(p); p = p->next; free_entry(q); q = p; @@ -278,6 +260,24 @@ free_entry(struct conf_entry *ent) } static void +free_clist(struct conf_entry **firstent) +{ + struct conf_entry *ent, *nextent; + + if (firstent == NULL) + return; /* There is nothing to do. */ + + ent = *firstent; + firstent = NULL; + + while (ent) { + nextent = ent->next; + free_entry(ent); + ent = nextent; + } +} + +static void do_entry(struct conf_entry * ent) { #define REASON_MAX 80 @@ -548,10 +548,10 @@ get_worklist(char **files) const char *fname; char **given; struct conf_entry *defconf, *dupent, *ent, *firstnew; - struct conf_entry *newlist, *worklist; - int gmatch; + struct conf_entry *globlist, *lastnew, *worklist; + int gmatch, fnres; - defconf = worklist = NULL; + defconf = globlist = worklist = NULL; fname = conf; if (fname == NULL) @@ -566,15 +566,19 @@ get_worklist(char **files) if (!f) err(1, "%s", conf); - parse_file(f, fname, &worklist, &defconf); + parse_file(f, fname, &worklist, &globlist, &defconf); (void) fclose(f); /* * All config-file information has been read in and turned into - * a worklist. If there were no specific files given on the run - * command, then the work of this routine is done. + * a worklist and a globlist. If there were no specific files + * given on the run command, then the only thing left to do is to + * call a routine which finds all files matched by the globlist + * and adds them to the worklist. Then return the worklist. */ if (*files == NULL) { + expand_globs(&worklist, &globlist); + free_clist(&globlist); if (defconf != NULL) free_entry(defconf); return (worklist); @@ -607,23 +611,21 @@ get_worklist(char **files) * we want to continue to allow it? If so, it should * probably be handled more intelligently. */ - firstnew = newlist = NULL; + firstnew = lastnew = NULL; for (given = files; *given; ++given) { - gmatch = 0; /* * First try to find exact-matches for this given file. */ + gmatch = 0; for (ent = worklist; ent; ent = ent->next) { - if ((ent->flags & CE_GLOB) != 0) - continue; if (strcmp(ent->log, *given) == 0) { gmatch++; dupent = init_entry(*given, ent); if (!firstnew) firstnew = dupent; else - newlist->next = dupent; - newlist = dupent; + lastnew->next = dupent; + lastnew = dupent; } } if (gmatch) { @@ -636,18 +638,23 @@ get_worklist(char **files) * There was no exact-match for this given file, so look * for a "glob" entry which does match. */ - for (ent = worklist; ent; ent = ent->next) { - if ((ent->flags & CE_GLOB) == 0) - continue; - if (fnmatch(ent->log, *given, FNM_PATHNAME) == 0) { + gmatch = 0; + if (verbose > 2 && globlist != NULL) + printf("\t+ Checking globs for %s\n", *given); + for (ent = globlist; ent; ent = ent->next) { + fnres = fnmatch(ent->log, *given, FNM_PATHNAME); + if (verbose > 2) + printf("\t+ = %d for pattern %s\n", fnres, + ent->log); + if (fnres == 0) { gmatch++; dupent = init_entry(*given, ent); if (!firstnew) firstnew = dupent; else - newlist->next = dupent; - newlist = dupent; - /* This work entry is *not* a glob! */ + lastnew->next = dupent; + lastnew = dupent; + /* This new entry is not a glob! */ dupent->flags &= ~CE_GLOB; /* Only allow a match to one glob-entry */ break; @@ -671,46 +678,138 @@ get_worklist(char **files) if (!firstnew) firstnew = dupent; else - newlist->next = dupent; + lastnew->next = dupent; /* Mark that it was *not* found in a config file */ dupent->def_cfg = 1; - newlist = dupent; + lastnew = dupent; } /* - * Free all the entries in the original work list, and then - * return the new work list. + * Free all the entries in the original work list, the list of + * glob entries, and the default entry. */ - while (worklist) { - ent = worklist->next; - free_entry(worklist); - worklist = ent; - } - + free_clist(&worklist); + free_clist(&globlist); free_entry(defconf); + + /* And finally, return a worklist which matches the given files. */ return (firstnew); } /* + * Expand the list of entries with filename patterns, and add all files + * which match those glob-entries onto the worklist. + */ +static void +expand_globs(struct conf_entry **work_p, struct conf_entry **glob_p) +{ + int gmatch, gres, i; + char *mfname; + struct conf_entry *dupent, *ent, *firstmatch, *globent; + struct conf_entry *lastmatch; + glob_t pglob; + struct stat st_fm; + + if ((glob_p == NULL) || (*glob_p == NULL)) + return; /* There is nothing to do. */ + + /* + * The worklist contains all fully-specified (non-GLOB) names. + * + * Now expand the list of filename-pattern (GLOB) entries into + * a second list, which (by definition) will only match files + * that already exist. Do not add a glob-related entry for any + * file which already exists in the fully-specified list. + */ + firstmatch = lastmatch = NULL; + for (globent = *glob_p; globent; globent = globent->next) { + + gres = glob(globent->log, GLOB_NOCHECK, NULL, &pglob); + if (gres != 0) { + warn("cannot expand pattern (%d): %s", gres, + globent->log); + continue; + } + + if (verbose > 2) + printf("\t+ Expanding pattern %s\n", globent->log); + for (i = 0; i < pglob.gl_matchc; i++) { + mfname = pglob.gl_pathv[i]; + + /* See if this file already has a specific entry. */ + gmatch = 0; + for (ent = *work_p; ent; ent = ent->next) { + if (strcmp(mfname, ent->log) == 0) { + gmatch++; + break; + } + } + if (gmatch) + continue; + + /* Make sure the named matched is a file. */ + gres = lstat(mfname, &st_fm); + if (gres != 0) { + /* Error on a file that glob() matched?!? */ + warn("Skipping %s - lstat() error", mfname); + continue; + } + if (!S_ISREG(st_fm.st_mode)) { + /* We only rotate files! */ + if (verbose > 2) + printf("\t+ . skipping %s (!file)\n", + mfname); + continue; + } + + if (verbose > 2) + printf("\t+ . add file %s\n", mfname); + dupent = init_entry(mfname, globent); + if (!firstmatch) + firstmatch = dupent; + else + lastmatch->next = dupent; + lastmatch = dupent; + /* This new entry is not a glob! */ + dupent->flags &= ~CE_GLOB; + } + globfree(&pglob); + if (verbose > 2) + printf("\t+ Done with pattern %s\n", globent->log); + } + + /* Add the list of matched files to the end of the worklist. */ + if (!*work_p) + *work_p = firstmatch; + else { + ent = *work_p; + while (ent->next) + ent = ent->next; + ent->next = firstmatch; + } + +} + +/* * Parse a configuration file and update a linked list of all the logs to * process. */ static void parse_file(FILE *cf, const char *cfname, struct conf_entry **work_p, - struct conf_entry **defconf_p) + struct conf_entry **glob_p, struct conf_entry **defconf_p) { char line[BUFSIZ], *parse, *q; char *cp, *errline, *group; - struct conf_entry *working, *worklist; + struct conf_entry *lastglob, *lastwork, *working; struct passwd *pwd; struct group *grp; - int eol; + int eol, special; /* * XXX - for now, assume that only one config file will be read, * ie, this routine is only called one time. */ - worklist = NULL; + lastglob = lastwork = NULL; while (fgets(line, BUFSIZ, cf)) { if ((line[0] == '\n') || (line[0] == '#') || @@ -736,8 +835,10 @@ parse_file(FILE *cf, const char *cfname, struct conf_entry **work_p, errline); *parse = '\0'; + special = 0; working = init_entry(q, NULL); if (strcasecmp(DEFAULT_MARKER, q) == 0) { + special = 1; if (defconf_p == NULL) { warnx("Ignoring entry for %s in %s!", q, cfname); @@ -749,12 +850,6 @@ parse_file(FILE *cf, const char *cfname, struct conf_entry **work_p, continue; } *defconf_p = working; - } else { - if (!*work_p) - *work_p = working; - else - worklist->next = working; - worklist = working; } q = parse = missing_field(sob(++parse), errline); @@ -993,6 +1088,26 @@ parse_file(FILE *cf, const char *cfname, struct conf_entry **work_p, working->pid_file = strdup(_PATH_SYSLOGPID); } + /* + * Add this entry to the appropriate list of entries, unless + * it was some kind of special entry (eg: <default>). + */ + if (special) { + ; /* Do not add to any list */ + } else if (working->flags & CE_GLOB) { + if (!*glob_p) + *glob_p = working; + else + lastglob->next = working; + lastglob = working; + } else { + if (!*work_p) + *work_p = working; + else + lastwork->next = working; + lastwork = working; + } + free(errline); errline = NULL; } |