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