=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/newsyslog/newsyslog.c,v retrieving revision 1.24 retrieving revision 1.25 diff -c -r1.24 -r1.25 *** src/usr.bin/newsyslog/newsyslog.c 1999/11/06 21:02:05 1.24 --- src/usr.bin/newsyslog/newsyslog.c 1999/11/07 03:59:12 1.25 *************** *** 1,4 **** ! /* $OpenBSD: newsyslog.c,v 1.24 1999/11/06 21:02:05 millert Exp $ */ /* * Copyright (c) 1997, Jason Downs. All rights reserved. --- 1,4 ---- ! /* $OpenBSD: newsyslog.c,v 1.25 1999/11/07 03:59:12 millert Exp $ */ /* * Copyright (c) 1997, Jason Downs. All rights reserved. *************** *** 61,67 **** */ #ifndef lint ! static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.24 1999/11/06 21:02:05 millert Exp $"; #endif /* not lint */ #ifndef CONF --- 61,67 ---- */ #ifndef lint ! static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.25 1999/11/07 03:59:12 millert Exp $"; #endif /* not lint */ #ifndef CONF *************** *** 99,106 **** #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 */ /* status messages */ --- 99,104 ---- *************** *** 109,116 **** struct conf_entry { char *log; /* Name of the log */ ! int uid; /* Owner of log */ ! int 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 */ --- 107,114 ---- struct conf_entry { char *log; /* Name of the 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,128 **** 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 */ --- 119,124 ---- *************** *** 139,145 **** 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)); int log_trim __P((char *)); void compress_log __P((char *)); int sizefile __P((char *)); --- 135,141 ---- void usage __P((void)); struct conf_entry *parse_file __P((void)); char *missing_field __P((char *, char *)); ! void dotrim __P((char *, int, int, int, uid_t, gid_t, pid_t)); int log_trim __P((char *)); void compress_log __P((char *)); int sizefile __P((char *)); *************** *** 152,174 **** void closemail __P((FILE *)); void child_killer __P((int)); ! int main(argc, argv) int argc; char **argv; { struct conf_entry *p, *q; int status; ! PRS(argc,argv); if (needroot && getuid() && geteuid()) errx(1, "You must be root."); p = q = parse_file(); signal(SIGCHLD, child_killer); while (p) { do_entry(p); ! p=p->next; free(q); ! q=p; } /* Wait for children to finish, then exit */ --- 148,171 ---- void closemail __P((FILE *)); void child_killer __P((int)); ! int ! main(argc, argv) int argc; char **argv; { struct conf_entry *p, *q; int status; ! PRS(argc, argv); if (needroot && getuid() && geteuid()) errx(1, "You must be root."); p = q = parse_file(); signal(SIGCHLD, child_killer); while (p) { do_entry(p); ! p = p->next; free(q); ! q = p; } /* Wait for children to finish, then exit */ *************** *** 177,197 **** exit(0); } ! void do_entry(ent) struct conf_entry *ent; { ! int size, modtime, pid; char line[BUFSIZ]; FILE *f; /* 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, --- 174,197 ---- exit(0); } ! void ! do_entry(ent) struct conf_entry *ent; { ! int modtime, size; ! pid_t pid; char line[BUFSIZ]; FILE *f; /* First find the pid to HUP */ ! pid = (pid_t)-1; ! if ((f = fopen(ent->pidfile, "r")) != NULL) { ! if (fgets(line, sizeof(line), f)) pid = atoi(line); (void)fclose(f); ! } else ! warn("can't open %s", ent->pidfile); if (verbose) printf("%s <%d%s>: ", ent->log, ent->numlogs, *************** *** 208,216 **** 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)) || ((ent->hours > 0) && ((modtime >= ent->hours) ! || (modtime < 0)))) { if (verbose) printf("--> trimming log....\n"); if (noaction && !verbose) --- 208,216 ---- 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)) || ((ent->hours > 0) && ((modtime >= ent->hours) ! || (modtime < 0))))) { if (verbose) printf("--> trimming log....\n"); if (noaction && !verbose) *************** *** 218,231 **** (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"); ! } } } ! void PRS(argc, argv) int argc; char **argv; { --- 218,230 ---- (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"); } } ! void ! PRS(argc, argv) int argc; char **argv; { *************** *** 237,243 **** daytime[15] = '\0'; /* Let's get our hostname */ ! (void) gethostname(hostname, sizeof(hostname)); /* Truncate domain */ p = strchr(hostname, '.'); --- 236,242 ---- daytime[15] = '\0'; /* Let's get our hostname */ ! (void)gethostname(hostname, sizeof(hostname)); /* Truncate domain */ p = strchr(hostname, '.'); *************** *** 245,251 **** *p = '\0'; optind = 1; /* Start options parsing */ ! while ((c = getopt(argc,argv,"nrvmf:t:")) != -1) { switch (c) { case 'n': noaction++; /* This implies needroot as off */ --- 244,250 ---- *p = '\0'; optind = 1; /* Start options parsing */ ! while ((c = getopt(argc, argv, "nrvmf:t:")) != -1) { switch (c) { case 'n': noaction++; /* This implies needroot as off */ *************** *** 268,301 **** } } ! void usage() { ! 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() { FILE *f; char line[BUFSIZ], *parse, *q; ! char *errline, *group; struct conf_entry *first = NULL; struct conf_entry *working; struct passwd *pass; struct group *grp; ! if (strcmp(conf,"-")) ! f = fopen(conf,"r"); ! else f = stdin; ! if (!f) ! err(1, conf); ! while (fgets(line,BUFSIZ,f)) { ! if ((line[0]== '\n') || (line[0] == '#')) continue; errline = strdup(line); if (errline == NULL) --- 267,305 ---- } } ! void ! usage() { ! 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() { FILE *f; char line[BUFSIZ], *parse, *q; ! char *errline, *group, *tmp; struct conf_entry *first = NULL; struct conf_entry *working; struct passwd *pass; struct group *grp; ! if (strcmp(conf, "-") == 0) f = stdin; ! else { ! if ((f = fopen(conf, "r")) == NULL) ! err(1, "can't open %s", conf); ! } ! while (fgets(line, sizeof(line), f)) { ! if ((line[0] == '\n') || (line[0] == '#')) continue; errline = strdup(line); if (errline == NULL) *************** *** 312,369 **** working = working->next; } ! 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); *(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 (!sscanf(q,"%o",&working->permissions)) errx(1, "Error in config file; bad permissions: %s", q); ! q = parse = missing_field(sob(++parse),errline); *(parse = son(parse)) = '\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); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->size = atoi(q); else working->size = -1; ! q = parse = missing_field(sob(++parse),errline); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->hours = atoi(q); --- 316,373 ---- working = working->next; } ! 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); *(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 (!sscanf(q, "%o", &working->permissions)) errx(1, "Error in config file; bad permissions: %s", q); ! q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\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); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->size = atoi(q); else working->size = -1; ! q = parse = missing_field(sob(++parse), errline); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->hours = atoi(q); *************** *** 399,419 **** q = parse = sob(++parse); /* Optional field */ *(parse = son(parse)) = '\0'; if (q && *q != '\0') { working->pidfile = strdup(q); if (working->pidfile == NULL) err(1, "strdup"); } free(errline); } if (working) working->next = NULL; ! (void) fclose(f); return(first); } ! char *missing_field(p, errline) ! char *p,*errline; { if (!p || !*p) { warnx("Missing field in config file line:"); --- 403,433 ---- 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); return(first); } ! char * ! missing_field(p, errline) ! char *p; ! char *errline; { if (!p || !*p) { warnx("Missing field in config file line:"); *************** *** 423,436 **** return(p); } ! void dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid) char *log; int numdays; int flags; int perm; ! int owner_uid; ! int group_gid; ! int daemon_pid; { char file1[MAXPATHLEN], file2[MAXPATHLEN]; char zfile1[MAXPATHLEN], zfile2[MAXPATHLEN]; --- 437,451 ---- return(p); } ! void ! dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid) char *log; int numdays; int flags; int perm; ! uid_t owner_uid; ! gid_t group_gid; ! pid_t daemon_pid; { char file1[MAXPATHLEN], file2[MAXPATHLEN]; char zfile1[MAXPATHLEN], zfile2[MAXPATHLEN]; *************** *** 438,491 **** 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); ! if (noaction) { printf("rm -f %s\n", file1); printf("rm -f %s\n", zfile1); } else { ! (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); if (lstat(file1, &st)) { ! (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("chmod %o %s\n", perm, zfile2); ! 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 (!noaction && !(flags & CE_BINARY)) ! (void) log_trim(log); /* Report the trimming to the old log */ if (days == 0) { if (noaction) ! printf("rm %s\n",log); ! else ! (void) unlink(log); } else { if (noaction) ! printf("mv %s to %s\n",log,file1); ! else ! (void) rename(log,file1); } if (noaction) { --- 453,509 ---- struct stat st; int days = numdays; ! /* 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); } else { ! (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); if (lstat(file1, &st)) { ! (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("chmod %o %s\n", perm, zfile2); ! printf("chown %d:%d %s\n", owner_uid, group_gid, zfile2); } else { ! 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 */ if (days == 0) { if (noaction) ! 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 if (rename(log, file1)) ! warn("can't to mv %s to %s", log, file1); } if (noaction) { *************** *** 493,581 **** } else { fd = open(log, O_WRONLY|O_TRUNC|O_CREAT, 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); if (fchmod(fd, perm)) ! err(1, "can't chmod \'%s\' log file", log, perm); ! (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("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); } } /* Log the fact that the logs were turned over */ ! int log_trim(log) char *log; { FILE *f; ! 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) err(1, "log_trim: fclose"); return(0); } /* Fork off compress or gzip to compress the old log file */ ! void compress_log(log) char *log; { ! int pid; char tmp[MAXPATHLEN]; pid = fork(); ! (void) sprintf(tmp,"%s.0",log); if (pid < 0) { err(1, "fork"); } else if (!pid) { ! (void) execl(COMPRESS,"compress","-f",tmp,0); warn(COMPRESS); _exit(1); } } /* Return size in kilobytes of a file */ ! int sizefile(file) char *file; { struct stat sb; ! if (stat(file,&sb) < 0) return(-1); ! return(kbytes(dbtob(sb.st_blocks))); } ! /* Return the age of old log file (file.0) or -1 if no old log file */ ! int age_old_log(file) char *file; { 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) return(-1); return( (int) (timenow - sb.st_mtime + 1800) / 3600); } /* Skip Over Blanks */ ! char *sob(p) register char *p; { while (p && *p && isspace(*p)) --- 511,607 ---- } else { fd = open(log, O_WRONLY|O_TRUNC|O_CREAT, 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); if (fchmod(fd, perm)) ! err(1, "can't chmod '%s' log file", log); ! (void)close(fd); ! /* Add status message */ ! if (!(flags & CE_BINARY) && log_trim(log)) ! err(1, "can't add status message to log '%s'", log); } if (noaction) ! (void)printf("kill -HUP %d\n", daemon_pid); ! else if (daemon_pid != (pid_t)-1) { ! 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) ! (void)printf("Compress %s.0\n", log); else compress_log(log); } } /* Log the fact that the logs were turned over */ ! int ! log_trim(log) char *log; { FILE *f; ! ! if ((f = fopen(log, "a")) == NULL) return(-1); ! (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) char *log; { ! pid_t pid; char tmp[MAXPATHLEN]; pid = fork(); ! (void)sprintf(tmp, "%s.0", log); if (pid < 0) { err(1, "fork"); } else if (!pid) { ! (void)execl(COMPRESS, "compress", "-f", tmp, 0); warn(COMPRESS); _exit(1); } } /* Return size in kilobytes of a file */ ! int ! sizefile(file) char *file; { struct stat sb; ! if (stat(file, &sb) < 0) return(-1); ! return(sb.st_blocks / (1024.0 / DEV_BSIZE)); } ! /* Return the age (in hours) of old log file (file.0), or -1 if none */ ! int ! age_old_log(file) char *file; { 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) return(-1); return( (int) (timenow - sb.st_mtime + 1800) / 3600); } /* Skip Over Blanks */ ! char * ! sob(p) register char *p; { while (p && *p && isspace(*p)) *************** *** 584,590 **** } /* Skip Over Non-Blanks */ ! char *son(p) register char *p; { while (p && *p && !isspace(*p)) --- 610,617 ---- } /* Skip Over Non-Blanks */ ! char * ! son(p) register char *p; { while (p && *p && !isspace(*p)) *************** *** 592,611 **** return(p); } - /* Check if string is actually a number */ ! ! int isnumberstr(string) char *string; { ! while (*string != '\0') { if (!isdigit(*string++)) return(0); } return(1); } ! void domonitor(log, whom) char *log, *whom; { struct stat sb, tsb; --- 619,638 ---- return(p); } /* Check if string is actually a number */ ! int ! isnumberstr(string) char *string; { ! while (*string) { if (!isdigit(*string++)) return(0); } return(1); } ! void ! domonitor(log, whom) char *log, *whom; { struct stat sb, tsb; *************** *** 711,717 **** free(rb); } ! FILE *openmail() { char *cmdbuf; FILE *ret; --- 738,745 ---- free(rb); } ! FILE * ! openmail() { char *cmdbuf; FILE *ret; *************** *** 727,739 **** return(ret); } ! void closemail(pfp) FILE *pfp; { pclose(pfp); } ! void child_killer(signum) int signum; { int status; --- 755,769 ---- return(ret); } ! void ! closemail(pfp) FILE *pfp; { pclose(pfp); } ! void ! child_killer(signum) int signum; { int status;