Annotation of 42BSD/usr.lib/sendmail/aux/syslog.c, revision 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.