Annotation of src/usr.bin/newsyslog/newsyslog.c, Revision 1.16
1.16 ! millert 1: /* $OpenBSD: newsyslog.c,v 1.15 1998/12/28 06:28:15 deraadt 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.16 ! millert 64: static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.15 1998/12/28 06:28:15 deraadt 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:
102: #define kbytes(size) (((size) + 1023) >> 10)
103:
1.10 downsj 104: #define CE_COMPACT 0x01 /* Compact the achived log files */
105: #define CE_BINARY 0x02 /* Logfile is in binary, don't add */
106: /* status messages */
107: #define CE_MONITOR 0x04 /* Monitory for changes */
1.1 deraadt 108: #define NONE -1
109:
110: struct conf_entry {
111: char *log; /* Name of the log */
112: int uid; /* Owner of log */
113: int gid; /* Group of log */
114: int numlogs; /* Number of logs to keep */
115: int size; /* Size cutoff to trigger trimming the log */
116: int hours; /* Hours between log trimming */
117: int permissions; /* File permissions on the log */
118: int flags; /* Flags (CE_COMPACT & CE_BINARY) */
1.10 downsj 119: char *whom; /* Whom to notify if logfile changes */
1.14 millert 120: char *pidfile; /* Path to file containg pid to HUP */
1.1 deraadt 121: struct conf_entry *next; /* Linked list pointer */
122: };
123:
1.11 downsj 124: extern const char *__progname;
125:
1.1 deraadt 126: int verbose = 0; /* Print out what's going on */
127: int needroot = 1; /* Root privs are necessary */
128: int noaction = 0; /* Don't do anything, just show it */
1.10 downsj 129: int monitor = 0; /* Don't do monitoring by default */
1.1 deraadt 130: char *conf = CONF; /* Configuration file to use */
131: time_t timenow;
1.16 ! millert 132: #define MIN_PID 4
1.15 deraadt 133: #define MAX_PID 99999
1.7 deraadt 134: char hostname[MAXHOSTNAMELEN]; /* hostname */
1.1 deraadt 135: char *daytime; /* timenow in human readable form */
136:
137:
1.9 downsj 138: void do_entry __P((struct conf_entry *));
139: void PRS __P((int, char **));
140: void usage __P((void));
141: struct conf_entry *parse_file __P((void));
142: char *missing_field __P((char *, char *));
1.14 millert 143: void dotrim __P((char *, int, int, int, int, int, int));
1.9 downsj 144: int log_trim __P((char *));
145: void compress_log __P((char *));
146: int sizefile __P((char *));
147: int age_old_log __P((char *));
148: char *sob __P((char *));
149: char *son __P((char *));
1.10 downsj 150: int isnumberstr __P((char *));
151: void domonitor __P((char *, char *));
152: FILE *openmail __P((void));
153: void closemail __P((FILE *));
1.16 ! millert 154: void child_killer __P((int));
1.1 deraadt 155:
1.9 downsj 156: int main(argc, argv)
1.1 deraadt 157: int argc;
158: char **argv;
159: {
160: struct conf_entry *p, *q;
1.16 ! millert 161: int status;
1.1 deraadt 162:
163: PRS(argc,argv);
1.11 downsj 164: if (needroot && getuid() && geteuid())
165: errx(1, "You must be root.");
1.1 deraadt 166: p = q = parse_file();
1.16 ! millert 167: signal(SIGCHLD, child_killer);
1.1 deraadt 168: while (p) {
169: do_entry(p);
170: p=p->next;
1.11 downsj 171: free(q);
1.1 deraadt 172: q=p;
173: }
1.16 ! millert 174:
! 175: /* Wait for children to finish, then exit */
! 176: while (waitpid(-1, &status, 0) != -1)
! 177: ;
1.1 deraadt 178: exit(0);
179: }
180:
1.9 downsj 181: void do_entry(ent)
1.1 deraadt 182: struct conf_entry *ent;
183:
184: {
1.14 millert 185: int size, modtime, pid;
186: char line[BUFSIZ];
187: FILE *f;
188:
189: /* First find the pid to HUP */
190: pid = -1;
191: if ((f = fopen(ent->pidfile,"r")) != NULL) {
192: if (fgets(line,BUFSIZ,f))
193: pid = atoi(line);
194: (void)fclose(f);
195: }
1.1 deraadt 196:
197: if (verbose) {
198: if (ent->flags & CE_COMPACT)
199: printf("%s <%dZ>: ",ent->log,ent->numlogs);
200: else
201: printf("%s <%d>: ",ent->log,ent->numlogs);
202: }
203: size = sizefile(ent->log);
204: modtime = age_old_log(ent->log);
205: if (size < 0) {
206: if (verbose)
207: printf("does not exist.\n");
208: } else {
209: if (verbose && (ent->size > 0))
210: printf("size (Kb): %d [%d] ", size, ent->size);
211: if (verbose && (ent->hours > 0))
212: printf(" age (hr): %d [%d] ", modtime, ent->hours);
1.10 downsj 213: if (monitor && ent->flags & CE_MONITOR)
214: domonitor(ent->log, ent->whom);
215: if (!monitor && ((ent->size > 0) && (size >= ent->size)) ||
1.1 deraadt 216: ((ent->hours > 0) && ((modtime >= ent->hours)
217: || (modtime < 0)))) {
218: if (verbose)
219: printf("--> trimming log....\n");
220: if (noaction && !verbose) {
221: if (ent->flags & CE_COMPACT)
222: printf("%s <%dZ>: trimming",
223: ent->log,ent->numlogs);
224: else
225: printf("%s <%d>: trimming",
226: ent->log,ent->numlogs);
227: }
228: dotrim(ent->log, ent->numlogs, ent->flags,
1.14 millert 229: ent->permissions, ent->uid, ent->gid, pid);
1.1 deraadt 230: } else {
231: if (verbose)
232: printf("--> skipping\n");
233: }
234: }
235: }
236:
1.9 downsj 237: void PRS(argc, argv)
1.1 deraadt 238: int argc;
239: char **argv;
240: {
241: int c;
242: char *p;
243:
1.12 kstailey 244: timenow = time(NULL);
1.1 deraadt 245: daytime = ctime(&timenow) + 4;
1.2 deraadt 246: daytime[15] = '\0';
1.1 deraadt 247:
248: /* Let's get our hostname */
249: (void) gethostname(hostname, sizeof(hostname));
250:
251: /* Truncate domain */
1.9 downsj 252: p = strchr(hostname, '.');
253: if (p)
1.1 deraadt 254: *p = '\0';
255:
256: optind = 1; /* Start options parsing */
1.10 downsj 257: while ((c = getopt(argc,argv,"nrvmf:t:")) != -1) {
1.1 deraadt 258: switch (c) {
259: case 'n':
260: noaction++; /* This implies needroot as off */
261: /* fall through */
262: case 'r':
263: needroot = 0;
264: break;
265: case 'v':
266: verbose++;
267: break;
268: case 'f':
269: conf = optarg;
270: break;
1.10 downsj 271: case 'm':
272: monitor++;
273: break;
1.1 deraadt 274: default:
275: usage();
276: }
277: }
1.9 downsj 278: }
1.1 deraadt 279:
1.9 downsj 280: void usage()
1.1 deraadt 281: {
1.14 millert 282: fprintf(stderr, "usage: %s [-nrvm] [-f config-file]\n", __progname);
283: exit(1);
1.1 deraadt 284: }
285:
286: /* Parse a configuration file and return a linked list of all the logs
287: * to process
288: */
289: struct conf_entry *parse_file()
290: {
291: FILE *f;
292: char line[BUFSIZ], *parse, *q;
293: char *errline, *group;
294: struct conf_entry *first = NULL;
295: struct conf_entry *working;
296: struct passwd *pass;
297: struct group *grp;
298:
299: if (strcmp(conf,"-"))
300: f = fopen(conf,"r");
301: else
302: f = stdin;
1.11 downsj 303: if (!f)
304: err(1, conf);
305:
1.1 deraadt 306: while (fgets(line,BUFSIZ,f)) {
307: if ((line[0]== '\n') || (line[0] == '#'))
308: continue;
309: errline = strdup(line);
1.11 downsj 310: if (errline == NULL)
311: err(1, "strdup");
1.1 deraadt 312: if (!first) {
313: working = (struct conf_entry *) malloc(sizeof(struct conf_entry));
1.11 downsj 314: if (working == NULL)
315: err(1, "malloc");
1.1 deraadt 316: first = working;
317: } else {
318: working->next = (struct conf_entry *) malloc(sizeof(struct conf_entry));
1.11 downsj 319: if (working->next == NULL)
320: err(1, "malloc");
1.1 deraadt 321: working = working->next;
322: }
323:
324: q = parse = missing_field(sob(line),errline);
325: *(parse = son(line)) = '\0';
326: working->log = strdup(q);
1.11 downsj 327: if (working->log == NULL)
328: err(1, "strdup");
1.1 deraadt 329:
330: q = parse = missing_field(sob(++parse),errline);
331: *(parse = son(parse)) = '\0';
332: if ((group = strchr(q, '.')) != NULL) {
333: *group++ = '\0';
334: if (*q) {
1.10 downsj 335: if (!(isnumberstr(q))) {
1.11 downsj 336: if ((pass = getpwnam(q)) == NULL)
337: errx(1, "Error in config file; unknown user: %s", q);
1.1 deraadt 338: working->uid = pass->pw_uid;
339: } else
340: working->uid = atoi(q);
341: } else
342: working->uid = NONE;
343:
344: q = group;
345: if (*q) {
1.10 downsj 346: if (!(isnumberstr(q))) {
1.11 downsj 347: if ((grp = getgrnam(q)) == NULL)
348: errx(1, "Error in config file; unknown group: %s", q);
1.1 deraadt 349: working->gid = grp->gr_gid;
350: } else
351: working->gid = atoi(q);
352: } else
353: working->gid = NONE;
354:
355: q = parse = missing_field(sob(++parse),errline);
356: *(parse = son(parse)) = '\0';
1.11 downsj 357: } else
1.1 deraadt 358: working->uid = working->gid = NONE;
359:
1.11 downsj 360: if (!sscanf(q,"%o",&working->permissions))
361: errx(1, "Error in config file; bad permissions: %s", q);
1.1 deraadt 362:
363: q = parse = missing_field(sob(++parse),errline);
364: *(parse = son(parse)) = '\0';
1.11 downsj 365: if (!sscanf(q,"%d",&working->numlogs))
366: errx(1, "Error in config file; bad number: %s", q);
1.1 deraadt 367:
368: q = parse = missing_field(sob(++parse),errline);
369: *(parse = son(parse)) = '\0';
370: if (isdigit(*q))
371: working->size = atoi(q);
372: else
373: working->size = -1;
374:
375: q = parse = missing_field(sob(++parse),errline);
376: *(parse = son(parse)) = '\0';
377: if (isdigit(*q))
378: working->hours = atoi(q);
379: else
380: working->hours = -1;
381:
382: q = parse = sob(++parse); /* Optional field */
383: *(parse = son(parse)) = '\0';
384: working->flags = 0;
385: while (q && *q && !isspace(*q)) {
386: if ((*q == 'Z') || (*q == 'z'))
387: working->flags |= CE_COMPACT;
388: else if ((*q == 'B') || (*q == 'b'))
389: working->flags |= CE_BINARY;
1.10 downsj 390: else if ((*q == 'M') || (*q == 'm'))
391: working->flags |= CE_MONITOR;
1.11 downsj 392: else
393: errx(1, "Illegal flag in config file: %c", *q);
1.1 deraadt 394: q++;
395: }
1.10 downsj 396:
397: working->whom = NULL;
398: if (working->flags & CE_MONITOR) { /* Optional field */
399: q = parse = sob(++parse);
400: *(parse = son(parse)) = '\0';
401:
402: working->whom = strdup(q);
1.11 downsj 403: if (working->log == NULL)
404: err(1, "strdup");
1.10 downsj 405: }
1.14 millert 406:
407: working->pidfile = PIDFILE;
408: q = parse = sob(++parse); /* Optional field */
409: *(parse = son(parse)) = '\0';
410: if (q && *q != '\0') {
411: working->pidfile = strdup(q);
412: if (working->pidfile == NULL)
413: err(1, "strdup");
414: }
1.1 deraadt 415:
416: free(errline);
417: }
418: if (working)
1.12 kstailey 419: working->next = NULL;
1.1 deraadt 420: (void) fclose(f);
421: return(first);
422: }
423:
1.9 downsj 424: char *missing_field(p, errline)
1.1 deraadt 425: char *p,*errline;
426: {
427: if (!p || !*p) {
1.14 millert 428: warnx("Missing field in config file line:");
1.11 downsj 429: fputs(errline, stderr);
1.1 deraadt 430: exit(1);
431: }
432: return(p);
433: }
434:
1.14 millert 435: void dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid)
1.1 deraadt 436: char *log;
437: int numdays;
438: int flags;
439: int perm;
440: int owner_uid;
441: int group_gid;
1.14 millert 442: int daemon_pid;
1.1 deraadt 443: {
1.7 deraadt 444: char file1[MAXPATHLEN], file2[MAXPATHLEN];
445: char zfile1[MAXPATHLEN], zfile2[MAXPATHLEN];
1.1 deraadt 446: int fd;
447: struct stat st;
1.6 tholo 448: int days = numdays;
1.1 deraadt 449:
450: /* Remove oldest log */
451: (void) sprintf(file1,"%s.%d",log,numdays);
452: (void) strcpy(zfile1, file1);
453: (void) strcat(zfile1, COMPRESS_POSTFIX);
454:
455: if (noaction) {
456: printf("rm -f %s\n", file1);
457: printf("rm -f %s\n", zfile1);
458: } else {
459: (void) unlink(file1);
460: (void) unlink(zfile1);
461: }
462:
463: /* Move down log files */
464: while (numdays--) {
465: (void) strcpy(file2,file1);
466: (void) sprintf(file1,"%s.%d",log,numdays);
467: (void) strcpy(zfile1, file1);
468: (void) strcpy(zfile2, file2);
469: if (lstat(file1, &st)) {
470: (void) strcat(zfile1, COMPRESS_POSTFIX);
471: (void) strcat(zfile2, COMPRESS_POSTFIX);
472: if (lstat(zfile1, &st)) continue;
473: }
474: if (noaction) {
475: printf("mv %s %s\n",zfile1,zfile2);
476: printf("chmod %o %s\n", perm, zfile2);
477: printf("chown %d.%d %s\n",
478: owner_uid, group_gid, zfile2);
479: } else {
480: (void) rename(zfile1, zfile2);
481: (void) chmod(zfile2, perm);
482: (void) chown(zfile2, owner_uid, group_gid);
483: }
484: }
485: if (!noaction && !(flags & CE_BINARY))
486: (void) log_trim(log); /* Report the trimming to the old log */
487:
1.6 tholo 488: if (days == 0) {
1.5 deraadt 489: if (noaction)
490: printf("rm %s\n",log);
491: else
492: (void) unlink(log);
493: } else {
494: if (noaction)
495: printf("mv %s to %s\n",log,file1);
496: else
497: (void) rename(log,file1);
498: }
499:
1.1 deraadt 500: if (noaction)
501: printf("Start new log...");
502: else {
503: fd = creat(log,perm);
1.11 downsj 504: if (fd < 0)
1.13 mickey 505: err(1, "can't start \'%s\' log", log);
1.11 downsj 506: if (fchown(fd, owner_uid, group_gid))
1.13 mickey 507: err(1, "can't chown \'%s\' log file", log);
1.1 deraadt 508: (void) close(fd);
509: if (!(flags & CE_BINARY))
1.11 downsj 510: if (log_trim(log)) /* Add status message */
1.13 mickey 511: err(1, "can't add status message to log \'%s\'", log);
1.1 deraadt 512: }
513: if (noaction)
514: printf("chmod %o %s...",perm,log);
515: else
516: (void) chmod(log,perm);
517: if (noaction)
1.14 millert 518: printf("kill -HUP %d\n",daemon_pid);
519: else if (daemon_pid < MIN_PID || daemon_pid > MAX_PID)
520: warnx("preposterous process number: %d", daemon_pid);
521: else if (kill(daemon_pid,SIGHUP))
522: warnx("warning - could not HUP daemon");
1.1 deraadt 523: if (flags & CE_COMPACT) {
524: if (noaction)
525: printf("Compress %s.0\n",log);
526: else
527: compress_log(log);
528: }
529: }
530:
531: /* Log the fact that the logs were turned over */
1.9 downsj 532: int log_trim(log)
1.1 deraadt 533: char *log;
534: {
535: FILE *f;
536: if ((f = fopen(log,"a")) == NULL)
537: return(-1);
538: fprintf(f,"%s %s newsyslog[%d]: logfile turned over\n",
539: daytime, hostname, getpid());
540: if (fclose(f) == EOF) {
1.11 downsj 541: err(1, "log_trim: fclose");
1.1 deraadt 542: }
543: return(0);
544: }
545:
1.16 ! millert 546: /* Fork off compress or gzip to compress the old log file */
1.9 downsj 547: void compress_log(log)
1.1 deraadt 548: char *log;
549: {
550: int pid;
1.7 deraadt 551: char tmp[MAXPATHLEN];
1.1 deraadt 552:
553: pid = fork();
554: (void) sprintf(tmp,"%s.0",log);
555: if (pid < 0) {
1.11 downsj 556: err(1, "fork");
1.1 deraadt 557: } else if (!pid) {
558: (void) execl(COMPRESS,"compress","-f",tmp,0);
1.16 ! millert 559: warn(COMPRESS);
! 560: _exit(1);
1.1 deraadt 561: }
562: }
563:
564: /* Return size in kilobytes of a file */
565: int sizefile(file)
566: char *file;
567: {
568: struct stat sb;
569:
570: if (stat(file,&sb) < 0)
571: return(-1);
572: return(kbytes(dbtob(sb.st_blocks)));
573: }
574:
575: /* Return the age of old log file (file.0) */
576: int age_old_log(file)
577: char *file;
578: {
579: struct stat sb;
1.7 deraadt 580: char tmp[MAXPATHLEN];
1.1 deraadt 581:
582: (void) strcpy(tmp,file);
583: if (stat(strcat(tmp,".0"),&sb) < 0)
584: if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0)
585: return(-1);
586: return( (int) (timenow - sb.st_mtime + 1800) / 3600);
587: }
588:
589: /* Skip Over Blanks */
590: char *sob(p)
591: register char *p;
592: {
593: while (p && *p && isspace(*p))
594: p++;
595: return(p);
596: }
597:
598: /* Skip Over Non-Blanks */
599: char *son(p)
600: register char *p;
601: {
602: while (p && *p && !isspace(*p))
603: p++;
604: return(p);
605: }
606:
607:
608: /* Check if string is actually a number */
609:
1.10 downsj 610: int isnumberstr(string)
611: char *string;
1.1 deraadt 612: {
613: while (*string != '\0') {
1.9 downsj 614: if (!isdigit(*string++))
615: return(0);
1.1 deraadt 616: }
617: return(1);
1.10 downsj 618: }
619:
620: void domonitor(log, whom)
621: char *log, *whom;
622: {
623: struct stat sb, tsb;
624: char *fname, *flog, *p, *rb = NULL;
625: FILE *fp;
626: off_t osize;
627: int rd;
628:
629: if (stat(log, &sb) < 0)
630: return;
631:
632: flog = strdup(log);
1.11 downsj 633: if (flog == NULL)
634: err(1, "strdup");
635:
1.10 downsj 636: for (p = flog; *p != '\0'; p++) {
637: if (*p == '/')
638: *p = '_';
639: }
640: fname = (char *) malloc(strlen(STATS_DIR) + strlen(flog) + 17);
1.11 downsj 641: if (fname == NULL)
642: err(1, "malloc");
643:
1.10 downsj 644: sprintf(fname, "%s/newsyslog.%s.size", STATS_DIR, flog);
645:
646: /* ..if it doesn't exist, simply record the current size. */
647: if ((sb.st_size == 0) || stat(fname, &tsb) < 0)
648: goto update;
649:
650: fp = fopen(fname, "r");
651: if (fp == NULL) {
1.11 downsj 652: warn(fname);
1.10 downsj 653: goto cleanup;
654: }
655: #ifdef QUAD_OFF_T
656: if (fscanf(fp, "%qd\n", &osize) != 1) {
657: #else
658: if (fscanf(fp, "%ld\n", &osize) != 1) {
659: #endif /* QUAD_OFF_T */
660: fclose(fp);
661: goto update;
662: }
663:
664: fclose(fp);
665:
666: /* If the file is smaller, mark the entire thing as changed. */
667: if (sb.st_size < osize)
668: osize = 0;
669:
670: /* Now see if current size is larger. */
671: if (sb.st_size > osize) {
672: rb = (char *) malloc(sb.st_size - osize);
1.11 downsj 673: if (rb == NULL)
674: err(1, "malloc");
1.10 downsj 675:
676: /* Open logfile, seek. */
677: fp = fopen(log, "r");
678: if (fp == NULL) {
1.11 downsj 679: warn(log);
1.10 downsj 680: goto cleanup;
681: }
682: fseek(fp, osize, SEEK_SET);
683: rd = fread(rb, 1, sb.st_size - osize, fp);
684: if (rd < 1) {
1.11 downsj 685: warn("fread");
1.10 downsj 686: fclose(fp);
687: goto cleanup;
688: }
689:
690: /* Send message. */
691: fclose(fp);
692:
693: fp = openmail();
694: if (fp == NULL) {
1.11 downsj 695: warn("openmail");
1.10 downsj 696: goto cleanup;
697: }
698: fprintf(fp, "To: %s\nSubject: LOGFILE NOTIFICATION: %s\n\n\n",
699: whom, log);
700: fwrite(rb, 1, rd, fp);
701: fputs("\n\n", fp);
702:
703: closemail(fp);
704: }
705: update:
706: /* Reopen for writing and update file. */
707: fp = fopen(fname, "w");
708: if (fp == NULL) {
1.11 downsj 709: warn(fname);
1.10 downsj 710: goto cleanup;
711: }
712: #ifdef QUAD_OFF_T
713: fprintf(fp, "%qd\n", sb.st_size);
714: #else
715: fprintf(fp, "%ld\n", sb.st_size);
716: #endif /* QUAD_OFF_T */
717: fclose(fp);
718:
719: cleanup:
720: free(flog);
721: free(fname);
722: if (rb != NULL)
723: free(rb);
724: }
725:
726: FILE *openmail()
727: {
728: char *cmdbuf;
729: FILE *ret;
730:
731: cmdbuf = (char *) malloc(strlen(SENDMAIL) + 3);
732: if (cmdbuf == NULL)
733: return(NULL);
734:
735: sprintf(cmdbuf, "%s -t", SENDMAIL);
736: ret = popen(cmdbuf, "w");
737:
738: free(cmdbuf);
739: return(ret);
740: }
741:
742: void closemail(pfp)
743: FILE *pfp;
744: {
745: pclose(pfp);
1.16 ! millert 746: }
! 747:
! 748: void child_killer(signum)
! 749: int signum;
! 750: {
! 751: int status;
! 752:
! 753: while (waitpid(-1, &status, WNOHANG) > 0)
! 754: ;
1.1 deraadt 755: }