Annotation of 42BSD/usr.lib/sendmail/aux/syslog.c, revision 1.1.1.1

1.1       root        1: /*
                      2: **  SYSLOG -- log system messages
                      3: **
                      4: **     This program implements a system log, implemented as the
                      5: **     "/dev/log" mpx file on a pre-4.2bsd system or a port on
                      6: **     a post-4.2bsd system.  This takes a series of lines.
                      7: **     Each line may have a priority, signified as "<n>" as
                      8: **     the first three characters of the line.  If this is
                      9: **     not present, a default priority (DefPri) is used, which
                     10: **     starts out as LOG_ERROR.  The default priority can get
                     11: **     changed using "<*>n".
                     12: **
                     13: **     Timestamps are added if they are not already present.
                     14: **
                     15: **     To kill syslog, send a signal 15 (terminate).  In 30
                     16: **     seconds, syslog will go down.  A signal 1 (hup) will
                     17: **     cause it to reread its configuration file.
                     18: **
                     19: **     Defined Constants:
                     20: **             MAXLINE -- the maximimum line length that can be
                     21: **                     handled.
                     22: **             NLOGS -- the maximum number of simultaneous log
                     23: **                     files.
                     24: **             NUSERS -- the maximum number of people that can
                     25: **                     be designated as "superusers" on your system.
                     26: **
                     27: **     Author:
                     28: **             Eric Allman, UCB/INGRES and Britton-Lee.
                     29: */
                     30: 
                     31: # define       NLOGS           10      /* max number of log files */
                     32: # define       NSUSERS         10      /* max number of special users */
                     33: # define       MAXLINE         256     /* maximum line length */
                     34: 
                     35: # define       LOGHOSTNAME     1       /* log hostid on each line */
                     36: 
                     37: # include      <syslog.h>
                     38: # include      <errno.h>
                     39: # include      <stdio.h>
                     40: # include      <utmp.h>
                     41: # include      <ctype.h>
                     42: # include      <sys/param.h>
                     43: # include      <sys/stat.h>
                     44: # include      <signal.h>
                     45: # include      <sysexits.h>
                     46: # ifdef LOG_IPC
                     47: # include      <sys/socket.h>
                     48: #ifndef LOG_OLDIPC
                     49: # include      <netinet/in.h>
                     50: # include      <netdb.h>
                     51: #else LOG_OLDIPC
                     52: # include      <net/in.h>
                     53: #endif LOG_OLDIPC
                     54: # else LOG_IPC
                     55: # include      <sys/mx.h>
                     56: # endif LOG_IPC
                     57: 
                     58: typedef char   bool;
                     59: # define       TRUE            1
                     60: # define       FALSE           0
                     61: 
                     62: # ifdef EBUG
                     63: # define       dprintf         if (Debug) printf
                     64: # else
                     65: # define       dprintf         if (0) printf
                     66: # endif
                     67: 
                     68: static char SccsId[] = "@(#)syslog.c   4.1     7/25/83";
                     69: 
                     70: # define UNAMESZ       8       /* length of a login name */
                     71: 
                     72: /*
                     73: **  This structure represents the files that will have log
                     74: **  copies printed.
                     75: */
                     76: 
                     77: struct filed
                     78: {
                     79:        char    f_pmask;        /* priority mask */
                     80:        bool    f_mark;         /* if set, output timing marks */
                     81:        bool    f_tty;          /* if set, this is a tty */
                     82:        FILE    *f_file;        /* file descriptor; NULL means unallocated */
                     83:        long    f_time;         /* the last time anything was output to it */
                     84:        char    f_name[30];     /* filename */
                     85: };
                     86: 
                     87: struct filed   Files[NLOGS];
                     88: 
                     89: /* list of superusers */
                     90: char           Susers[NSUSERS][UNAMESZ+1];
                     91: 
                     92: int    ShutDown;               /* set if going down */
                     93: int    DefPri = LOG_ERROR;     /* the default priority for untagged msgs */
                     94: int    Debug;                  /* debug flag */
                     95: int    LogFile;                /* log mx file descriptor */
                     96: int    MarkIntvl = 15;         /* mark interval in minutes */
                     97: char   *ConfFile;              /* configuration file */
                     98: 
                     99: # ifdef LOG_IPC
                    100: #ifndef LOG_OLDIPC
                    101: struct sockaddr_in     SyslogAddr;
                    102: #else LOG_OLDIPC
                    103: struct sockaddr_in     SyslogAddr =    { AF_INET, LOG_PORT };
                    104: struct sockproto       SyslogProto =   { PF_INET, IPPROTO_UDP };
                    105: #endif LOG_OLDIPC
                    106: # endif LOG_IPC
                    107: 
                    108: main(argc, argv)
                    109:        int argc;
                    110:        char **argv;
                    111: {
                    112:        register int i;
                    113:        register char *p;
                    114:        extern shutdown();
                    115:        extern int domark();
                    116:        extern int errno;
                    117:        int errct = 0;
                    118:        FILE *fp;
                    119:        char *logname = "/dev/log";
                    120: #ifndef LOG_OLDIPC
                    121: #ifdef LOG_IPC
                    122:        auto int lenSyslogAddr;
                    123:        struct servent *sp;
                    124:        struct hostent *hp;
                    125: #endif LOG_IPC
                    126: #endif LOG_OLDIPC
                    127:        static char *defconf = "/etc/syslog.conf";
                    128:        static char *defpid = "/etc/syslog.pid";
                    129:        char line[300];
                    130: 
                    131: #ifndef LOG_OLDIPC
                    132: #ifdef LOG_IPC
                    133:        /* set up initial port assignment */
                    134:        sp = getservbyname("syslog", "udp");
                    135:        if (sp == NULL)
                    136:        {
                    137:                perror("Cannot get server");
                    138:                exit(EX_OSFILE);
                    139:        }
                    140:        SyslogAddr.sin_family = AF_INET;
                    141:        SyslogAddr.sin_port = sp->s_port;
                    142:        SyslogAddr.sin_addr.s_addr = INADDR_ANY;
                    143: #endif LOG_IPC
                    144: 
                    145: #endif LOG_OLDIPC
                    146:        while (--argc > 0)
                    147:        {
                    148:                p = *++argv;
                    149:                if (p[0] == '-')
                    150:                {
                    151:                        switch (p[1])
                    152:                        {
                    153:                          case 'm':             /* set mark interval */
                    154:                                MarkIntvl = atoi(&p[2]);
                    155:                                if (MarkIntvl <= 0)
                    156:                                        MarkIntvl = 1;
                    157:                                break;
                    158: 
                    159:                          case 'f':             /* configuration file */
                    160:                                if (p[2] != '\0')
                    161:                                        ConfFile = &p[2];
                    162:                                else
                    163:                                        ConfFile = defconf;
                    164:                                break;
                    165: 
                    166:                          case 'd':             /* debug */
                    167:                                Debug++;
                    168:                                if (ConfFile == NULL)
                    169:                                        ConfFile = "./syslog.conf";
                    170:                                break;
                    171: 
                    172: # ifdef LOG_IPC
                    173:                          case 'p':             /* port */
                    174:                                SyslogAddr.sin_port = htons(atoi(&p[2]));
                    175:                                break;
                    176: # endif LOG_IPC
                    177:                        }
                    178:                }
                    179:        }
                    180: 
                    181:        if (ConfFile == NULL)
                    182:                ConfFile = defconf;
                    183: 
                    184:        /* try to ignore all signals */
                    185:        if (!Debug)
                    186:        {
                    187:                for (i = 1; i < NSIG; i++)
                    188:                        signal(i, SIG_IGN);
                    189:        }
                    190:        else
                    191:                signal(SIGINT, shutdown);
                    192:        signal(SIGTERM, shutdown);
                    193:        signal(SIGALRM, domark);
                    194:        alarm(MarkIntvl*60);
                    195:        
                    196:        /* close all files */
                    197:        if (!Debug)
                    198:                for (i = 0; i < NOFILE; i++)
                    199:                        close(i);
                    200: 
                    201: # ifdef LOG_IPC
                    202:        logname = "IPC socket";
                    203: #ifndef LOG_OLDIPC
                    204:        LogFile = socket(AF_INET, SOCK_DGRAM, 0, 0);
                    205:        if (LogFile >= 0 && bind(LogFile, &SyslogAddr, sizeof SyslogAddr, 0) < 0)
                    206:        {
                    207:                close(LogFile);
                    208:                LogFile = -1;
                    209:        }
                    210: #else LOG_OLDIPC
                    211:        LogFile = socket(SOCK_DGRAM, &SyslogProto, &SyslogAddr, 0);
                    212: #endif LOG_OLDIPC
                    213: # else  LOG_IPC
                    214:        /* create the "/dev/log" device */
                    215:        if (Debug)
                    216:                logname = "log";
                    217:        unlink(logname);
                    218:        LogFile = mpx(logname, 0222);
                    219:        chmod(logname, 0222);
                    220: # endif LOG_IPC
                    221:        if (LogFile < 0)
                    222:        {
                    223:                fp = fopen("/dev/console", "w");
                    224:                fprintf(fp, "\r\nsyslog: cannot create %s (%d)\r\n", logname, errno);
                    225:                dprintf("cannot create %s (%d)\n", logname, errno);
                    226:                exit(EX_OSFILE);
                    227:        }
                    228: 
                    229:        /* now we can run as daemon safely */
                    230:        setuid(1);
                    231:        dprintf("off & running....\n");
                    232:        if (!Debug)
                    233:        {
                    234:                if (fork() == 0)
                    235:                {
                    236:                        /* tuck my process id away */
                    237:                        fp = fopen(defpid, "w");
                    238:                        if (fp != NULL)
                    239:                        {
                    240:                                fprintf(fp, "%d\n", getpid());
                    241:                                fclose(fp);
                    242:                        }
                    243:                }
                    244:                else
                    245:                        exit(0);
                    246:        }
                    247:        
                    248:        init();
                    249: 
                    250:        for (;;)
                    251:        {
                    252: # ifdef LOG_IPC
                    253: #ifndef LOG_OLDIPC
                    254:                lenSyslogAddr = sizeof SyslogAddr;
                    255:                i = recvfrom(LogFile, line, sizeof line, 0, &SyslogAddr, &lenSyslogAddr);
                    256: #else LOG_OLDIPC
                    257:                i = receive(LogFile, &SyslogAddr, line, sizeof line);
                    258: #endif LOG_OLDIPC
                    259: # else LOG_IPC
                    260:                i = read(LogFile, line, sizeof line);
                    261: # endif LOG_IPC
                    262:                if (i < 0)
                    263:                {
                    264:                        if (errno == EINTR)
                    265:                                continue;
                    266:                        logerror("read");
                    267:                        errct++;
                    268:                        if (errct > 1000)
                    269:                        {
                    270:                                logmsg(LOG_SALERT, "syslog: too many errors");
                    271:                                die();
                    272:                        }
                    273:                        sleep(15);
                    274:                        continue;
                    275:                }
                    276: # ifdef LOG_IPC
                    277:                line[i] = '\0';
                    278:                hp = gethostbyaddr(&SyslogAddr.sin_addr,
                    279:                    sizeof (SyslogAddr.sin_addr), AF_INET);
                    280:                if (hp == 0)
                    281:                        printline(line, inet_ntoa(SyslogAddr.sin_addr));
                    282:                else
                    283:                        printline(line, hp->h_name);
                    284: # else LOG_IPC
                    285:                crack(line, i);
                    286: # endif LOG_IPC
                    287:        }
                    288: }
                    289: /*
                    290: **  LOGERROR -- log an error on the log.
                    291: **
                    292: **     Parameters:
                    293: **             type -- string to print as error type.
                    294: **
                    295: **     Returns:
                    296: **             none.
                    297: **
                    298: **     Side Effects:
                    299: **             outputs the error code in errno to someplace.
                    300: */
                    301: 
                    302: logerror(type)
                    303:        char *type;
                    304: {
                    305:        char buf[50];
                    306:        extern int errno;
                    307: 
                    308:        sprintf(buf, "log %s error %d\n", type, errno);
                    309:        errno = 0;
                    310:        logmsg(LOG_SALERT, buf);
                    311: }
                    312: 
                    313: # ifndef LOG_IPC
                    314: 
                    315: /*
                    316: **  CRACK -- parse & handle a log line
                    317: **
                    318: **     Parameters:
                    319: **             rec -- the input record.
                    320: **             bc -- the byte count for rec.
                    321: **
                    322: **     Returns:
                    323: **             nothing
                    324: **
                    325: **     Side Effects:
                    326: **             rec is output.
                    327: */
                    328: 
                    329: # define skip(rec, n)  ((struct rh *) (((char *) rec) + n))
                    330: 
                    331: crack(rec, bc)
                    332:        register struct rh *rec;
                    333:        int bc;
                    334: {
                    335:        struct rh *endrec;
                    336: 
                    337:        endrec = skip(rec, bc);
                    338: 
                    339:        while (rec < endrec)
                    340:        {
                    341:                if (rec->count == 0)
                    342:                {
                    343:                        /* control record from mpx file */
                    344:                        dprintf("%d byte control message\n", rec->ccount);
                    345:                        control(rec);
                    346:                }
                    347:                else
                    348:                {
                    349:                        /* data record -- process message */
                    350:                        messg(rec);
                    351:                }
                    352:                rec->count += rec->ccount;
                    353:                if (rec->count & 01)
                    354:                        rec->count++;
                    355:                rec = skip(rec, rec->count + sizeof *rec);
                    356:        }
                    357: }
                    358: /*
                    359: **  CONTROL -- handle mpx control messages.
                    360: **
                    361: **     Parameters:
                    362: **             rec -- control message.
                    363: **
                    364: **     Returns:
                    365: **             none.
                    366: **
                    367: **     Side Effects:
                    368: **             as necessary for that control message.
                    369: */
                    370: 
                    371: short NoIoctl[] = { M_IOANS };
                    372: 
                    373: control(rec)
                    374:        register struct rh *rec;
                    375: {
                    376:        register int cmd;
                    377:        register short val;
                    378:        register short *ap;
                    379: # ifdef MPXDEBUG
                    380:        char dbbuf[100];
                    381: # endif MPXDEBUG
                    382: 
                    383:        ap = (short *) (((char *) rec) + sizeof *rec);
                    384:        cmd = *ap++ & 0377;
                    385:        val = *ap++;
                    386: # ifdef MPXDEBUG
                    387:        sprintf(dbbuf, "syslog: ctl ch=%x cmd=%d val=%d", rec->index, cmd, val);
                    388:        logmsg(LOG_DEBUG, dbbuf);
                    389: # endif MPXDEBUG
                    390: 
                    391:        switch (cmd)
                    392:        {
                    393:          case M_WATCH:         /* attempted connect; value is uid */
                    394:                dprintf("WATCH, uid=%d\n", val);
                    395:                attach(rec->index, LogFile);
                    396:                break;
                    397: 
                    398:          case M_CLOSE:         /* close channel; value is unused */
                    399:                dprintf("CLOSE, val=%d\n", val);
                    400:                detach(rec->index, LogFile);
                    401:                break;
                    402: 
                    403:          case M_IOCTL:
                    404:                dprintf("IOCTL, val=%d\n", val);
                    405:                wmpxctl(rec->index, NoIoctl, sizeof NoIoctl);
                    406:                break;
                    407: 
                    408:          default:
                    409:                dprintf("unknown cmd %d, val=%d\n", cmd, val);
                    410:                break;
                    411:        }
                    412: }
                    413: /*
                    414: **  WMPXCTL -- write mpx control message
                    415: **
                    416: **     Parameters:
                    417: **             index -- index to write to.
                    418: **             buf -- place to write.
                    419: **             len -- length to write.
                    420: **
                    421: **     Returns:
                    422: **             none.
                    423: **
                    424: **     Side Effects:
                    425: **             writes to LogFile.
                    426: */
                    427: 
                    428: wmpxctl(index, buf, cnt)
                    429:        int index;
                    430:        char *buf;
                    431:        int cnt;
                    432: {
                    433:        struct wh wbuf;
                    434: 
                    435:        wbuf.index = index;
                    436:        wbuf.count = 0;
                    437:        wbuf.ccount = cnt;
                    438:        wbuf.data = buf;
                    439:        write(LogFile, &wbuf, sizeof wbuf);
                    440: }
                    441: /*
                    442: **  MESSG -- log message
                    443: **
                    444: **     Parameters:
                    445: **             rec -- record of data.
                    446: **
                    447: **     Returns:
                    448: **             nothing.
                    449: **
                    450: **     Side Effects:
                    451: **             sends the record to the system log.
                    452: */
                    453: 
                    454: messg(rec)
                    455:        register struct rh *rec;
                    456: {
                    457:        char endchar;
                    458:        char *endptr;
                    459:        register char *q;
                    460: 
                    461:        q = (char *) rec + sizeof *rec;
                    462:        endptr = &q[rec->count];
                    463:        endchar = *endptr;
                    464:        *endptr = '\0';
                    465:        printline(q, NULL);
                    466:        *endptr = endchar;
                    467: }
                    468: 
                    469: # endif LOG_IPC
                    470: /*
                    471: **  PRINTLINE -- print one line
                    472: **
                    473: **     This is really it -- we have one line -- we crack it and
                    474: **     and print it appropriately.
                    475: **
                    476: **     Parameters:
                    477: **             q -- pointer to the line.
                    478: **             tag -- the name of the host this is from.
                    479: **
                    480: **     Returns:
                    481: **             none.
                    482: **
                    483: **     Side Effects:
                    484: **             q is broken up and printed.
                    485: */
                    486: 
                    487: printline(q, tag)
                    488:        register char *q;
                    489: {
                    490:        register int i;
                    491:        static int pri;
                    492:        register char *p;
                    493:        static char buf[1000];
                    494:        static char *bp = buf;
                    495: 
                    496:        dprintf("message = ``%s''\n", q);
                    497:        while (*q != '\0')
                    498:        {
                    499:                if (bp == buf)
                    500:                {
                    501: # if LOGHOSTNAME > 0
                    502:                        if (tag != NULL)
                    503:                        {
                    504:                                strcpy(bp, tag);
                    505:                                strcat(bp, ": ");
                    506:                                bp += strlen(bp);
                    507:                        }
                    508: # endif LOGHOSTNAME
                    509: 
                    510:                        /* test for special codes */
                    511:                        pri = DefPri;
                    512:                        if (q[0] == '<' && q[2] == '>')
                    513:                        {
                    514:                                switch (q[1])
                    515:                                {
                    516:                                  case '*':     /* reset default message priority */
                    517:                                        dprintf("default priority = %c\n", q[3]);
                    518:                                        i = q[3] - '0';
                    519:                                        if (i > 0 && i <= 9)
                    520:                                                DefPri = i;
                    521:                                        continue;
                    522: 
                    523:                                  case '$':     /* reconfigure */
                    524:                                        dprintf("reconfigure\n");
                    525:                                        init();
                    526:                                        continue;
                    527:                                }
                    528:                                q++;
                    529:                                pri = *q++ - '0';
                    530:                                q++;
                    531:                                if (pri < 0 || pri > 9)
                    532:                                        pri = DefPri;
                    533:                        }
                    534:                        else
                    535:                                pri = DefPri;
                    536:                }
                    537:                while (*q != '\0' && *q != '\n')
                    538:                {
                    539:                        if (*q != '\r')
                    540:                                *bp++ = *q;
                    541:                        q++;
                    542:                }
                    543:                if (*q == '\0')
                    544:                        continue;
                    545:                *bp++ = '\0';
                    546:                q++;
                    547:                bp = buf;
                    548: 
                    549:                /* output the line to all files */
                    550:                logmsg(pri, bp);
                    551:                bp = buf;
                    552:        }
                    553: }
                    554: /*
                    555: **  SHUTDOWN -- shutdown the logger
                    556: **
                    557: **     This should only be done when the system is going down.
                    558: **
                    559: **     Parameters:
                    560: **             none
                    561: **
                    562: **     Returns:
                    563: **             none
                    564: **
                    565: **     Side Effects:
                    566: **             Starts up an alarm clock, to let other things
                    567: **                     happen.  Alarm clock will call "die".
                    568: **
                    569: **     Called By:
                    570: **             main
                    571: **             signal 15 (terminate)
                    572: */
                    573: 
                    574: shutdown()
                    575: {
                    576:        extern die();
                    577: 
                    578:        logmsg(LOG_CRIT, "syslog: shutdown within 30 seconds\n");
                    579:        ShutDown++;
                    580:        signal(SIGALRM, die);
                    581:        alarm(30);
                    582:        signal(SIGTERM, die);
                    583:        if (Debug)
                    584:                signal(SIGINT, die);
                    585: }
                    586: /*
                    587: **  DIE -- really die.
                    588: **
                    589: **     Parameters:
                    590: **             none
                    591: **
                    592: **     Returns:
                    593: **             never
                    594: **
                    595: **     Side Effects:
                    596: **             Syslog dies.
                    597: **
                    598: **     Requires:
                    599: **             exit (sys)
                    600: **
                    601: **     Called By:
                    602: **             alarm clock (signal 14)
                    603: */
                    604: 
                    605: die()
                    606: {
                    607:        alarm(0);
                    608:        logmsg(LOG_CRIT, "syslog: down\n");
                    609:        sleep(2);       /* wait for output to drain */
                    610: # ifndef LOG_IPC
                    611:        if (!Debug)
                    612:                unlink("/dev/log");
                    613: # endif LOG_IPC
                    614:        sync();
                    615:        exit(0);
                    616: }
                    617: /*
                    618: **  STAMPED -- tell if line is already time stamped.
                    619: **
                    620: **     Accepts time stamps of the form "Sep 13 00:15:17".
                    621: **     Currently just looks for blanks and colons.
                    622: **
                    623: **     Parameters:
                    624: **             l -- the line to check.
                    625: **
                    626: **     Returns:
                    627: **             nonzero -- if the line is time stamped.
                    628: **             zero -- otherwise.
                    629: **
                    630: **     Side Effects:
                    631: **             none.
                    632: */
                    633: 
                    634: stamped(l)
                    635: register char *l;
                    636: {
                    637:        register int i;
                    638: 
                    639:        /* timestamps are at least 15 bytes long */
                    640:        for (i = 0; i < 15; i++)
                    641:                if (l[i] == '\0')
                    642:                        return (0);
                    643: 
                    644:        /* and they have blanks & colons in well-known places */
                    645:        if (l[3] != ' ' || l[6] != ' ' || l[9] != ':' || l[12] != ':')
                    646:                return (0);
                    647:        return (1);
                    648: }
                    649: /*
                    650: **  LOGMSG -- log a message to the outputs
                    651: **
                    652: **     Arranges to get the message to the correct places
                    653: **     based on the priority of the message.  A timestamp
                    654: **     is prepended to the message if one does not already
                    655: **     exist.
                    656: **
                    657: **     Parameters:
                    658: **             pri -- the message priority.
                    659: **             msg -- the message to be logged.
                    660: **
                    661: **     Returns:
                    662: **             none
                    663: **
                    664: **     Side Effects:
                    665: **             possibly messages to all users, or just specific
                    666: **             users.
                    667: */
                    668: 
                    669: logmsg(pri, msg)
                    670:        int     pri;
                    671:        char    *msg;
                    672: {
                    673:        register char *m;
                    674:        register char *p;
                    675:        register struct filed *f;
                    676:        register int l;
                    677:        register int i;
                    678:        char buf[MAXLINE+2];
                    679:        auto int st;
                    680:        auto long now;
                    681:        extern char *ctime();
                    682:        extern int errno;
                    683: 
                    684:        p = buf;
                    685:        l = MAXLINE;
                    686:        
                    687:        /* output a time stamp if one is not already there */
                    688:        time(&now);
                    689:        if (!stamped(msg))
                    690:        {
                    691:                m = &ctime(&now)[4];
                    692:                for (i = 16; i > 0; i--)
                    693:                        *p++ = *m++;
                    694:                l -= 16;
                    695:        }
                    696: 
                    697:        /* find the end of the message */
                    698:        for (m = msg; *m != '\0' &&l -- >= 0; )
                    699:                *p++ = *m++;
                    700:        if (*--m != '\n')
                    701:                *p++ = '\n';
                    702:        
                    703:        /* log the message to the particular outputs */
                    704:        for (i = 0; i < NLOGS; i++)
                    705:        {
                    706:                f = &Files[i];
                    707:                if (f->f_file == NULL)
                    708:                        continue;
                    709:                if (pri < 0)
                    710:                {
                    711:                        if (!f->f_mark || f->f_time + MarkIntvl*60 > now)
                    712:                                continue;
                    713:                }
                    714:                else if (f->f_pmask < pri)
                    715:                        continue;
                    716:                fseek(f->f_file, 0L, 2);
                    717:                errno = 0;
                    718:                fwrite(buf, p - buf, 1, f->f_file);
                    719:                if (f->f_tty)
                    720:                        fwrite("\r", 1, 1, f->f_file);
                    721:                f->f_time = now;
                    722:                fflush(f->f_file);
                    723:                if (ferror(f->f_file))
                    724:                {
                    725:                        char namebuf[40];
                    726: 
                    727:                        fclose(f->f_file);
                    728:                        f->f_file = NULL;
                    729:                        sprintf(namebuf, "write %s", f->f_name);
                    730:                        logerror(namebuf);
                    731:                }
                    732:        }
                    733: 
                    734:        /* let's be paranoid.... */
                    735:        sync();
                    736: 
                    737:        /*
                    738:        **  Output alert and subalert priority messages to terminals.
                    739:        **
                    740:        **      We double fork here so that we can continue.  Our
                    741:        **      child will fork again and die; we wait for him.
                    742:        **      Then process one inherits our grandchildren, we
                    743:        **      can run off and have a good time.  Our grandchild
                    744:        **      actually tries to do the writing (by calling
                    745:        **      wallmsg).
                    746:        **
                    747:        **      Anything go wrong? -- just give up.
                    748:        */
                    749: 
                    750:        if (pri <= LOG_SALERT && pri > 0)
                    751:        {
                    752:                if (fork() == 0)
                    753:                {
                    754:                        if (fork() == 0)
                    755:                        {
                    756:                                wallmsg(pri == LOG_ALERT, buf, p - buf);
                    757:                                exit(0);
                    758:                        }
                    759:                        else
                    760:                                exit(0);
                    761:                }
                    762:                else
                    763:                        while (wait(&st) >= 0)
                    764:                                continue;
                    765:        }
                    766: }
                    767: /*
                    768: **  INIT -- Initialize syslog from configuration table
                    769: **
                    770: **     The configuration table consists of a series of lines
                    771: **     broken into two sections by a blank line.  The first
                    772: **     section gives a list of files to log on.  The first
                    773: **     character is a digit which is the priority mask for
                    774: **     that file.  If the second digit is an asterisk, then
                    775: **     syslog arranges for something to be printed every fifteen
                    776: **     minutes (even if only a null line), so that crashes and
                    777: **     other events can be localized.  The rest of the line is
                    778: **     the pathname of the log file.  The second section is
                    779: **     a list of user names; these people are all notified
                    780: **     when subalert messages occur (if they are logged on).
                    781: **
                    782: **     The configuration table will be reread by this routine
                    783: **     if a signal 1 occurs; for that reason, it is tricky
                    784: **     about not re-opening files and closing files it will
                    785: **     not be using.
                    786: **
                    787: **     Parameters:
                    788: **             none
                    789: **
                    790: **     Returns:
                    791: **             none
                    792: **
                    793: **     Side Effects:
                    794: **             'Files' and 'Susers' are (re)initialized.
                    795: */
                    796: 
                    797: init()
                    798: {
                    799:        register int i;
                    800:        register FILE *cf;
                    801:        char cline[40];
                    802:        register struct filed *f;
                    803:        register char *p;
                    804:        int mark;
                    805:        int pmask;
                    806: 
                    807:        dprintf("init\n");
                    808: 
                    809:        /* ignore interrupts during this routine */
                    810:        signal(SIGHUP, SIG_IGN);
                    811:        logmsg(LOG_INFO, "reinitializing\n");
                    812: 
                    813:        /* open the configuration file */
                    814:        if ((cf = fopen(ConfFile, "r")) == NULL)
                    815:        {
                    816:                dprintf("cannot open %s\n", ConfFile);
                    817:                return;
                    818:        }
                    819: 
                    820:        /*
                    821:        **  Close all open files.
                    822:        */
                    823: 
                    824:        for (f = Files; f < &Files[NLOGS]; f++)
                    825:        {
                    826:                if (f->f_file != NULL)
                    827:                        fclose(f->f_file);
                    828:                f->f_file = NULL;
                    829:        }
                    830: 
                    831:        /*
                    832:        **  Foreach line in the conf table, open that file.
                    833:        */
                    834: 
                    835:        f = Files;
                    836:        while (fgets(cline, sizeof cline, cf) != NULL)
                    837:        {
                    838:                dprintf("F: got line >%s<\n", cline, 0);
                    839:                /* check for end-of-section */
                    840:                if (cline[0] == '\n')
                    841:                        break;
                    842: 
                    843:                /* strip off possible newline character */
                    844:                for (p = cline; *p != '\0' && *p != '\n'; p++)
                    845:                        continue;
                    846:                *p = '\0';
                    847: 
                    848:                /* extract priority mask and mark flag */
                    849:                p = cline;
                    850:                mark = FALSE;
                    851:                pmask = *p++ - '0';
                    852:                if (*p == '*')
                    853:                {
                    854:                        p++;
                    855:                        mark = TRUE;
                    856:                }
                    857: 
                    858:                /* insure that it is null-terminated */
                    859:                p[sizeof Files[0].f_name - 1] = '\0';
                    860: 
                    861:                if (f >= &Files[NLOGS])
                    862:                        continue;
                    863: 
                    864:                /* mark entry as used and update flags */
                    865:                strcpy(f->f_name, p);
                    866:                f->f_file = fopen(p, "a");
                    867:                f->f_time = 0;
                    868:                f->f_pmask = pmask;
                    869:                f->f_mark = mark;
                    870:                f->f_tty = isatty(fileno(f->f_file));
                    871:                dprintf("File %s pmask %d mark %d tty %d\n", p, pmask, mark, f->f_tty);
                    872:                f++;
                    873:        }
                    874: 
                    875:        /*
                    876:        **  Read the list of users.
                    877:        **
                    878:        **      Anyone in this list is informed directly if s/he
                    879:        **      is logged in when a "subalert" or higher priority
                    880:        **      message comes through.
                    881:        **
                    882:        **      Out with the old order, in with the new.
                    883:        */
                    884: 
                    885:        for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++)
                    886:        {
                    887:                /* strip off newline */
                    888:                for (p = cline; *p != '\0' && *p != '\n'; p++)
                    889:                        continue;
                    890:                *p = '\0';
                    891:                cline[8] = '\0';
                    892:                strcpy(Susers[i], cline, 8);
                    893:        }
                    894: 
                    895:        /* zero the rest of the old superusers */
                    896:        for (; i < NSUSERS; i++)
                    897:                Susers[i][0] = '\0';
                    898: 
                    899:        /* close the configuration file */
                    900:        fclose(cf);
                    901: 
                    902:        logmsg(LOG_INFO, "syslog restart\n");
                    903: 
                    904:        /* arrange for signal 1 to reconfigure */
                    905:        signal(SIGHUP, init);
                    906: }
                    907: /*
                    908: **  WALLMSG -- Write a message to the world at large
                    909: **
                    910: **     This writes the specified message to either the entire
                    911: **     world, or at least a list of approved users.
                    912: **
                    913: **     It scans the utmp file.  For each user logged in, it
                    914: **     checks to see if the user is on the approved list, or if
                    915: **     this is an "alert" priority message.  In either case,
                    916: **     it opens a line to that typewriter (unless mesg permission
                    917: **     is denied) and outputs the message to that terminal.
                    918: **
                    919: **     Parameters:
                    920: **             toall -- if non-zero, writes the message to everyone.
                    921: **             msg -- the message to write.
                    922: **             len -- the length of the message.
                    923: **
                    924: **     Returns:
                    925: **             none
                    926: **
                    927: **     Side Effects:
                    928: **             none
                    929: **
                    930: **     Requires:
                    931: **             open(sys)
                    932: **             read(sys)
                    933: **             write(sys)
                    934: **             fstat(sys)
                    935: **             strcmp(sys)
                    936: **             fork(sys)
                    937: **             sleep(sys)
                    938: **             exit(sys)
                    939: **             close(sys)
                    940: **
                    941: **     Called By:
                    942: **             logmsg
                    943: */
                    944: 
                    945: wallmsg(toall, msg, len)
                    946:        int toall;
                    947:        char *msg;
                    948:        int len;
                    949: {
                    950:        struct utmp ut;
                    951:        register int i;
                    952:        register char *p;
                    953:        int uf;
                    954:        struct stat statbuf;
                    955:        auto long t;
                    956:        extern char *ctime();
                    957:        char sbuf[1024];
                    958: #ifdef LOG_IPC
                    959:        extern char *gethostname();
                    960:        char hbuf[32];
                    961:        auto int hlen;
                    962: #endif LOG_IPC
                    963: 
                    964:        /* open the user login file */
                    965:        uf = open("/etc/utmp", 0);
                    966:        if (uf < 0)
                    967:                return;
                    968: 
                    969:        /* scan the user login file */
                    970:        while (read(uf, &ut, sizeof ut) == sizeof ut)
                    971:        {
                    972:                /* is this slot used? */
                    973:                if (ut.ut_name[0] == '\0')
                    974:                        continue;
                    975: 
                    976:                /* if not "alert", check if this user is super */
                    977:                if (!toall)
                    978:                {
                    979:                        for (i = 0; i < NSUSERS; i++)
                    980:                        {
                    981:                                if (namecheck(Susers[i], ut.ut_name))
                    982:                                        break;
                    983:                        }
                    984:                        if (i >= NSUSERS)
                    985:                        {
                    986:                                /* nope, just a serf */
                    987:                                continue;
                    988:                        }
                    989:                }
                    990: 
                    991:                /* fork so that the open can't hang us */
                    992:                if (fork() != 0)
                    993:                        continue;
                    994:                sleep(1);
                    995: 
                    996:                /* compute the device name */
                    997: # ifdef V6
                    998:                p = "/dev/ttyx";
                    999:                p[8] = ut.ut_tty;
                   1000: # else
                   1001:                p = "/dev/12345678";
                   1002:                strcpyn(&p[5], ut.ut_line, 8);
                   1003: # endif
                   1004: 
                   1005:                /* open the terminal */
                   1006:                i = open(p, 1);
                   1007:                if (i < 0)
                   1008:                        exit(1);
                   1009: 
                   1010:                /* does he have write permission? */
                   1011:                if (fstat(i, &statbuf) < 0 || (statbuf.st_mode & 02) == 0)
                   1012:                {
                   1013:                        /* no, just pass him by */
                   1014:                        dprintf("Drop user, mode=%o\n", statbuf.st_mode, 0);
                   1015:                        close(i);
                   1016:                        exit(0);
                   1017:                }
                   1018: 
                   1019:                /* yes, output the message */
                   1020:                time(&t);
                   1021:                strcpy(sbuf, "\r\n\007Broadcast message from ");
                   1022: #ifdef LOG_IPC
                   1023:                strcat(sbuf, "syslog@");
                   1024:                hlen = sizeof hbuf;
                   1025:                gethostname(hbuf, &hlen);
                   1026:                strcat(sbuf, hbuf);
                   1027: #else LOG_IPC
                   1028:                strcat(sbuf, sysname);
                   1029:                strcat(sbuf, "!syslog");
                   1030: #endif LOG_IPC
                   1031:                strcat(sbuf, " at ");
                   1032:                strncat(sbuf, ctime(&t), 24);
                   1033:                strcat(sbuf, "...\r\n");
                   1034:                write(i, sbuf, strlen(sbuf));
                   1035:                p = sbuf;
                   1036:                while (len-- > 0)
                   1037:                {
                   1038:                        *msg &= 0177;
                   1039:                        if (iscntrl(*msg))
                   1040:                        {
                   1041:                                *p++ = '^';
                   1042:                                *p++ = *msg++ ^ 0100;
                   1043:                        }
                   1044:                        else
                   1045:                                *p++ = *msg++;
                   1046:                }
                   1047:                strcpy(p, "\r\n");
                   1048:                write(i, sbuf, strlen(sbuf));
                   1049: 
                   1050:                /* all finished!  go away */
                   1051:                exit(0);
                   1052:        }
                   1053: 
                   1054:        /* close the user login file */
                   1055:        close(uf);
                   1056: }
                   1057: /*
                   1058: **  CHECKNAME -- Do an equality comparison on names.
                   1059: **
                   1060: **     Does right blank padding.
                   1061: **
                   1062: **     Parameters:
                   1063: **             a, b -- pointers to the names to check.
                   1064: **
                   1065: **     Returns:
                   1066: **             1 if equal
                   1067: **             0 otherwise.
                   1068: **
                   1069: **     Side Effects:
                   1070: **             none
                   1071: **
                   1072: **     Requires:
                   1073: **             none
                   1074: **
                   1075: **     Called By:
                   1076: **             wallmsg
                   1077: */
                   1078: 
                   1079: namecheck(a, b)
                   1080: register char *a, *b;
                   1081: {
                   1082:        register int i;
                   1083: 
                   1084:        for (i = 0; i < 8; i++)
                   1085:        {
                   1086:                if (*a != *b)
                   1087:                {
                   1088:                        if (!((*a == ' ' && *b == '\0') || (*a == '\0' && *b == ' ')))
                   1089:                                return (0);
                   1090:                }
                   1091:                if (*a != ' ' && *a != '\0')
                   1092:                        a++;
                   1093:                if (*b != ' ' && *b != '\0')
                   1094:                        b++;
                   1095:        }
                   1096:        return (1);
                   1097: }
                   1098: /*
                   1099: **  DOMARK -- Make sure every marked file gets output every 15 minutes
                   1100: **
                   1101: **     Just calls "logmsg" with a negative priority every time it
                   1102: **     gets called.
                   1103: **
                   1104: **     Algorithm:
                   1105: **             create timestamp.
                   1106: **             call logmsg.
                   1107: **
                   1108: **     Parameters:
                   1109: **             none
                   1110: **
                   1111: **     Returns:
                   1112: **             none
                   1113: **
                   1114: **     Side Effects:
                   1115: **             sets the alarm clock to call itself after MarkIntvl
                   1116: **                     minutes.
                   1117: **
                   1118: **     Requires:
                   1119: **             logmsg
                   1120: **
                   1121: **     Called By:
                   1122: **             system alarm clock.
                   1123: **             init
                   1124: */
                   1125: 
                   1126: domark()
                   1127: {
                   1128:        auto long t;
                   1129:        extern char *ctime();
                   1130:        register char *p;
                   1131:        register char *q;
                   1132:        char buf[40];
                   1133: 
                   1134:        alarm(0);
                   1135:        dprintf("domark\n");
                   1136:        time(&t);
                   1137:        q = buf;
                   1138:        for (p = " --- MARK --- "; (*q++ = *p++) != '\0'; )
                   1139:                continue;
                   1140:        q--;
                   1141:        for (p = ctime(&t); (*q++ = *p++) != '\0'; )
                   1142:                continue;
                   1143:        logmsg(-1, buf);
                   1144:        signal(SIGALRM, domark);
                   1145:        alarm(MarkIntvl*60);
                   1146: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.