Apply by doing: cd /usr/src patch -p0 < 001_newsyslog.patch cd usr.bin/newsyslog make make install Index: usr.bin/newsyslog/newsyslog.c =================================================================== RCS file: /cvs/src/usr.bin/newsyslog/newsyslog.c,v retrieving revision 1.21 retrieving revision 1.27 diff -u -r1.21 -r1.27 --- usr.bin/newsyslog/newsyslog.c 1999/10/13 17:24:23 1.21 +++ usr.bin/newsyslog/newsyslog.c 1999/11/07 05:31:53 1.27 @@ -1,4 +1,4 @@ -/* $OpenBSD: newsyslog.c,v 1.21 1999/10/13 17:24:23 millert Exp $ */ +/* $OpenBSD: newsyslog.c,v 1.27 1999/11/07 05:31:53 millert Exp $ */ /* * Copyright (c) 1997, Jason Downs. All rights reserved. @@ -61,7 +61,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.21 1999/10/13 17:24:23 millert Exp $"; +static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.27 1999/11/07 05:31:53 millert Exp $"; #endif /* not lint */ #ifndef CONF @@ -99,18 +99,17 @@ #include #include -#define kbytes(size) (((size) + 1023) >> 10) - -#define CE_COMPACT 0x01 /* Compact the achived log files */ -#define CE_BINARY 0x02 /* Logfile is in binary, don't add */ +#define CE_ROTATED 0x01 /* Log file has been rotated */ +#define CE_COMPACT 0x02 /* Compact the achived log files */ +#define CE_BINARY 0x04 /* Logfile is in binary, don't add */ /* status messages */ -#define CE_MONITOR 0x04 /* Monitory for changes */ +#define CE_MONITOR 0x08 /* Monitory for changes */ #define NONE -1 struct conf_entry { char *log; /* Name of the log */ - int uid; /* Owner of log */ - int gid; /* Group of log */ + uid_t uid; /* Owner of log */ + gid_t gid; /* Group of log */ int numlogs; /* Number of logs to keep */ int size; /* Size cutoff to trigger trimming the log */ int hours; /* Hours between log trimming */ @@ -121,8 +120,6 @@ struct conf_entry *next; /* Linked list pointer */ }; -extern const char *__progname; - int verbose = 0; /* Print out what's going on */ int needroot = 1; /* Root privs are necessary */ int noaction = 0; /* Don't do anything, just show it */ @@ -139,11 +136,11 @@ void usage __P((void)); struct conf_entry *parse_file __P((void)); char *missing_field __P((char *, char *)); -void dotrim __P((char *, int, int, int, int, int, int)); +void dotrim __P((char *, int, int, int, uid_t, gid_t)); int log_trim __P((char *)); void compress_log __P((char *)); int sizefile __P((char *)); -int age_old_log __P((char *, int *)); +int age_old_log __P((char *)); char *sob __P((char *)); char *son __P((char *)); int isnumberstr __P((char *)); @@ -151,24 +148,44 @@ FILE *openmail __P((void)); void closemail __P((FILE *)); void child_killer __P((int)); +void send_hup __P((char *)); -int main(argc, argv) +int +main(argc, argv) int argc; char **argv; { struct conf_entry *p, *q; int status; - PRS(argc,argv); + PRS(argc, argv); if (needroot && getuid() && geteuid()) errx(1, "You must be root."); p = q = parse_file(); signal(SIGCHLD, child_killer); + + /* Step 1, rotate all log files */ + while (q) { + do_entry(q); + q = q->next; + } + + /* Step 2, send a HUP to relevant processes */ + /* XXX - should avoid HUP'ing the same process multiple times */ + q = p; + while (q) { + if (q->flags & CE_ROTATED) + send_hup(q->pidfile); + q = q->next; + } + + /* Step 3, compress the log.0 file if configured to do so and free */ while (p) { - do_entry(p); - p=p->next; + if ((p->flags & CE_COMPACT) && (p->flags & CE_ROTATED)) + compress_log(p->log); + q = p; + p = p->next; free(q); - q=p; } /* Wait for children to finish, then exit */ @@ -177,28 +194,18 @@ exit(0); } -void do_entry(ent) +void +do_entry(ent) struct conf_entry *ent; { - int size, modtime, pid; - char line[BUFSIZ]; - FILE *f; + int modtime, size; - /* First find the pid to HUP */ - pid = -1; - if ((f = fopen(ent->pidfile,"r")) != NULL) { - if (fgets(line,BUFSIZ,f)) - pid = atoi(line); - (void)fclose(f); - } - if (verbose) printf("%s <%d%s>: ", ent->log, ent->numlogs, (ent->flags & CE_COMPACT) ? "Z" : ""); size = sizefile(ent->log); - if (age_old_log(ent->log, &modtime) == -1) - modtime = 0; + modtime = age_old_log(ent->log); if (size < 0) { if (verbose) printf("does not exist.\n"); @@ -209,24 +216,52 @@ printf(" age (hr): %d [%d] ", modtime, ent->hours); if (monitor && ent->flags & CE_MONITOR) domonitor(ent->log, ent->whom); - if (!monitor && ((ent->size > 0) && (size >= ent->size)) || + if (!monitor && (((ent->size > 0) && (size >= ent->size)) || ((ent->hours > 0) && ((modtime >= ent->hours) - || (modtime < 0)))) { + || (modtime < 0))))) { if (verbose) printf("--> trimming log....\n"); if (noaction && !verbose) printf("%s <%d%s>: ", ent->log, ent->numlogs, (ent->flags & CE_COMPACT) ? "Z" : ""); dotrim(ent->log, ent->numlogs, ent->flags, - ent->permissions, ent->uid, ent->gid, pid); - } else { - if (verbose) - printf("--> skipping\n"); - } + ent->permissions, ent->uid, ent->gid); + ent->flags |= CE_ROTATED; + } else if (verbose) + printf("--> skipping\n"); } } + +/* Send a HUP to the pid specified by pidfile */ +void +send_hup(pidfile) + char *pidfile; +{ + FILE *f; + char line[BUFSIZ]; + pid_t pid = 0; + + if ((f = fopen(pidfile, "r")) == NULL) { + warn("can't open %s", pidfile); + return; + } + + if (fgets(line, sizeof(line), f)) + pid = atoi(line); + (void)fclose(f); + + if (noaction) + (void)printf("kill -HUP %d\n", pid); + else if (pid == 0) + warnx("empty pid file: %s", pidfile); + else if (pid < MIN_PID) + warnx("preposterous process number: %d", pid); + else if (kill(pid, SIGHUP)) + warnx("warning - could not HUP daemon"); +} -void PRS(argc, argv) +void +PRS(argc, argv) int argc; char **argv; { @@ -238,7 +273,7 @@ daytime[15] = '\0'; /* Let's get our hostname */ - (void) gethostname(hostname, sizeof(hostname)); + (void)gethostname(hostname, sizeof(hostname)); /* Truncate domain */ p = strchr(hostname, '.'); @@ -246,7 +281,7 @@ *p = '\0'; optind = 1; /* Start options parsing */ - while ((c = getopt(argc,argv,"nrvmf:t:")) != -1) { + while ((c = getopt(argc, argv, "nrvmf:t:")) != -1) { switch (c) { case 'n': noaction++; /* This implies needroot as off */ @@ -269,34 +304,39 @@ } } -void usage() +void +usage() { - fprintf(stderr, "usage: %s [-nrvm] [-f config-file]\n", __progname); + extern const char *__progname; + + (void)fprintf(stderr, "usage: %s [-nrvm] [-f config-file]\n", + __progname); exit(1); } /* Parse a configuration file and return a linked list of all the logs * to process */ -struct conf_entry *parse_file() +struct conf_entry * +parse_file() { FILE *f; char line[BUFSIZ], *parse, *q; - char *errline, *group; + char *errline, *group, *tmp; struct conf_entry *first = NULL; struct conf_entry *working; struct passwd *pass; struct group *grp; - if (strcmp(conf,"-")) - f = fopen(conf,"r"); - else + if (strcmp(conf, "-") == 0) f = stdin; - if (!f) - err(1, conf); + else { + if ((f = fopen(conf, "r")) == NULL) + err(1, "can't open %s", conf); + } - while (fgets(line,BUFSIZ,f)) { - if ((line[0]== '\n') || (line[0] == '#')) + while (fgets(line, sizeof(line), f)) { + if ((line[0] == '\n') || (line[0] == '#')) continue; errline = strdup(line); if (errline == NULL) @@ -313,58 +353,58 @@ working = working->next; } - q = parse = missing_field(sob(line),errline); + q = parse = missing_field(sob(line), errline); *(parse = son(line)) = '\0'; working->log = strdup(q); if (working->log == NULL) err(1, "strdup"); - q = parse = missing_field(sob(++parse),errline); + q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\0'; - if ((group = strchr(q, '.')) != NULL) { - *group++ = '\0'; - if (*q) { - if (!(isnumberstr(q))) { - if ((pass = getpwnam(q)) == NULL) - errx(1, "Error in config file; unknown user: %s", q); - working->uid = pass->pw_uid; - } else - working->uid = atoi(q); - } else - working->uid = NONE; - - q = group; - if (*q) { - if (!(isnumberstr(q))) { - if ((grp = getgrnam(q)) == NULL) - errx(1, "Error in config file; unknown group: %s", q); - working->gid = grp->gr_gid; - } else - working->gid = atoi(q); - } else - working->gid = NONE; - - q = parse = missing_field(sob(++parse),errline); - *(parse = son(parse)) = '\0'; - } else - working->uid = working->gid = NONE; + if ((group = strchr(q, '.')) != NULL) { + *group++ = '\0'; + if (*q) { + if (!(isnumberstr(q))) { + if ((pass = getpwnam(q)) == NULL) + errx(1, "Error in config file; unknown user: %s", q); + working->uid = pass->pw_uid; + } else + working->uid = atoi(q); + } else + working->uid = NONE; + + q = group; + if (*q) { + if (!(isnumberstr(q))) { + if ((grp = getgrnam(q)) == NULL) + errx(1, "Error in config file; unknown group: %s", q); + working->gid = grp->gr_gid; + } else + working->gid = atoi(q); + } else + working->gid = NONE; + + q = parse = missing_field(sob(++parse), errline); + *(parse = son(parse)) = '\0'; + } else + working->uid = working->gid = NONE; - if (!sscanf(q,"%o",&working->permissions)) + if (!sscanf(q, "%o", &working->permissions)) errx(1, "Error in config file; bad permissions: %s", q); - q = parse = missing_field(sob(++parse),errline); + q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\0'; - if (!sscanf(q,"%d",&working->numlogs) || working->numlogs < 0) + if (!sscanf(q, "%d", &working->numlogs) || working->numlogs < 0) errx(1, "Error in config file; bad number: %s", q); - q = parse = missing_field(sob(++parse),errline); + q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->size = atoi(q); else working->size = -1; - q = parse = missing_field(sob(++parse),errline); + q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->hours = atoi(q); @@ -400,21 +440,31 @@ q = parse = sob(++parse); /* Optional field */ *(parse = son(parse)) = '\0'; if (q && *q != '\0') { + if (strlen(q) >= MAXPATHLEN) + errx(1, "%s: pathname too long", q); working->pidfile = strdup(q); if (working->pidfile == NULL) err(1, "strdup"); } + + /* Make sure we can't oflow MAXPATHLEN */ + if (asprintf(&tmp, "%s.%d%s", working->log, working->numlogs, + COMPRESS_POSTFIX) >= MAXPATHLEN) + errx(1, "%s: pathname too long", working->log); + free(tmp); free(errline); } if (working) working->next = NULL; - (void) fclose(f); + (void)fclose(f); return(first); } -char *missing_field(p, errline) - char *p,*errline; +char * +missing_field(p, errline) + char *p; + char *errline; { if (!p || !*p) { warnx("Missing field in config file line:"); @@ -424,164 +474,170 @@ return(p); } -void dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid) +void +dotrim(log, numdays, flags, perm, owner_uid, group_gid) char *log; int numdays; int flags; int perm; - int owner_uid; - int group_gid; - int daemon_pid; + uid_t owner_uid; + gid_t group_gid; { char file1[MAXPATHLEN], file2[MAXPATHLEN]; char zfile1[MAXPATHLEN], zfile2[MAXPATHLEN]; int fd; struct stat st; int days = numdays; - - /* Remove oldest log */ - (void) sprintf(file1,"%s.%d",log,numdays); - (void) strcpy(zfile1, file1); - (void) strcat(zfile1, COMPRESS_POSTFIX); + /* Remove oldest log (may not exist) */ + (void)sprintf(file1, "%s.%d", log, numdays); + (void)strcpy(zfile1, file1); + (void)strcat(zfile1, COMPRESS_POSTFIX); if (noaction) { - printf("rm -f %s\n", file1); - printf("rm -f %s\n", zfile1); + printf("rm -f %s %s\n", file1, zfile1); } else { - (void) unlink(file1); - (void) unlink(zfile1); + (void)unlink(file1); + (void)unlink(zfile1); } /* Move down log files */ while (numdays--) { - (void) strcpy(file2,file1); - (void) sprintf(file1,"%s.%d",log,numdays); - (void) strcpy(zfile1, file1); - (void) strcpy(zfile2, file2); + (void)strcpy(file2, file1); + (void)sprintf(file1, "%s.%d", log, numdays); + (void)strcpy(zfile1, file1); + (void)strcpy(zfile2, file2); if (lstat(file1, &st)) { - (void) strcat(zfile1, COMPRESS_POSTFIX); - (void) strcat(zfile2, COMPRESS_POSTFIX); - if (lstat(zfile1, &st)) continue; + (void)strcat(zfile1, COMPRESS_POSTFIX); + (void)strcat(zfile2, COMPRESS_POSTFIX); + if (lstat(zfile1, &st)) + continue; } if (noaction) { - printf("mv %s %s\n",zfile1,zfile2); + printf("mv %s %s\n", zfile1, zfile2); printf("chmod %o %s\n", perm, zfile2); - printf("chown %d.%d %s\n", + printf("chown %d:%d %s\n", owner_uid, group_gid, zfile2); } else { - (void) rename(zfile1, zfile2); - (void) chmod(zfile2, perm); - (void) chown(zfile2, owner_uid, group_gid); + if (rename(zfile1, zfile2)) + warn("can't mv %s to %s", zfile1, zfile2); + if (chmod(zfile2, perm)) + warn("can't chmod %s", zfile2); + if (chown(zfile2, owner_uid, group_gid)) + warn("can't chown %s", zfile2); } } if (!noaction && !(flags & CE_BINARY)) - (void) log_trim(log); /* Report the trimming to the old log */ + (void)log_trim(log); /* Report the trimming to the old log */ + (void)snprintf(file2, sizeof(file2), "%s.XXXXXXXXXX", log); + if (noaction) { + printf("Create new log file...\n"); + } else { + if ((fd = mkstemp(file2)) < 0) + err(1, "can't start '%s' log", file2); + if (fchown(fd, owner_uid, group_gid)) + err(1, "can't chown '%s' log file", file2); + if (fchmod(fd, perm)) + err(1, "can't chmod '%s' log file", file2); + (void)close(fd); + /* Add status message */ + if (!(flags & CE_BINARY) && log_trim(file2)) + err(1, "can't add status message to log '%s'", file2); + } + if (days == 0) { if (noaction) - printf("rm %s\n",log); - else - (void) unlink(log); + printf("rm %s\n", log); + else if (unlink(log)) + warn("can't rm %s", log); } else { if (noaction) - printf("mv %s to %s\n",log,file1); - else - (void) rename(log,file1); + printf("mv %s to %s\n", log, file1); + else if (rename(log, file1)) + warn("can't to mv %s to %s", log, file1); } - if (noaction) - printf("Start new log..."); - else { - fd = creat(log,perm); - if (fd < 0) - err(1, "can't start \'%s\' log", log); - if (fchown(fd, owner_uid, group_gid)) - err(1, "can't chown \'%s\' log file", log); - (void) close(fd); - if (!(flags & CE_BINARY)) - if (log_trim(log)) /* Add status message */ - err(1, "can't add status message to log \'%s\'", log); - } - if (noaction) - printf("chmod %o %s...",perm,log); - else - (void) chmod(log,perm); - if (noaction) - printf("kill -HUP %d\n",daemon_pid); - else if (daemon_pid < MIN_PID) - warnx("preposterous process number: %d", daemon_pid); - else if (kill(daemon_pid,SIGHUP)) - warnx("warning - could not HUP daemon"); - if (flags & CE_COMPACT) { - if (noaction) - printf("Compress %s.0\n",log); - else - compress_log(log); - } + /* Now move the new log file into place */ + if (noaction) + printf("mv %s to %s\n", file2, log); + else if (rename(file2, log)) + warn("can't to mv %s to %s", file2, log); } /* Log the fact that the logs were turned over */ -int log_trim(log) +int +log_trim(log) char *log; { FILE *f; - if ((f = fopen(log,"a")) == NULL) + + if ((f = fopen(log, "a")) == NULL) return(-1); - fprintf(f,"%s %s newsyslog[%d]: logfile turned over\n", - daytime, hostname, getpid()); - if (fclose(f) == EOF) { + (void)fprintf(f, "%s %s newsyslog[%d]: logfile turned over\n", + daytime, hostname, getpid()); + if (fclose(f) == EOF) err(1, "log_trim: fclose"); - } return(0); } /* Fork off compress or gzip to compress the old log file */ -void compress_log(log) +void +compress_log(log) char *log; { - int pid; + pid_t pid; + char *base; char tmp[MAXPATHLEN]; + if ((base = strrchr(COMPRESS, '/')) == NULL) + base = COMPRESS; + else + base++; + if (noaction) { + printf("%s %s.0\n", base, log); + return; + } pid = fork(); - (void) sprintf(tmp,"%s.0",log); + (void)sprintf(tmp, "%s.0", log); if (pid < 0) { err(1, "fork"); } else if (!pid) { - (void) execl(COMPRESS,"compress","-f",tmp,0); + (void)execl(COMPRESS, base, "-f", tmp, 0); warn(COMPRESS); _exit(1); } } /* Return size in kilobytes of a file */ -int sizefile(file) +int +sizefile(file) char *file; { struct stat sb; - if (stat(file,&sb) < 0) + if (stat(file, &sb) < 0) return(-1); - return(kbytes(dbtob(sb.st_blocks))); + return(sb.st_blocks / (1024.0 / DEV_BSIZE)); } -/* Return the age of old log file (file.0) */ -int age_old_log(file, mtime) +/* Return the age (in hours) of old log file (file.0), or -1 if none */ +int +age_old_log(file) char *file; - int *mtime; { struct stat sb; char tmp[MAXPATHLEN]; - (void) strcpy(tmp,file); - if (stat(strcat(tmp,".0"),&sb) < 0) - if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0) + (void)strcpy(tmp, file); + if (stat(strcat(tmp, ".0"), &sb) < 0) + if (stat(strcat(tmp, COMPRESS_POSTFIX), &sb) < 0) return(-1); - *mtime = (int) (timenow - sb.st_mtime + 1800) / 3600; - return(0); + return( (int) (timenow - sb.st_mtime + 1800) / 3600); } /* Skip Over Blanks */ -char *sob(p) +char * +sob(p) register char *p; { while (p && *p && isspace(*p)) @@ -590,7 +646,8 @@ } /* Skip Over Non-Blanks */ -char *son(p) +char * +son(p) register char *p; { while (p && *p && !isspace(*p)) @@ -598,20 +655,20 @@ return(p); } - /* Check if string is actually a number */ - -int isnumberstr(string) +int +isnumberstr(string) char *string; { - while (*string != '\0') { + while (*string) { if (!isdigit(*string++)) return(0); } return(1); } -void domonitor(log, whom) +void +domonitor(log, whom) char *log, *whom; { struct stat sb, tsb; @@ -717,7 +774,8 @@ free(rb); } -FILE *openmail() +FILE * +openmail() { char *cmdbuf; FILE *ret; @@ -733,13 +791,15 @@ return(ret); } -void closemail(pfp) +void +closemail(pfp) FILE *pfp; { pclose(pfp); } -void child_killer(signum) +void +child_killer(signum) int signum; { int status;