Annotation of src/usr.bin/newsyslog/newsyslog.c, Revision 1.25
1.25 ! millert 1: /* $OpenBSD: newsyslog.c,v 1.24 1999/11/06 21:02:05 millert Exp $ */
1.10 downsj 2:
3: /*
4: * Copyright (c) 1997, Jason Downs. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. All advertising materials mentioning features or use of this software
15: * must display the following acknowledgement:
16: * This product includes software developed by Jason Downs for the
17: * OpenBSD system.
18: * 4. Neither the name(s) of the author(s) nor the name OpenBSD
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
23: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
26: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
1.3 deraadt 34:
1.1 deraadt 35: /*
36: * This file contains changes from the Open Software Foundation.
37: */
38:
39: /*
40:
41: Copyright 1988, 1989 by the Massachusetts Institute of Technology
42:
43: Permission to use, copy, modify, and distribute this software
44: and its documentation for any purpose and without fee is
45: hereby granted, provided that the above copyright notice
46: appear in all copies and that both that copyright notice and
47: this permission notice appear in supporting documentation,
48: and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
49: used in advertising or publicity pertaining to distribution
50: of the software without specific, written prior permission.
51: M.I.T. and the M.I.T. S.I.P.B. make no representations about
52: the suitability of this software for any purpose. It is
53: provided "as is" without express or implied warranty.
54:
55: */
56:
57: /*
58: * newsyslog - roll over selected logs at the appropriate time,
59: * keeping the a specified number of backup files around.
60: *
61: */
62:
63: #ifndef lint
1.25 ! millert 64: static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.24 1999/11/06 21:02:05 millert Exp $";
1.1 deraadt 65: #endif /* not lint */
66:
67: #ifndef CONF
68: #define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
69: #endif
70: #ifndef PIDFILE
71: #define PIDFILE "/etc/syslog.pid"
72: #endif
73: #ifndef COMPRESS
74: #define COMPRESS "/usr/ucb/compress" /* File compression program */
75: #endif
76: #ifndef COMPRESS_POSTFIX
77: #define COMPRESS_POSTFIX ".Z"
78: #endif
1.10 downsj 79: #ifndef STATS_DIR
80: #define STATS_DIR "/etc"
81: #endif
82: #ifndef SENDMAIL
83: #define SENDMAIL "/usr/lib/sendmail"
84: #endif
1.1 deraadt 85:
86: #include <stdio.h>
1.9 downsj 87: #include <sys/types.h>
88: #include <sys/time.h>
89: #include <sys/stat.h>
90: #include <sys/param.h>
91: #include <sys/wait.h>
1.1 deraadt 92: #include <stdlib.h>
93: #include <string.h>
94: #include <ctype.h>
95: #include <signal.h>
1.9 downsj 96: #include <fcntl.h>
1.1 deraadt 97: #include <pwd.h>
98: #include <grp.h>
1.9 downsj 99: #include <unistd.h>
1.11 downsj 100: #include <err.h>
1.1 deraadt 101:
1.10 downsj 102: #define CE_COMPACT 0x01 /* Compact the achived log files */
103: #define CE_BINARY 0x02 /* Logfile is in binary, don't add */
104: /* status messages */
105: #define CE_MONITOR 0x04 /* Monitory for changes */
1.1 deraadt 106: #define NONE -1
107:
108: struct conf_entry {
109: char *log; /* Name of the log */
1.25 ! millert 110: uid_t uid; /* Owner of log */
! 111: gid_t gid; /* Group of log */
1.1 deraadt 112: int numlogs; /* Number of logs to keep */
113: int size; /* Size cutoff to trigger trimming the log */
114: int hours; /* Hours between log trimming */
115: int permissions; /* File permissions on the log */
116: int flags; /* Flags (CE_COMPACT & CE_BINARY) */
1.10 downsj 117: char *whom; /* Whom to notify if logfile changes */
1.14 millert 118: char *pidfile; /* Path to file containg pid to HUP */
1.1 deraadt 119: struct conf_entry *next; /* Linked list pointer */
120: };
121:
122: int verbose = 0; /* Print out what's going on */
123: int needroot = 1; /* Root privs are necessary */
124: int noaction = 0; /* Don't do anything, just show it */
1.10 downsj 125: int monitor = 0; /* Don't do monitoring by default */
1.1 deraadt 126: char *conf = CONF; /* Configuration file to use */
127: time_t timenow;
1.16 millert 128: #define MIN_PID 4
1.7 deraadt 129: char hostname[MAXHOSTNAMELEN]; /* hostname */
1.1 deraadt 130: char *daytime; /* timenow in human readable form */
131:
132:
1.9 downsj 133: void do_entry __P((struct conf_entry *));
134: void PRS __P((int, char **));
135: void usage __P((void));
136: struct conf_entry *parse_file __P((void));
137: char *missing_field __P((char *, char *));
1.25 ! millert 138: void dotrim __P((char *, int, int, int, uid_t, gid_t, pid_t));
1.9 downsj 139: int log_trim __P((char *));
140: void compress_log __P((char *));
141: int sizefile __P((char *));
1.24 millert 142: int age_old_log __P((char *));
1.9 downsj 143: char *sob __P((char *));
144: char *son __P((char *));
1.10 downsj 145: int isnumberstr __P((char *));
146: void domonitor __P((char *, char *));
147: FILE *openmail __P((void));
148: void closemail __P((FILE *));
1.16 millert 149: void child_killer __P((int));
1.1 deraadt 150:
1.25 ! millert 151: int
! 152: main(argc, argv)
1.1 deraadt 153: int argc;
154: char **argv;
155: {
156: struct conf_entry *p, *q;
1.16 millert 157: int status;
1.1 deraadt 158:
1.25 ! millert 159: PRS(argc, argv);
1.11 downsj 160: if (needroot && getuid() && geteuid())
161: errx(1, "You must be root.");
1.1 deraadt 162: p = q = parse_file();
1.16 millert 163: signal(SIGCHLD, child_killer);
1.1 deraadt 164: while (p) {
165: do_entry(p);
1.25 ! millert 166: p = p->next;
1.11 downsj 167: free(q);
1.25 ! millert 168: q = p;
1.1 deraadt 169: }
1.16 millert 170:
171: /* Wait for children to finish, then exit */
172: while (waitpid(-1, &status, 0) != -1)
173: ;
1.1 deraadt 174: exit(0);
175: }
176:
1.25 ! millert 177: void
! 178: do_entry(ent)
1.1 deraadt 179: struct conf_entry *ent;
180:
181: {
1.25 ! millert 182: int modtime, size;
! 183: pid_t pid;
1.14 millert 184: char line[BUFSIZ];
185: FILE *f;
186:
187: /* First find the pid to HUP */
1.25 ! millert 188: pid = (pid_t)-1;
! 189: if ((f = fopen(ent->pidfile, "r")) != NULL) {
! 190: if (fgets(line, sizeof(line), f))
1.14 millert 191: pid = atoi(line);
192: (void)fclose(f);
1.25 ! millert 193: } else
! 194: warn("can't open %s", ent->pidfile);
1.1 deraadt 195:
1.19 kstailey 196: if (verbose)
197: printf("%s <%d%s>: ", ent->log, ent->numlogs,
198: (ent->flags & CE_COMPACT) ? "Z" : "");
1.1 deraadt 199: size = sizefile(ent->log);
1.24 millert 200: modtime = age_old_log(ent->log);
1.1 deraadt 201: if (size < 0) {
202: if (verbose)
203: printf("does not exist.\n");
204: } else {
205: if (verbose && (ent->size > 0))
206: printf("size (Kb): %d [%d] ", size, ent->size);
207: if (verbose && (ent->hours > 0))
208: printf(" age (hr): %d [%d] ", modtime, ent->hours);
1.10 downsj 209: if (monitor && ent->flags & CE_MONITOR)
210: domonitor(ent->log, ent->whom);
1.25 ! millert 211: if (!monitor && (((ent->size > 0) && (size >= ent->size)) ||
1.1 deraadt 212: ((ent->hours > 0) && ((modtime >= ent->hours)
1.25 ! millert 213: || (modtime < 0))))) {
1.1 deraadt 214: if (verbose)
215: printf("--> trimming log....\n");
1.19 kstailey 216: if (noaction && !verbose)
217: printf("%s <%d%s>: ", ent->log, ent->numlogs,
218: (ent->flags & CE_COMPACT) ? "Z" : "");
1.1 deraadt 219: dotrim(ent->log, ent->numlogs, ent->flags,
1.14 millert 220: ent->permissions, ent->uid, ent->gid, pid);
1.25 ! millert 221: } else if (verbose)
! 222: printf("--> skipping\n");
1.1 deraadt 223: }
224: }
225:
1.25 ! millert 226: void
! 227: PRS(argc, argv)
1.1 deraadt 228: int argc;
229: char **argv;
230: {
231: int c;
232: char *p;
233:
1.12 kstailey 234: timenow = time(NULL);
1.1 deraadt 235: daytime = ctime(&timenow) + 4;
1.2 deraadt 236: daytime[15] = '\0';
1.1 deraadt 237:
238: /* Let's get our hostname */
1.25 ! millert 239: (void)gethostname(hostname, sizeof(hostname));
1.1 deraadt 240:
241: /* Truncate domain */
1.9 downsj 242: p = strchr(hostname, '.');
243: if (p)
1.1 deraadt 244: *p = '\0';
245:
246: optind = 1; /* Start options parsing */
1.25 ! millert 247: while ((c = getopt(argc, argv, "nrvmf:t:")) != -1) {
1.1 deraadt 248: switch (c) {
249: case 'n':
250: noaction++; /* This implies needroot as off */
251: /* fall through */
252: case 'r':
253: needroot = 0;
254: break;
255: case 'v':
256: verbose++;
257: break;
258: case 'f':
259: conf = optarg;
260: break;
1.10 downsj 261: case 'm':
262: monitor++;
263: break;
1.1 deraadt 264: default:
265: usage();
266: }
267: }
1.9 downsj 268: }
1.1 deraadt 269:
1.25 ! millert 270: void
! 271: usage()
1.1 deraadt 272: {
1.25 ! millert 273: extern const char *__progname;
! 274:
! 275: (void)fprintf(stderr, "usage: %s [-nrvm] [-f config-file]\n",
! 276: __progname);
1.14 millert 277: exit(1);
1.1 deraadt 278: }
279:
280: /* Parse a configuration file and return a linked list of all the logs
281: * to process
282: */
1.25 ! millert 283: struct conf_entry *
! 284: parse_file()
1.1 deraadt 285: {
286: FILE *f;
287: char line[BUFSIZ], *parse, *q;
1.25 ! millert 288: char *errline, *group, *tmp;
1.1 deraadt 289: struct conf_entry *first = NULL;
290: struct conf_entry *working;
291: struct passwd *pass;
292: struct group *grp;
293:
1.25 ! millert 294: if (strcmp(conf, "-") == 0)
1.1 deraadt 295: f = stdin;
1.25 ! millert 296: else {
! 297: if ((f = fopen(conf, "r")) == NULL)
! 298: err(1, "can't open %s", conf);
! 299: }
1.11 downsj 300:
1.25 ! millert 301: while (fgets(line, sizeof(line), f)) {
! 302: if ((line[0] == '\n') || (line[0] == '#'))
1.1 deraadt 303: continue;
304: errline = strdup(line);
1.11 downsj 305: if (errline == NULL)
306: err(1, "strdup");
1.1 deraadt 307: if (!first) {
308: working = (struct conf_entry *) malloc(sizeof(struct conf_entry));
1.11 downsj 309: if (working == NULL)
310: err(1, "malloc");
1.1 deraadt 311: first = working;
312: } else {
313: working->next = (struct conf_entry *) malloc(sizeof(struct conf_entry));
1.11 downsj 314: if (working->next == NULL)
315: err(1, "malloc");
1.1 deraadt 316: working = working->next;
317: }
318:
1.25 ! millert 319: q = parse = missing_field(sob(line), errline);
1.1 deraadt 320: *(parse = son(line)) = '\0';
321: working->log = strdup(q);
1.11 downsj 322: if (working->log == NULL)
323: err(1, "strdup");
1.1 deraadt 324:
1.25 ! millert 325: q = parse = missing_field(sob(++parse), errline);
1.1 deraadt 326: *(parse = son(parse)) = '\0';
1.25 ! millert 327: if ((group = strchr(q, '.')) != NULL) {
! 328: *group++ = '\0';
! 329: if (*q) {
! 330: if (!(isnumberstr(q))) {
! 331: if ((pass = getpwnam(q)) == NULL)
! 332: errx(1, "Error in config file; unknown user: %s", q);
! 333: working->uid = pass->pw_uid;
! 334: } else
! 335: working->uid = atoi(q);
! 336: } else
! 337: working->uid = NONE;
! 338:
! 339: q = group;
! 340: if (*q) {
! 341: if (!(isnumberstr(q))) {
! 342: if ((grp = getgrnam(q)) == NULL)
! 343: errx(1, "Error in config file; unknown group: %s", q);
! 344: working->gid = grp->gr_gid;
! 345: } else
! 346: working->gid = atoi(q);
! 347: } else
! 348: working->gid = NONE;
! 349:
! 350: q = parse = missing_field(sob(++parse), errline);
! 351: *(parse = son(parse)) = '\0';
! 352: } else
! 353: working->uid = working->gid = NONE;
1.1 deraadt 354:
1.25 ! millert 355: if (!sscanf(q, "%o", &working->permissions))
1.11 downsj 356: errx(1, "Error in config file; bad permissions: %s", q);
1.1 deraadt 357:
1.25 ! millert 358: q = parse = missing_field(sob(++parse), errline);
1.1 deraadt 359: *(parse = son(parse)) = '\0';
1.25 ! millert 360: if (!sscanf(q, "%d", &working->numlogs) || working->numlogs < 0)
1.11 downsj 361: errx(1, "Error in config file; bad number: %s", q);
1.1 deraadt 362:
1.25 ! millert 363: q = parse = missing_field(sob(++parse), errline);
1.1 deraadt 364: *(parse = son(parse)) = '\0';
365: if (isdigit(*q))
366: working->size = atoi(q);
367: else
368: working->size = -1;
369:
1.25 ! millert 370: q = parse = missing_field(sob(++parse), errline);
1.1 deraadt 371: *(parse = son(parse)) = '\0';
372: if (isdigit(*q))
373: working->hours = atoi(q);
374: else
375: working->hours = -1;
376:
377: q = parse = sob(++parse); /* Optional field */
378: *(parse = son(parse)) = '\0';
379: working->flags = 0;
380: while (q && *q && !isspace(*q)) {
381: if ((*q == 'Z') || (*q == 'z'))
382: working->flags |= CE_COMPACT;
383: else if ((*q == 'B') || (*q == 'b'))
384: working->flags |= CE_BINARY;
1.10 downsj 385: else if ((*q == 'M') || (*q == 'm'))
386: working->flags |= CE_MONITOR;
1.11 downsj 387: else
388: errx(1, "Illegal flag in config file: %c", *q);
1.1 deraadt 389: q++;
390: }
1.10 downsj 391:
392: working->whom = NULL;
393: if (working->flags & CE_MONITOR) { /* Optional field */
394: q = parse = sob(++parse);
395: *(parse = son(parse)) = '\0';
396:
397: working->whom = strdup(q);
1.11 downsj 398: if (working->log == NULL)
399: err(1, "strdup");
1.10 downsj 400: }
1.14 millert 401:
402: working->pidfile = PIDFILE;
403: q = parse = sob(++parse); /* Optional field */
404: *(parse = son(parse)) = '\0';
405: if (q && *q != '\0') {
1.25 ! millert 406: if (strlen(q) >= MAXPATHLEN)
! 407: errx(1, "%s: pathname too long", q);
1.14 millert 408: working->pidfile = strdup(q);
409: if (working->pidfile == NULL)
410: err(1, "strdup");
411: }
1.25 ! millert 412:
! 413: /* Make sure we can't oflow MAXPATHLEN */
! 414: if (asprintf(&tmp, "%s.%d%s", working->log, working->numlogs,
! 415: COMPRESS_POSTFIX) >= MAXPATHLEN)
! 416: errx(1, "%s: pathname too long", working->log);
1.1 deraadt 417:
1.25 ! millert 418: free(tmp);
1.1 deraadt 419: free(errline);
420: }
421: if (working)
1.12 kstailey 422: working->next = NULL;
1.25 ! millert 423: (void)fclose(f);
1.1 deraadt 424: return(first);
425: }
426:
1.25 ! millert 427: char *
! 428: missing_field(p, errline)
! 429: char *p;
! 430: char *errline;
1.1 deraadt 431: {
432: if (!p || !*p) {
1.14 millert 433: warnx("Missing field in config file line:");
1.11 downsj 434: fputs(errline, stderr);
1.1 deraadt 435: exit(1);
436: }
437: return(p);
438: }
439:
1.25 ! millert 440: void
! 441: dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid)
1.1 deraadt 442: char *log;
443: int numdays;
444: int flags;
445: int perm;
1.25 ! millert 446: uid_t owner_uid;
! 447: gid_t group_gid;
! 448: pid_t daemon_pid;
1.1 deraadt 449: {
1.7 deraadt 450: char file1[MAXPATHLEN], file2[MAXPATHLEN];
451: char zfile1[MAXPATHLEN], zfile2[MAXPATHLEN];
1.1 deraadt 452: int fd;
453: struct stat st;
1.6 tholo 454: int days = numdays;
1.1 deraadt 455:
1.25 ! millert 456: /* Remove oldest log (may not exist) */
! 457: (void)sprintf(file1, "%s.%d", log, numdays);
! 458: (void)strcpy(zfile1, file1);
! 459: (void)strcat(zfile1, COMPRESS_POSTFIX);
1.1 deraadt 460: if (noaction) {
461: printf("rm -f %s\n", file1);
462: printf("rm -f %s\n", zfile1);
463: } else {
1.25 ! millert 464: (void)unlink(file1);
! 465: (void)unlink(zfile1);
1.1 deraadt 466: }
467:
468: /* Move down log files */
469: while (numdays--) {
1.25 ! millert 470: (void)strcpy(file2, file1);
! 471: (void)sprintf(file1, "%s.%d", log, numdays);
! 472: (void)strcpy(zfile1, file1);
! 473: (void)strcpy(zfile2, file2);
1.1 deraadt 474: if (lstat(file1, &st)) {
1.25 ! millert 475: (void)strcat(zfile1, COMPRESS_POSTFIX);
! 476: (void)strcat(zfile2, COMPRESS_POSTFIX);
! 477: if (lstat(zfile1, &st))
! 478: continue;
1.1 deraadt 479: }
480: if (noaction) {
1.25 ! millert 481: printf("mv %s %s\n", zfile1, zfile2);
1.1 deraadt 482: printf("chmod %o %s\n", perm, zfile2);
1.25 ! millert 483: printf("chown %d:%d %s\n",
1.1 deraadt 484: owner_uid, group_gid, zfile2);
485: } else {
1.25 ! millert 486: if (rename(zfile1, zfile2))
! 487: warn("can't mv %s to %s", zfile1, zfile2);
! 488: if (chmod(zfile2, perm))
! 489: warn("can't chmod %s", zfile2);
! 490: if (chown(zfile2, owner_uid, group_gid))
! 491: warn("can't chown %s", zfile2);
1.1 deraadt 492: }
493: }
494: if (!noaction && !(flags & CE_BINARY))
1.25 ! millert 495: (void)log_trim(log); /* Report the trimming to the old log */
1.1 deraadt 496:
1.6 tholo 497: if (days == 0) {
1.5 deraadt 498: if (noaction)
1.25 ! millert 499: printf("rm %s\n", log);
! 500: else if (unlink(log))
! 501: warn("can't rm %s", log);
1.5 deraadt 502: } else {
503: if (noaction)
1.25 ! millert 504: printf("mv %s to %s\n", log, file1);
! 505: else if (rename(log, file1))
! 506: warn("can't to mv %s to %s", log, file1);
1.5 deraadt 507: }
508:
1.22 millert 509: if (noaction) {
1.1 deraadt 510: printf("Start new log...");
1.22 millert 511: } else {
512: fd = open(log, O_WRONLY|O_TRUNC|O_CREAT, perm);
1.11 downsj 513: if (fd < 0)
1.25 ! millert 514: err(1, "can't start '%s' log", log);
1.11 downsj 515: if (fchown(fd, owner_uid, group_gid))
1.25 ! millert 516: err(1, "can't chown '%s' log file", log);
1.22 millert 517: if (fchmod(fd, perm))
1.25 ! millert 518: err(1, "can't chmod '%s' log file", log);
! 519: (void)close(fd);
! 520: /* Add status message */
! 521: if (!(flags & CE_BINARY) && log_trim(log))
! 522: err(1, "can't add status message to log '%s'", log);
1.1 deraadt 523: }
524: if (noaction)
1.25 ! millert 525: (void)printf("kill -HUP %d\n", daemon_pid);
! 526: else if (daemon_pid != (pid_t)-1) {
! 527: if (daemon_pid < MIN_PID)
! 528: warnx("preposterous process number: %d", daemon_pid);
! 529: else if (kill(daemon_pid, SIGHUP))
! 530: warnx("warning - could not HUP daemon");
! 531: }
1.17 deraadt 532: if (flags & CE_COMPACT) {
533: if (noaction)
1.25 ! millert 534: (void)printf("Compress %s.0\n", log);
1.17 deraadt 535: else
536: compress_log(log);
537: }
1.1 deraadt 538: }
539:
540: /* Log the fact that the logs were turned over */
1.25 ! millert 541: int
! 542: log_trim(log)
1.17 deraadt 543: char *log;
1.1 deraadt 544: {
545: FILE *f;
1.25 ! millert 546:
! 547: if ((f = fopen(log, "a")) == NULL)
1.1 deraadt 548: return(-1);
1.25 ! millert 549: (void)fprintf(f, "%s %s newsyslog[%d]: logfile turned over\n",
! 550: daytime, hostname, getpid());
1.24 millert 551: if (fclose(f) == EOF)
1.11 downsj 552: err(1, "log_trim: fclose");
1.1 deraadt 553: return(0);
554: }
555:
1.16 millert 556: /* Fork off compress or gzip to compress the old log file */
1.25 ! millert 557: void
! 558: compress_log(log)
1.1 deraadt 559: char *log;
560: {
1.25 ! millert 561: pid_t pid;
1.7 deraadt 562: char tmp[MAXPATHLEN];
1.1 deraadt 563:
564: pid = fork();
1.25 ! millert 565: (void)sprintf(tmp, "%s.0", log);
1.1 deraadt 566: if (pid < 0) {
1.11 downsj 567: err(1, "fork");
1.1 deraadt 568: } else if (!pid) {
1.25 ! millert 569: (void)execl(COMPRESS, "compress", "-f", tmp, 0);
1.16 millert 570: warn(COMPRESS);
571: _exit(1);
1.1 deraadt 572: }
573: }
574:
575: /* Return size in kilobytes of a file */
1.25 ! millert 576: int
! 577: sizefile(file)
1.1 deraadt 578: char *file;
579: {
580: struct stat sb;
581:
1.25 ! millert 582: if (stat(file, &sb) < 0)
1.1 deraadt 583: return(-1);
1.25 ! millert 584: return(sb.st_blocks / (1024.0 / DEV_BSIZE));
1.1 deraadt 585: }
586:
1.25 ! millert 587: /* Return the age (in hours) of old log file (file.0), or -1 if none */
! 588: int
! 589: age_old_log(file)
1.1 deraadt 590: char *file;
591: {
592: struct stat sb;
1.7 deraadt 593: char tmp[MAXPATHLEN];
1.1 deraadt 594:
1.25 ! millert 595: (void)strcpy(tmp, file);
! 596: if (stat(strcat(tmp, ".0"), &sb) < 0)
! 597: if (stat(strcat(tmp, COMPRESS_POSTFIX), &sb) < 0)
1.1 deraadt 598: return(-1);
1.24 millert 599: return( (int) (timenow - sb.st_mtime + 1800) / 3600);
1.1 deraadt 600: }
601:
602: /* Skip Over Blanks */
1.25 ! millert 603: char *
! 604: sob(p)
1.1 deraadt 605: register char *p;
606: {
607: while (p && *p && isspace(*p))
608: p++;
609: return(p);
610: }
611:
612: /* Skip Over Non-Blanks */
1.25 ! millert 613: char *
! 614: son(p)
1.1 deraadt 615: register char *p;
616: {
617: while (p && *p && !isspace(*p))
618: p++;
619: return(p);
620: }
621:
622: /* Check if string is actually a number */
1.25 ! millert 623: int
! 624: isnumberstr(string)
1.10 downsj 625: char *string;
1.1 deraadt 626: {
1.25 ! millert 627: while (*string) {
1.9 downsj 628: if (!isdigit(*string++))
629: return(0);
1.1 deraadt 630: }
631: return(1);
1.10 downsj 632: }
633:
1.25 ! millert 634: void
! 635: domonitor(log, whom)
1.10 downsj 636: char *log, *whom;
637: {
638: struct stat sb, tsb;
639: char *fname, *flog, *p, *rb = NULL;
640: FILE *fp;
641: off_t osize;
642: int rd;
643:
644: if (stat(log, &sb) < 0)
645: return;
646:
647: flog = strdup(log);
1.11 downsj 648: if (flog == NULL)
649: err(1, "strdup");
650:
1.10 downsj 651: for (p = flog; *p != '\0'; p++) {
652: if (*p == '/')
653: *p = '_';
654: }
1.20 fgsch 655: fname = (char *) malloc(sizeof(STATS_DIR) + strlen(flog) + 16);
1.11 downsj 656: if (fname == NULL)
657: err(1, "malloc");
658:
1.10 downsj 659: sprintf(fname, "%s/newsyslog.%s.size", STATS_DIR, flog);
660:
661: /* ..if it doesn't exist, simply record the current size. */
662: if ((sb.st_size == 0) || stat(fname, &tsb) < 0)
663: goto update;
664:
665: fp = fopen(fname, "r");
666: if (fp == NULL) {
1.11 downsj 667: warn(fname);
1.10 downsj 668: goto cleanup;
669: }
670: #ifdef QUAD_OFF_T
671: if (fscanf(fp, "%qd\n", &osize) != 1) {
672: #else
673: if (fscanf(fp, "%ld\n", &osize) != 1) {
674: #endif /* QUAD_OFF_T */
675: fclose(fp);
676: goto update;
677: }
678:
679: fclose(fp);
680:
681: /* If the file is smaller, mark the entire thing as changed. */
682: if (sb.st_size < osize)
683: osize = 0;
684:
685: /* Now see if current size is larger. */
686: if (sb.st_size > osize) {
687: rb = (char *) malloc(sb.st_size - osize);
1.11 downsj 688: if (rb == NULL)
689: err(1, "malloc");
1.10 downsj 690:
691: /* Open logfile, seek. */
692: fp = fopen(log, "r");
693: if (fp == NULL) {
1.11 downsj 694: warn(log);
1.10 downsj 695: goto cleanup;
696: }
697: fseek(fp, osize, SEEK_SET);
698: rd = fread(rb, 1, sb.st_size - osize, fp);
699: if (rd < 1) {
1.11 downsj 700: warn("fread");
1.10 downsj 701: fclose(fp);
702: goto cleanup;
703: }
704:
705: /* Send message. */
706: fclose(fp);
707:
708: fp = openmail();
709: if (fp == NULL) {
1.11 downsj 710: warn("openmail");
1.10 downsj 711: goto cleanup;
712: }
713: fprintf(fp, "To: %s\nSubject: LOGFILE NOTIFICATION: %s\n\n\n",
714: whom, log);
715: fwrite(rb, 1, rd, fp);
716: fputs("\n\n", fp);
717:
718: closemail(fp);
719: }
720: update:
721: /* Reopen for writing and update file. */
722: fp = fopen(fname, "w");
723: if (fp == NULL) {
1.11 downsj 724: warn(fname);
1.10 downsj 725: goto cleanup;
726: }
727: #ifdef QUAD_OFF_T
728: fprintf(fp, "%qd\n", sb.st_size);
729: #else
730: fprintf(fp, "%ld\n", sb.st_size);
731: #endif /* QUAD_OFF_T */
732: fclose(fp);
733:
734: cleanup:
735: free(flog);
736: free(fname);
737: if (rb != NULL)
738: free(rb);
739: }
740:
1.25 ! millert 741: FILE *
! 742: openmail()
1.10 downsj 743: {
744: char *cmdbuf;
745: FILE *ret;
746:
1.20 fgsch 747: cmdbuf = (char *) malloc(sizeof(SENDMAIL) + 3);
1.10 downsj 748: if (cmdbuf == NULL)
749: return(NULL);
750:
751: sprintf(cmdbuf, "%s -t", SENDMAIL);
752: ret = popen(cmdbuf, "w");
753:
754: free(cmdbuf);
755: return(ret);
756: }
757:
1.25 ! millert 758: void
! 759: closemail(pfp)
1.10 downsj 760: FILE *pfp;
761: {
762: pclose(pfp);
1.16 millert 763: }
764:
1.25 ! millert 765: void
! 766: child_killer(signum)
1.16 millert 767: int signum;
768: {
769: int status;
770:
771: while (waitpid(-1, &status, WNOHANG) > 0)
772: ;
1.1 deraadt 773: }