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

1.1     ! deraadt     1: /*
        !             2:  * This file contains changes from the Open Software Foundation.
        !             3:  */
        !             4:
        !             5: /*
        !             6:
        !             7: Copyright 1988, 1989 by the Massachusetts Institute of Technology
        !             8:
        !             9: Permission to use, copy, modify, and distribute this software
        !            10: and its documentation for any purpose and without fee is
        !            11: hereby granted, provided that the above copyright notice
        !            12: appear in all copies and that both that copyright notice and
        !            13: this permission notice appear in supporting documentation,
        !            14: and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
        !            15: used in advertising or publicity pertaining to distribution
        !            16: of the software without specific, written prior permission.
        !            17: M.I.T. and the M.I.T. S.I.P.B. make no representations about
        !            18: the suitability of this software for any purpose.  It is
        !            19: provided "as is" without express or implied warranty.
        !            20:
        !            21: */
        !            22:
        !            23: /*
        !            24:  *      newsyslog - roll over selected logs at the appropriate time,
        !            25:  *              keeping the a specified number of backup files around.
        !            26:  *
        !            27:  *      $Source: /a/cvsroot/src/usr.bin/newsyslog/newsyslog.c,v $
        !            28:  *      $Author: jtc $
        !            29:  */
        !            30:
        !            31: #ifndef lint
        !            32: static char rcsid[] = "$Id: newsyslog.c,v 1.9 1995/01/21 21:53:46 jtc Exp $";
        !            33: #endif /* not lint */
        !            34:
        !            35: #ifndef CONF
        !            36: #define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
        !            37: #endif
        !            38: #ifndef PIDFILE
        !            39: #define PIDFILE "/etc/syslog.pid"
        !            40: #endif
        !            41: #ifndef COMPRESS
        !            42: #define COMPRESS "/usr/ucb/compress" /* File compression program */
        !            43: #endif
        !            44: #ifndef COMPRESS_POSTFIX
        !            45: #define COMPRESS_POSTFIX ".Z"
        !            46: #endif
        !            47:
        !            48: #include <stdio.h>
        !            49: #include <stdlib.h>
        !            50: #include <string.h>
        !            51: #include <ctype.h>
        !            52: #include <signal.h>
        !            53: #include <pwd.h>
        !            54: #include <grp.h>
        !            55: #include <sys/types.h>
        !            56: #include <sys/time.h>
        !            57: #include <sys/stat.h>
        !            58: #include <sys/param.h>
        !            59: #include <sys/wait.h>
        !            60:
        !            61: #define kbytes(size)  (((size) + 1023) >> 10)
        !            62: #ifdef _IBMR2
        !            63: /* Calculates (db * DEV_BSIZE) */
        !            64: #define dbtob(db)  ((unsigned)(db) << UBSHIFT)
        !            65: #endif
        !            66:
        !            67: #define CE_COMPACT 1            /* Compact the achived log files */
        !            68: #define CE_BINARY 2             /* Logfile is in binary, don't add */
        !            69:                                 /* status messages */
        !            70: #define NONE -1
        !            71:
        !            72: struct conf_entry {
        !            73:         char    *log;           /* Name of the log */
        !            74:         int     uid;            /* Owner of log */
        !            75:         int     gid;            /* Group of log */
        !            76:         int     numlogs;        /* Number of logs to keep */
        !            77:         int     size;           /* Size cutoff to trigger trimming the log */
        !            78:         int     hours;          /* Hours between log trimming */
        !            79:         int     permissions;    /* File permissions on the log */
        !            80:         int     flags;          /* Flags (CE_COMPACT & CE_BINARY)  */
        !            81:         struct conf_entry       *next; /* Linked list pointer */
        !            82: };
        !            83:
        !            84: extern int      optind;
        !            85: extern char     *optarg;
        !            86: extern char *malloc();
        !            87: extern uid_t getuid(),geteuid();
        !            88: extern time_t time();
        !            89:
        !            90: char    *progname;              /* contains argv[0] */
        !            91: int     verbose = 0;            /* Print out what's going on */
        !            92: int     needroot = 1;           /* Root privs are necessary */
        !            93: int     noaction = 0;           /* Don't do anything, just show it */
        !            94: char    *conf = CONF;           /* Configuration file to use */
        !            95: time_t  timenow;
        !            96: int     syslog_pid;             /* read in from /etc/syslog.pid */
        !            97: #define MIN_PID                3
        !            98: #define MAX_PID                65534
        !            99: char    hostname[64];           /* hostname */
        !           100: char    *daytime;               /* timenow in human readable form */
        !           101:
        !           102:
        !           103: struct conf_entry *parse_file();
        !           104: char *sob(), *son(), *strdup(), *missing_field();
        !           105:
        !           106: main(argc,argv)
        !           107:         int argc;
        !           108:         char **argv;
        !           109: {
        !           110:         struct conf_entry *p, *q;
        !           111:
        !           112:         PRS(argc,argv);
        !           113:         if (needroot && getuid() && geteuid()) {
        !           114:                 fprintf(stderr,"%s: must have root privs\n",progname);
        !           115:                 exit(1);
        !           116:         }
        !           117:         p = q = parse_file();
        !           118:         while (p) {
        !           119:                 do_entry(p);
        !           120:                 p=p->next;
        !           121:                 free((char *) q);
        !           122:                 q=p;
        !           123:         }
        !           124:         exit(0);
        !           125: }
        !           126:
        !           127: do_entry(ent)
        !           128:         struct conf_entry       *ent;
        !           129:
        !           130: {
        !           131:         int     size, modtime;
        !           132:
        !           133:         if (verbose) {
        !           134:                 if (ent->flags & CE_COMPACT)
        !           135:                         printf("%s <%dZ>: ",ent->log,ent->numlogs);
        !           136:                 else
        !           137:                         printf("%s <%d>: ",ent->log,ent->numlogs);
        !           138:         }
        !           139:         size = sizefile(ent->log);
        !           140:         modtime = age_old_log(ent->log);
        !           141:         if (size < 0) {
        !           142:                 if (verbose)
        !           143:                         printf("does not exist.\n");
        !           144:         } else {
        !           145:                 if (verbose && (ent->size > 0))
        !           146:                         printf("size (Kb): %d [%d] ", size, ent->size);
        !           147:                 if (verbose && (ent->hours > 0))
        !           148:                         printf(" age (hr): %d [%d] ", modtime, ent->hours);
        !           149:                 if (((ent->size > 0) && (size >= ent->size)) ||
        !           150:                     ((ent->hours > 0) && ((modtime >= ent->hours)
        !           151:                                         || (modtime < 0)))) {
        !           152:                         if (verbose)
        !           153:                                 printf("--> trimming log....\n");
        !           154:                         if (noaction && !verbose) {
        !           155:                                 if (ent->flags & CE_COMPACT)
        !           156:                                         printf("%s <%dZ>: trimming",
        !           157:                                                ent->log,ent->numlogs);
        !           158:                                 else
        !           159:                                         printf("%s <%d>: trimming",
        !           160:                                                ent->log,ent->numlogs);
        !           161:                         }
        !           162:                         dotrim(ent->log, ent->numlogs, ent->flags,
        !           163:                                ent->permissions, ent->uid, ent->gid);
        !           164:                 } else {
        !           165:                         if (verbose)
        !           166:                                 printf("--> skipping\n");
        !           167:                 }
        !           168:         }
        !           169: }
        !           170:
        !           171: PRS(argc,argv)
        !           172:         int argc;
        !           173:         char **argv;
        !           174: {
        !           175:         int     c;
        !           176:         FILE    *f;
        !           177:         char    line[BUFSIZ];
        !           178:        char    *p;
        !           179:
        !           180:         progname = argv[0];
        !           181:         timenow = time((time_t *) 0);
        !           182:         daytime = ctime(&timenow) + 4;
        !           183:         daytime[16] = '\0';
        !           184:
        !           185:         /* Let's find the pid of syslogd */
        !           186:         syslog_pid = 0;
        !           187:         f = fopen(PIDFILE,"r");
        !           188:         if (f && fgets(line,BUFSIZ,f))
        !           189:                 syslog_pid = atoi(line);
        !           190:        if (f)
        !           191:                (void)fclose(f);
        !           192:
        !           193:         /* Let's get our hostname */
        !           194:         (void) gethostname(hostname, sizeof(hostname));
        !           195:
        !           196:        /* Truncate domain */
        !           197:        if (p = strchr(hostname, '.')) {
        !           198:                *p = '\0';
        !           199:        }
        !           200:
        !           201:         optind = 1;             /* Start options parsing */
        !           202:         while ((c=getopt(argc,argv,"nrvf:t:")) != EOF)
        !           203:                 switch (c) {
        !           204:                 case 'n':
        !           205:                         noaction++; /* This implies needroot as off */
        !           206:                         /* fall through */
        !           207:                 case 'r':
        !           208:                         needroot = 0;
        !           209:                         break;
        !           210:                 case 'v':
        !           211:                         verbose++;
        !           212:                         break;
        !           213:                 case 'f':
        !           214:                         conf = optarg;
        !           215:                         break;
        !           216:                 default:
        !           217:                         usage();
        !           218:                 }
        !           219:         }
        !           220:
        !           221: usage()
        !           222: {
        !           223:         fprintf(stderr,
        !           224:                 "Usage: %s <-nrv> <-f config-file>\n", progname);
        !           225:         exit(1);
        !           226: }
        !           227:
        !           228: /* Parse a configuration file and return a linked list of all the logs
        !           229:  * to process
        !           230:  */
        !           231: struct conf_entry *parse_file()
        !           232: {
        !           233:         FILE    *f;
        !           234:         char    line[BUFSIZ], *parse, *q;
        !           235:         char    *errline, *group;
        !           236:         struct conf_entry *first = NULL;
        !           237:         struct conf_entry *working;
        !           238:         struct passwd *pass;
        !           239:         struct group *grp;
        !           240:
        !           241:         if (strcmp(conf,"-"))
        !           242:                 f = fopen(conf,"r");
        !           243:         else
        !           244:                 f = stdin;
        !           245:         if (!f) {
        !           246:                 (void) fprintf(stderr,"%s: ",progname);
        !           247:                 perror(conf);
        !           248:                 exit(1);
        !           249:         }
        !           250:         while (fgets(line,BUFSIZ,f)) {
        !           251:                 if ((line[0]== '\n') || (line[0] == '#'))
        !           252:                         continue;
        !           253:                 errline = strdup(line);
        !           254:                 if (!first) {
        !           255:                         working = (struct conf_entry *) malloc(sizeof(struct conf_entry));
        !           256:                         first = working;
        !           257:                 } else {
        !           258:                         working->next = (struct conf_entry *) malloc(sizeof(struct conf_entry));
        !           259:                         working = working->next;
        !           260:                 }
        !           261:
        !           262:                 q = parse = missing_field(sob(line),errline);
        !           263:                 *(parse = son(line)) = '\0';
        !           264:                 working->log = strdup(q);
        !           265:
        !           266:                 q = parse = missing_field(sob(++parse),errline);
        !           267:                 *(parse = son(parse)) = '\0';
        !           268:                 if ((group = strchr(q, '.')) != NULL) {
        !           269:                     *group++ = '\0';
        !           270:                     if (*q) {
        !           271:                         if (!(isnumber(q))) {
        !           272:                             if ((pass = getpwnam(q)) == NULL) {
        !           273:                                 fprintf(stderr,
        !           274:                                     "Error in config file; unknown user:\n");
        !           275:                                 fputs(errline,stderr);
        !           276:                                 exit(1);
        !           277:                             }
        !           278:                             working->uid = pass->pw_uid;
        !           279:                         } else
        !           280:                             working->uid = atoi(q);
        !           281:                     } else
        !           282:                         working->uid = NONE;
        !           283:
        !           284:                     q = group;
        !           285:                     if (*q) {
        !           286:                         if (!(isnumber(q))) {
        !           287:                             if ((grp = getgrnam(q)) == NULL) {
        !           288:                                 fprintf(stderr,
        !           289:                                     "Error in config file; unknown group:\n");
        !           290:                                 fputs(errline,stderr);
        !           291:                                 exit(1);
        !           292:                             }
        !           293:                             working->gid = grp->gr_gid;
        !           294:                         } else
        !           295:                             working->gid = atoi(q);
        !           296:                     } else
        !           297:                         working->gid = NONE;
        !           298:
        !           299:                     q = parse = missing_field(sob(++parse),errline);
        !           300:                     *(parse = son(parse)) = '\0';
        !           301:                 }
        !           302:                 else
        !           303:                     working->uid = working->gid = NONE;
        !           304:
        !           305:                 if (!sscanf(q,"%o",&working->permissions)) {
        !           306:                         fprintf(stderr,
        !           307:                                 "Error in config file; bad permissions:\n");
        !           308:                         fputs(errline,stderr);
        !           309:                         exit(1);
        !           310:                 }
        !           311:
        !           312:                 q = parse = missing_field(sob(++parse),errline);
        !           313:                 *(parse = son(parse)) = '\0';
        !           314:                 if (!sscanf(q,"%d",&working->numlogs)) {
        !           315:                         fprintf(stderr,
        !           316:                                 "Error in config file; bad number:\n");
        !           317:                         fputs(errline,stderr);
        !           318:                         exit(1);
        !           319:                 }
        !           320:
        !           321:                 q = parse = missing_field(sob(++parse),errline);
        !           322:                 *(parse = son(parse)) = '\0';
        !           323:                 if (isdigit(*q))
        !           324:                         working->size = atoi(q);
        !           325:                 else
        !           326:                         working->size = -1;
        !           327:
        !           328:                 q = parse = missing_field(sob(++parse),errline);
        !           329:                 *(parse = son(parse)) = '\0';
        !           330:                 if (isdigit(*q))
        !           331:                         working->hours = atoi(q);
        !           332:                 else
        !           333:                         working->hours = -1;
        !           334:
        !           335:                 q = parse = sob(++parse); /* Optional field */
        !           336:                 *(parse = son(parse)) = '\0';
        !           337:                 working->flags = 0;
        !           338:                 while (q && *q && !isspace(*q)) {
        !           339:                         if ((*q == 'Z') || (*q == 'z'))
        !           340:                                 working->flags |= CE_COMPACT;
        !           341:                         else if ((*q == 'B') || (*q == 'b'))
        !           342:                                 working->flags |= CE_BINARY;
        !           343:                         else {
        !           344:                                 fprintf(stderr,
        !           345:                                         "Illegal flag in config file -- %c\n",
        !           346:                                         *q);
        !           347:                                 exit(1);
        !           348:                         }
        !           349:                         q++;
        !           350:                 }
        !           351:
        !           352:                 free(errline);
        !           353:         }
        !           354:         if (working)
        !           355:                 working->next = (struct conf_entry *) NULL;
        !           356:         (void) fclose(f);
        !           357:         return(first);
        !           358: }
        !           359:
        !           360: char *missing_field(p,errline)
        !           361:         char    *p,*errline;
        !           362: {
        !           363:         if (!p || !*p) {
        !           364:                 fprintf(stderr,"Missing field in config file:\n");
        !           365:                 fputs(errline,stderr);
        !           366:                 exit(1);
        !           367:         }
        !           368:         return(p);
        !           369: }
        !           370:
        !           371: dotrim(log,numdays,flags,perm,owner_uid,group_gid)
        !           372:         char    *log;
        !           373:         int     numdays;
        !           374:         int     flags;
        !           375:         int     perm;
        !           376:         int     owner_uid;
        !           377:         int     group_gid;
        !           378: {
        !           379:         char    file1[128], file2[128];
        !           380:         char    zfile1[128], zfile2[128];
        !           381:         int     fd;
        !           382:         struct  stat st;
        !           383:
        !           384: #ifdef _IBMR2
        !           385: /* AIX 3.1 has a broken fchown- if the owner_uid is -1, it will actually */
        !           386: /* change it to be owned by uid -1, instead of leaving it as is, as it is */
        !           387: /* supposed to. */
        !           388:                 if (owner_uid == -1)
        !           389:                   owner_uid = geteuid();
        !           390: #endif
        !           391:
        !           392:         /* Remove oldest log */
        !           393:         (void) sprintf(file1,"%s.%d",log,numdays);
        !           394:         (void) strcpy(zfile1, file1);
        !           395:         (void) strcat(zfile1, COMPRESS_POSTFIX);
        !           396:
        !           397:         if (noaction) {
        !           398:                 printf("rm -f %s\n", file1);
        !           399:                 printf("rm -f %s\n", zfile1);
        !           400:         } else {
        !           401:                 (void) unlink(file1);
        !           402:                 (void) unlink(zfile1);
        !           403:         }
        !           404:
        !           405:         /* Move down log files */
        !           406:         while (numdays--) {
        !           407:                 (void) strcpy(file2,file1);
        !           408:                 (void) sprintf(file1,"%s.%d",log,numdays);
        !           409:                 (void) strcpy(zfile1, file1);
        !           410:                 (void) strcpy(zfile2, file2);
        !           411:                 if (lstat(file1, &st)) {
        !           412:                         (void) strcat(zfile1, COMPRESS_POSTFIX);
        !           413:                         (void) strcat(zfile2, COMPRESS_POSTFIX);
        !           414:                         if (lstat(zfile1, &st)) continue;
        !           415:                 }
        !           416:                 if (noaction) {
        !           417:                         printf("mv %s %s\n",zfile1,zfile2);
        !           418:                         printf("chmod %o %s\n", perm, zfile2);
        !           419:                         printf("chown %d.%d %s\n",
        !           420:                                owner_uid, group_gid, zfile2);
        !           421:                 } else {
        !           422:                         (void) rename(zfile1, zfile2);
        !           423:                         (void) chmod(zfile2, perm);
        !           424:                         (void) chown(zfile2, owner_uid, group_gid);
        !           425:                 }
        !           426:         }
        !           427:         if (!noaction && !(flags & CE_BINARY))
        !           428:                 (void) log_trim(log);  /* Report the trimming to the old log */
        !           429:
        !           430:         if (noaction)
        !           431:                 printf("mv %s to %s\n",log,file1);
        !           432:         else
        !           433:                 (void) rename(log,file1);
        !           434:         if (noaction)
        !           435:                 printf("Start new log...");
        !           436:         else {
        !           437:                 fd = creat(log,perm);
        !           438:                 if (fd < 0) {
        !           439:                         perror("can't start new log");
        !           440:                         exit(1);
        !           441:                 }
        !           442:                 if (fchown(fd, owner_uid, group_gid)) {
        !           443:                         perror("can't chmod new log file");
        !           444:                         exit(1);
        !           445:                 }
        !           446:                 (void) close(fd);
        !           447:                 if (!(flags & CE_BINARY))
        !           448:                         if (log_trim(log)) {    /* Add status message */
        !           449:                                 perror("can't add status message to log");
        !           450:                                 exit(1);
        !           451:                         }
        !           452:         }
        !           453:         if (noaction)
        !           454:                 printf("chmod %o %s...",perm,log);
        !           455:         else
        !           456:                 (void) chmod(log,perm);
        !           457:         if (noaction)
        !           458:                 printf("kill -HUP %d (syslogd)\n",syslog_pid);
        !           459:         else
        !           460:        if (syslog_pid < MIN_PID || syslog_pid > MAX_PID) {
        !           461:                fprintf(stderr,"%s: preposterous process number: %d\n",
        !           462:                                progname, syslog_pid);
        !           463:         } else if (kill(syslog_pid,SIGHUP)) {
        !           464:                         fprintf(stderr,"%s: ",progname);
        !           465:                         perror("warning - could not restart syslogd");
        !           466:                 }
        !           467:         if (flags & CE_COMPACT) {
        !           468:                 if (noaction)
        !           469:                         printf("Compress %s.0\n",log);
        !           470:                 else
        !           471:                         compress_log(log);
        !           472:         }
        !           473: }
        !           474:
        !           475: /* Log the fact that the logs were turned over */
        !           476: log_trim(log)
        !           477:         char    *log;
        !           478: {
        !           479:         FILE    *f;
        !           480:         if ((f = fopen(log,"a")) == NULL)
        !           481:                 return(-1);
        !           482:         fprintf(f,"%s %s newsyslog[%d]: logfile turned over\n",
        !           483:                 daytime, hostname, getpid());
        !           484:         if (fclose(f) == EOF) {
        !           485:                 perror("log_trim: fclose:");
        !           486:                 exit(1);
        !           487:         }
        !           488:         return(0);
        !           489: }
        !           490:
        !           491: /* Fork of /usr/ucb/compress to compress the old log file */
        !           492: compress_log(log)
        !           493:         char    *log;
        !           494: {
        !           495:         int     pid;
        !           496:         char    tmp[128];
        !           497:
        !           498:         pid = fork();
        !           499:         (void) sprintf(tmp,"%s.0",log);
        !           500:         if (pid < 0) {
        !           501:                 fprintf(stderr,"%s: ",progname);
        !           502:                 perror("fork");
        !           503:                 exit(1);
        !           504:         } else if (!pid) {
        !           505:                 (void) execl(COMPRESS,"compress","-f",tmp,0);
        !           506:                 fprintf(stderr,"%s: ",progname);
        !           507:                 perror(COMPRESS);
        !           508:                 exit(1);
        !           509:         }
        !           510: }
        !           511:
        !           512: /* Return size in kilobytes of a file */
        !           513: int sizefile(file)
        !           514:         char    *file;
        !           515: {
        !           516:         struct stat sb;
        !           517:
        !           518:         if (stat(file,&sb) < 0)
        !           519:                 return(-1);
        !           520:         return(kbytes(dbtob(sb.st_blocks)));
        !           521: }
        !           522:
        !           523: /* Return the age of old log file (file.0) */
        !           524: int age_old_log(file)
        !           525:         char    *file;
        !           526: {
        !           527:         struct stat sb;
        !           528:         char tmp[MAXPATHLEN+3];
        !           529:
        !           530:         (void) strcpy(tmp,file);
        !           531:         if (stat(strcat(tmp,".0"),&sb) < 0)
        !           532:             if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0)
        !           533:                 return(-1);
        !           534:         return( (int) (timenow - sb.st_mtime + 1800) / 3600);
        !           535: }
        !           536:
        !           537:
        !           538: #ifndef OSF
        !           539: /* Duplicate a string using malloc */
        !           540:
        !           541: char *strdup(strp)
        !           542: register char   *strp;
        !           543: {
        !           544:         register char *cp;
        !           545:
        !           546:         if ((cp = malloc((unsigned) strlen(strp) + 1)) == NULL)
        !           547:                 abort();
        !           548:         return(strcpy (cp, strp));
        !           549: }
        !           550: #endif
        !           551:
        !           552: /* Skip Over Blanks */
        !           553: char *sob(p)
        !           554:         register char   *p;
        !           555: {
        !           556:         while (p && *p && isspace(*p))
        !           557:                 p++;
        !           558:         return(p);
        !           559: }
        !           560:
        !           561: /* Skip Over Non-Blanks */
        !           562: char *son(p)
        !           563:         register char   *p;
        !           564: {
        !           565:         while (p && *p && !isspace(*p))
        !           566:                 p++;
        !           567:         return(p);
        !           568: }
        !           569:
        !           570:
        !           571: /* Check if string is actually a number */
        !           572:
        !           573: isnumber(string)
        !           574: char *string;
        !           575: {
        !           576:         while (*string != '\0') {
        !           577:             if (*string < '0' || *string > '9') return(0);
        !           578:             string++;
        !           579:         }
        !           580:         return(1);
        !           581: }