[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.28

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