[BACK]Return to newsyslog.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / newsyslog

Annotation of src/usr.bin/newsyslog/newsyslog.c, Revision 1.21

1.21    ! millert     1: /*     $OpenBSD: newsyslog.c,v 1.20 1999/08/27 08:49:29 fgsch 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.21    ! millert    64: static char rcsid[] = "$OpenBSD: newsyslog.c,v 1.20 1999/08/27 08:49:29 fgsch 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.7       deraadt   133: char    hostname[MAXHOSTNAMELEN]; /* hostname */
1.1       deraadt   134: char    *daytime;               /* timenow in human readable form */
                    135:
                    136:
1.9       downsj    137: void do_entry __P((struct conf_entry *));
                    138: void PRS __P((int, char **));
                    139: void usage __P((void));
                    140: struct conf_entry *parse_file __P((void));
                    141: char *missing_field __P((char *, char *));
1.14      millert   142: void dotrim __P((char *, int, int, int, int, int, int));
1.9       downsj    143: int log_trim __P((char *));
                    144: void compress_log __P((char *));
                    145: int sizefile __P((char *));
1.21    ! millert   146: int age_old_log __P((char *, int *));
1.9       downsj    147: char *sob __P((char *));
                    148: char *son __P((char *));
1.10      downsj    149: int isnumberstr __P((char *));
                    150: void domonitor __P((char *, char *));
                    151: FILE *openmail __P((void));
                    152: void closemail __P((FILE *));
1.16      millert   153: void child_killer __P((int));
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;
1.16      millert   160:        int status;
1.1       deraadt   161:
                    162:         PRS(argc,argv);
1.11      downsj    163:         if (needroot && getuid() && geteuid())
                    164:                errx(1, "You must be root.");
1.1       deraadt   165:         p = q = parse_file();
1.16      millert   166:        signal(SIGCHLD, child_killer);
1.1       deraadt   167:         while (p) {
                    168:                 do_entry(p);
                    169:                 p=p->next;
1.11      downsj    170:                 free(q);
1.1       deraadt   171:                 q=p;
                    172:         }
1.16      millert   173:
                    174:        /* Wait for children to finish, then exit */
                    175:        while (waitpid(-1, &status, 0) != -1)
                    176:                ;
1.1       deraadt   177:         exit(0);
                    178: }
                    179:
1.9       downsj    180: void do_entry(ent)
1.1       deraadt   181:         struct conf_entry       *ent;
                    182:
                    183: {
1.14      millert   184:         int     size, modtime, pid;
                    185:         char    line[BUFSIZ];
                    186:         FILE    *f;
                    187:
                    188:         /* First find the pid to HUP */
                    189:         pid = -1;
                    190:         if ((f = fopen(ent->pidfile,"r")) != NULL) {
                    191:                if (fgets(line,BUFSIZ,f))
                    192:                        pid = atoi(line);
                    193:                (void)fclose(f);
                    194:        }
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.21    ! millert   200:        if (age_old_log(ent->log, &modtime) == -1)
        !           201:                modtime = 0;
1.1       deraadt   202:         if (size < 0) {
                    203:                 if (verbose)
                    204:                         printf("does not exist.\n");
                    205:         } else {
                    206:                 if (verbose && (ent->size > 0))
                    207:                         printf("size (Kb): %d [%d] ", size, ent->size);
                    208:                 if (verbose && (ent->hours > 0))
                    209:                         printf(" age (hr): %d [%d] ", modtime, ent->hours);
1.10      downsj    210:                if (monitor && ent->flags & CE_MONITOR)
                    211:                        domonitor(ent->log, ent->whom);
                    212:                 if (!monitor && ((ent->size > 0) && (size >= ent->size)) ||
1.1       deraadt   213:                     ((ent->hours > 0) && ((modtime >= ent->hours)
                    214:                                         || (modtime < 0)))) {
                    215:                         if (verbose)
                    216:                                 printf("--> trimming log....\n");
1.19      kstailey  217:                        if (noaction && !verbose)
                    218:                                printf("%s <%d%s>: ", ent->log, ent->numlogs,
                    219:                                        (ent->flags & CE_COMPACT) ? "Z" : "");
1.1       deraadt   220:                         dotrim(ent->log, ent->numlogs, ent->flags,
1.14      millert   221:                                ent->permissions, ent->uid, ent->gid, pid);
1.1       deraadt   222:                 } else {
                    223:                         if (verbose)
                    224:                                 printf("--> skipping\n");
                    225:                 }
                    226:         }
                    227: }
                    228:
1.9       downsj    229: void PRS(argc, argv)
1.1       deraadt   230:         int argc;
                    231:         char **argv;
                    232: {
                    233:         int     c;
                    234:        char    *p;
                    235:
1.12      kstailey  236:         timenow = time(NULL);
1.1       deraadt   237:         daytime = ctime(&timenow) + 4;
1.2       deraadt   238:         daytime[15] = '\0';
1.1       deraadt   239:
                    240:         /* Let's get our hostname */
                    241:         (void) gethostname(hostname, sizeof(hostname));
                    242:
                    243:        /* Truncate domain */
1.9       downsj    244:        p = strchr(hostname, '.');
                    245:        if (p)
1.1       deraadt   246:                *p = '\0';
                    247:
                    248:         optind = 1;             /* Start options parsing */
1.10      downsj    249:         while ((c = getopt(argc,argv,"nrvmf:t:")) != -1) {
1.1       deraadt   250:                 switch (c) {
                    251:                 case 'n':
                    252:                         noaction++; /* This implies needroot as off */
                    253:                         /* fall through */
                    254:                 case 'r':
                    255:                         needroot = 0;
                    256:                         break;
                    257:                 case 'v':
                    258:                         verbose++;
                    259:                         break;
                    260:                 case 'f':
                    261:                         conf = optarg;
                    262:                         break;
1.10      downsj    263:                case 'm':
                    264:                        monitor++;
                    265:                        break;
1.1       deraadt   266:                 default:
                    267:                         usage();
                    268:                 }
                    269:         }
1.9       downsj    270: }
1.1       deraadt   271:
1.9       downsj    272: void usage()
1.1       deraadt   273: {
1.14      millert   274:        fprintf(stderr, "usage: %s [-nrvm] [-f config-file]\n", __progname);
                    275:        exit(1);
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.18      millert   357:                 if (!sscanf(q,"%d",&working->numlogs) || working->numlogs < 0)
1.11      downsj    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.14      millert   398:
                    399:                working->pidfile = PIDFILE;
                    400:                 q = parse = sob(++parse); /* Optional field */
                    401:                 *(parse = son(parse)) = '\0';
                    402:                if (q && *q != '\0') {
                    403:                        working->pidfile = strdup(q);
                    404:                        if (working->pidfile == NULL)
                    405:                                err(1, "strdup");
                    406:                }
1.1       deraadt   407:
                    408:                 free(errline);
                    409:         }
                    410:         if (working)
1.12      kstailey  411:                 working->next = NULL;
1.1       deraadt   412:         (void) fclose(f);
                    413:         return(first);
                    414: }
                    415:
1.9       downsj    416: char *missing_field(p, errline)
1.1       deraadt   417:         char    *p,*errline;
                    418: {
                    419:         if (!p || !*p) {
1.14      millert   420:                warnx("Missing field in config file line:");
1.11      downsj    421:                 fputs(errline, stderr);
1.1       deraadt   422:                 exit(1);
                    423:         }
                    424:         return(p);
                    425: }
                    426:
1.14      millert   427: void dotrim(log, numdays, flags, perm, owner_uid, group_gid, daemon_pid)
1.1       deraadt   428:         char    *log;
                    429:         int     numdays;
                    430:         int     flags;
                    431:         int     perm;
                    432:         int     owner_uid;
                    433:         int     group_gid;
1.14      millert   434:        int     daemon_pid;
1.1       deraadt   435: {
1.7       deraadt   436:         char    file1[MAXPATHLEN], file2[MAXPATHLEN];
                    437:         char    zfile1[MAXPATHLEN], zfile2[MAXPATHLEN];
1.1       deraadt   438:         int     fd;
                    439:         struct  stat st;
1.6       tholo     440:        int     days = numdays;
1.1       deraadt   441:
                    442:         /* Remove oldest log */
                    443:         (void) sprintf(file1,"%s.%d",log,numdays);
                    444:         (void) strcpy(zfile1, file1);
                    445:         (void) strcat(zfile1, COMPRESS_POSTFIX);
                    446:
                    447:         if (noaction) {
                    448:                 printf("rm -f %s\n", file1);
                    449:                 printf("rm -f %s\n", zfile1);
                    450:         } else {
                    451:                 (void) unlink(file1);
                    452:                 (void) unlink(zfile1);
                    453:         }
                    454:
                    455:         /* Move down log files */
                    456:         while (numdays--) {
                    457:                 (void) strcpy(file2,file1);
                    458:                 (void) sprintf(file1,"%s.%d",log,numdays);
                    459:                 (void) strcpy(zfile1, file1);
                    460:                 (void) strcpy(zfile2, file2);
                    461:                 if (lstat(file1, &st)) {
                    462:                         (void) strcat(zfile1, COMPRESS_POSTFIX);
                    463:                         (void) strcat(zfile2, COMPRESS_POSTFIX);
                    464:                         if (lstat(zfile1, &st)) continue;
                    465:                 }
                    466:                 if (noaction) {
                    467:                         printf("mv %s %s\n",zfile1,zfile2);
                    468:                         printf("chmod %o %s\n", perm, zfile2);
                    469:                         printf("chown %d.%d %s\n",
                    470:                                owner_uid, group_gid, zfile2);
                    471:                 } else {
                    472:                         (void) rename(zfile1, zfile2);
                    473:                         (void) chmod(zfile2, perm);
                    474:                         (void) chown(zfile2, owner_uid, group_gid);
                    475:                 }
                    476:         }
                    477:         if (!noaction && !(flags & CE_BINARY))
                    478:                 (void) log_trim(log);  /* Report the trimming to the old log */
                    479:
1.6       tholo     480:        if (days == 0) {
1.5       deraadt   481:                if (noaction)
                    482:                        printf("rm %s\n",log);
                    483:                else
                    484:                        (void) unlink(log);
                    485:        } else {
                    486:                if (noaction)
                    487:                        printf("mv %s to %s\n",log,file1);
                    488:                else
                    489:                        (void) rename(log,file1);
                    490:        }
                    491:
1.1       deraadt   492:         if (noaction)
                    493:                 printf("Start new log...");
                    494:         else {
                    495:                 fd = creat(log,perm);
1.11      downsj    496:                 if (fd < 0)
1.13      mickey    497:                        err(1, "can't start \'%s\' log", log);
1.11      downsj    498:                 if (fchown(fd, owner_uid, group_gid))
1.13      mickey    499:                        err(1, "can't chown \'%s\' log file", log);
1.1       deraadt   500:                 (void) close(fd);
                    501:                 if (!(flags & CE_BINARY))
1.11      downsj    502:                         if (log_trim(log))     /* Add status message */
1.13      mickey    503:                                 err(1, "can't add status message to log \'%s\'", log);
1.1       deraadt   504:         }
                    505:         if (noaction)
                    506:                 printf("chmod %o %s...",perm,log);
                    507:         else
                    508:                 (void) chmod(log,perm);
                    509:         if (noaction)
1.14      millert   510:                 printf("kill -HUP %d\n",daemon_pid);
1.17      deraadt   511:         else if (daemon_pid < MIN_PID)
1.14      millert   512:                warnx("preposterous process number: %d", daemon_pid);
                    513:         else if (kill(daemon_pid,SIGHUP))
1.17      deraadt   514:                warnx("warning - could not HUP daemon");
                    515:        if (flags & CE_COMPACT) {
                    516:                if (noaction)
                    517:                        printf("Compress %s.0\n",log);
                    518:                else
                    519:                        compress_log(log);
                    520:        }
1.1       deraadt   521: }
                    522:
                    523: /* Log the fact that the logs were turned over */
1.9       downsj    524: int log_trim(log)
1.17      deraadt   525:        char    *log;
1.1       deraadt   526: {
                    527:         FILE    *f;
                    528:         if ((f = fopen(log,"a")) == NULL)
                    529:                 return(-1);
                    530:         fprintf(f,"%s %s newsyslog[%d]: logfile turned over\n",
                    531:                 daytime, hostname, getpid());
                    532:         if (fclose(f) == EOF) {
1.11      downsj    533:                 err(1, "log_trim: fclose");
1.1       deraadt   534:         }
                    535:         return(0);
                    536: }
                    537:
1.16      millert   538: /* Fork off compress or gzip to compress the old log file */
1.9       downsj    539: void compress_log(log)
1.1       deraadt   540:         char    *log;
                    541: {
                    542:         int     pid;
1.7       deraadt   543:         char    tmp[MAXPATHLEN];
1.1       deraadt   544:
                    545:         pid = fork();
                    546:         (void) sprintf(tmp,"%s.0",log);
                    547:         if (pid < 0) {
1.11      downsj    548:                err(1, "fork");
1.1       deraadt   549:         } else if (!pid) {
                    550:                 (void) execl(COMPRESS,"compress","-f",tmp,0);
1.16      millert   551:                warn(COMPRESS);
                    552:                _exit(1);
1.1       deraadt   553:         }
                    554: }
                    555:
                    556: /* Return size in kilobytes of a file */
                    557: int sizefile(file)
                    558:         char    *file;
                    559: {
                    560:         struct stat sb;
                    561:
                    562:         if (stat(file,&sb) < 0)
                    563:                 return(-1);
                    564:         return(kbytes(dbtob(sb.st_blocks)));
                    565: }
                    566:
                    567: /* Return the age of old log file (file.0) */
1.21    ! millert   568: int age_old_log(file, mtime)
1.1       deraadt   569:         char    *file;
1.21    ! millert   570:        int     *mtime;
1.1       deraadt   571: {
                    572:         struct stat sb;
1.7       deraadt   573:         char tmp[MAXPATHLEN];
1.1       deraadt   574:
                    575:         (void) strcpy(tmp,file);
                    576:         if (stat(strcat(tmp,".0"),&sb) < 0)
                    577:             if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0)
                    578:                 return(-1);
1.21    ! millert   579:        *mtime = (int) (timenow - sb.st_mtime + 1800) / 3600;
        !           580:        return(0);
1.1       deraadt   581: }
                    582:
                    583: /* Skip Over Blanks */
                    584: char *sob(p)
                    585:         register char   *p;
                    586: {
                    587:         while (p && *p && isspace(*p))
                    588:                 p++;
                    589:         return(p);
                    590: }
                    591:
                    592: /* Skip Over Non-Blanks */
                    593: char *son(p)
                    594:         register char   *p;
                    595: {
                    596:         while (p && *p && !isspace(*p))
                    597:                 p++;
                    598:         return(p);
                    599: }
                    600:
                    601:
                    602: /* Check if string is actually a number */
                    603:
1.10      downsj    604: int isnumberstr(string)
                    605:        char *string;
1.1       deraadt   606: {
                    607:         while (*string != '\0') {
1.9       downsj    608:             if (!isdigit(*string++))
                    609:                return(0);
1.1       deraadt   610:         }
                    611:         return(1);
1.10      downsj    612: }
                    613:
                    614: void domonitor(log, whom)
                    615:        char *log, *whom;
                    616: {
                    617:        struct stat sb, tsb;
                    618:        char *fname, *flog, *p, *rb = NULL;
                    619:        FILE *fp;
                    620:        off_t osize;
                    621:        int rd;
                    622:
                    623:        if (stat(log, &sb) < 0)
                    624:                return;
                    625:
                    626:        flog = strdup(log);
1.11      downsj    627:        if (flog == NULL)
                    628:                err(1, "strdup");
                    629:
1.10      downsj    630:        for (p = flog; *p != '\0'; p++) {
                    631:                if (*p == '/')
                    632:                        *p = '_';
                    633:        }
1.20      fgsch     634:        fname = (char *) malloc(sizeof(STATS_DIR) + strlen(flog) + 16);
1.11      downsj    635:        if (fname == NULL)
                    636:                err(1, "malloc");
                    637:
1.10      downsj    638:        sprintf(fname, "%s/newsyslog.%s.size", STATS_DIR, flog);
                    639:
                    640:        /* ..if it doesn't exist, simply record the current size. */
                    641:        if ((sb.st_size == 0) || stat(fname, &tsb) < 0)
                    642:                goto update;
                    643:
                    644:        fp = fopen(fname, "r");
                    645:        if (fp == NULL) {
1.11      downsj    646:                warn(fname);
1.10      downsj    647:                goto cleanup;
                    648:        }
                    649: #ifdef QUAD_OFF_T
                    650:        if (fscanf(fp, "%qd\n", &osize) != 1) {
                    651: #else
                    652:        if (fscanf(fp, "%ld\n", &osize) != 1) {
                    653: #endif /* QUAD_OFF_T */
                    654:                fclose(fp);
                    655:                goto update;
                    656:        }
                    657:
                    658:        fclose(fp);
                    659:
                    660:        /* If the file is smaller, mark the entire thing as changed. */
                    661:        if (sb.st_size < osize)
                    662:                osize = 0;
                    663:
                    664:        /* Now see if current size is larger. */
                    665:        if (sb.st_size > osize) {
                    666:                rb = (char *) malloc(sb.st_size - osize);
1.11      downsj    667:                if (rb == NULL)
                    668:                        err(1, "malloc");
1.10      downsj    669:
                    670:                /* Open logfile, seek. */
                    671:                fp = fopen(log, "r");
                    672:                if (fp == NULL) {
1.11      downsj    673:                        warn(log);
1.10      downsj    674:                        goto cleanup;
                    675:                }
                    676:                fseek(fp, osize, SEEK_SET);
                    677:                rd = fread(rb, 1, sb.st_size - osize, fp);
                    678:                if (rd < 1) {
1.11      downsj    679:                        warn("fread");
1.10      downsj    680:                        fclose(fp);
                    681:                        goto cleanup;
                    682:                }
                    683:
                    684:                /* Send message. */
                    685:                fclose(fp);
                    686:
                    687:                fp = openmail();
                    688:                if (fp == NULL) {
1.11      downsj    689:                        warn("openmail");
1.10      downsj    690:                        goto cleanup;
                    691:                }
                    692:                fprintf(fp, "To: %s\nSubject: LOGFILE NOTIFICATION: %s\n\n\n",
                    693:                    whom, log);
                    694:                fwrite(rb, 1, rd, fp);
                    695:                fputs("\n\n", fp);
                    696:
                    697:                closemail(fp);
                    698:        }
                    699: update:
                    700:        /* Reopen for writing and update file. */
                    701:        fp = fopen(fname, "w");
                    702:        if (fp == NULL) {
1.11      downsj    703:                warn(fname);
1.10      downsj    704:                goto cleanup;
                    705:        }
                    706: #ifdef QUAD_OFF_T
                    707:        fprintf(fp, "%qd\n", sb.st_size);
                    708: #else
                    709:        fprintf(fp, "%ld\n", sb.st_size);
                    710: #endif /* QUAD_OFF_T */
                    711:        fclose(fp);
                    712:
                    713: cleanup:
                    714:        free(flog);
                    715:        free(fname);
                    716:        if (rb != NULL)
                    717:                free(rb);
                    718: }
                    719:
                    720: FILE *openmail()
                    721: {
                    722:        char *cmdbuf;
                    723:        FILE *ret;
                    724:
1.20      fgsch     725:        cmdbuf = (char *) malloc(sizeof(SENDMAIL) + 3);
1.10      downsj    726:        if (cmdbuf == NULL)
                    727:                return(NULL);
                    728:
                    729:        sprintf(cmdbuf, "%s -t", SENDMAIL);
                    730:        ret = popen(cmdbuf, "w");
                    731:
                    732:        free(cmdbuf);
                    733:        return(ret);
                    734: }
                    735:
                    736: void closemail(pfp)
                    737:        FILE *pfp;
                    738: {
                    739:        pclose(pfp);
1.16      millert   740: }
                    741:
                    742: void child_killer(signum)
                    743:        int signum;
                    744: {
                    745:        int status;
                    746:
                    747:        while (waitpid(-1, &status, WNOHANG) > 0)
                    748:                ;
1.1       deraadt   749: }