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