home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / syslogd / syslogd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  25.3 KB  |  1,121 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)syslogd.c    5.45 (Berkeley) 3/2/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  *  syslogd -- log system messages
  46.  *
  47.  * This program implements a system log. It takes a series of lines.
  48.  * Each line may have a priority, signified as "<n>" as
  49.  * the first characters of the line.  If this is
  50.  * not present, a default priority is used.
  51.  *
  52.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  53.  * cause it to reread its configuration file.
  54.  *
  55.  * Defined Constants:
  56.  *
  57.  * MAXLINE -- the maximimum line length that can be handled.
  58.  * DEFUPRI -- the default priority for user messages
  59.  * DEFSPRI -- the default priority for kernel messages
  60.  *
  61.  * Author: Eric Allman
  62.  * extensive changes by Ralph Campbell
  63.  * more extensive changes by Eric Allman (again)
  64.  */
  65.  
  66. #define    MAXLINE        1024        /* maximum line length */
  67. #define    MAXSVLINE    120        /* maximum saved line length */
  68. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  69. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  70. #define TIMERINTVL    30        /* interval for checking flush, mark */
  71.  
  72. #include <sys/param.h>
  73. #include <sys/errno.h>
  74. #include <sys/ioctl.h>
  75. #include <sys/stat.h>
  76. #include <sys/wait.h>
  77. #include <sys/socket.h>
  78. #include <sys/file.h>
  79. #include <sys/msgbuf.h>
  80. #include <sys/uio.h>
  81. #include <sys/un.h>
  82. #include <sys/time.h>
  83. #include <sys/resource.h>
  84. #include <sys/signal.h>
  85.  
  86. #include <netinet/in.h>
  87. #include <netdb.h>
  88.  
  89. #include <utmp.h>
  90. #include <setjmp.h>
  91. #include <stdio.h>
  92. #include <ctype.h>
  93. #include <string.h>
  94. #include <unistd.h>
  95. #include "pathnames.h"
  96.  
  97. #define SYSLOG_NAMES
  98. #include <sys/syslog.h>
  99.  
  100. char    *LogName = _PATH_LOG;
  101. char    *ConfFile = _PATH_LOGCONF;
  102. char    *PidFile = _PATH_LOGPID;
  103. char    ctty[] = _PATH_CONSOLE;
  104.  
  105. #define FDMASK(fd)    (1 << (fd))
  106.  
  107. #define    dprintf        if (Debug) printf
  108.  
  109. #define MAXUNAMES    20    /* maximum number of user names */
  110.  
  111. /*
  112.  * Flags to logmsg().
  113.  */
  114.  
  115. #define IGN_CONS    0x001    /* don't print on console */
  116. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  117. #define ADDDATE        0x004    /* add a date to the message */
  118. #define MARK        0x008    /* this message is a mark */
  119.  
  120. /*
  121.  * This structure represents the files that will have log
  122.  * copies printed.
  123.  */
  124.  
  125. struct filed {
  126.     struct    filed *f_next;        /* next in linked list */
  127.     short    f_type;            /* entry type, see below */
  128.     short    f_file;            /* file descriptor */
  129.     time_t    f_time;            /* time this was last written */
  130.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  131.     union {
  132.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  133.         struct {
  134.             char    f_hname[MAXHOSTNAMELEN+1];
  135.             struct sockaddr_in    f_addr;
  136.         } f_forw;        /* forwarding address */
  137.         char    f_fname[MAXPATHLEN];
  138.     } f_un;
  139.     char    f_prevline[MAXSVLINE];        /* last message logged */
  140.     char    f_lasttime[16];            /* time of last occurrence */
  141.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  142.     int    f_prevpri;            /* pri of f_prevline */
  143.     int    f_prevlen;            /* length of f_prevline */
  144.     int    f_prevcount;            /* repetition cnt of prevline */
  145.     int    f_repeatcount;            /* number of "repeated" msgs */
  146. };
  147.  
  148. /*
  149.  * Intervals at which we flush out "message repeated" messages,
  150.  * in seconds after previous message is logged.  After each flush,
  151.  * we move to the next interval until we reach the largest.
  152.  */
  153. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  154. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  155. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  156. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  157.                  (f)->f_repeatcount = MAXREPEAT; \
  158.             }
  159.  
  160. /* values for f_type */
  161. #define F_UNUSED    0        /* unused entry */
  162. #define F_FILE        1        /* regular file */
  163. #define F_TTY        2        /* terminal */
  164. #define F_CONSOLE    3        /* console terminal */
  165. #define F_FORW        4        /* remote machine */
  166. #define F_USERS        5        /* list of users */
  167. #define F_WALL        6        /* everyone logged on */
  168.  
  169. char    *TypeNames[7] = {
  170.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  171.     "FORW",        "USERS",    "WALL"
  172. };
  173.  
  174. struct    filed *Files;
  175. struct    filed consfile;
  176.  
  177. int    Debug;            /* debug flag */
  178. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  179. char    *LocalDomain;        /* our local domain name */
  180. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  181. int    finet;            /* Internet datagram socket */
  182. int    LogPort;        /* port number for INET connections */
  183. int    Initialized = 0;    /* set when we have initialized ourselves */
  184. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  185. int    MarkSeq = 0;        /* mark sequence number */
  186.  
  187. extern    int errno;
  188. extern    char *ctime(), *index(), *calloc();
  189.  
  190. main(argc, argv)
  191.     int argc;
  192.     char **argv;
  193. {
  194.     register int i;
  195.     register char *p;
  196.     int funix, inetm, fklog, klogm, len;
  197.     struct sockaddr_un sunx, fromunix;
  198.     struct sockaddr_in sin, frominet;
  199.     FILE *fp;
  200.     int ch;
  201.     char line[MSG_BSIZE + 1];
  202.     extern int optind;
  203.     extern char *optarg;
  204.     void die(), domark(), init(), reapchild();
  205.  
  206.     while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
  207.         switch((char)ch) {
  208.         case 'd':        /* debug */
  209.             Debug++;
  210.             break;
  211.         case 'f':        /* configuration file */
  212.             ConfFile = optarg;
  213.             break;
  214.         case 'm':        /* mark interval */
  215.             MarkInterval = atoi(optarg) * 60;
  216.             break;
  217.         case 'p':        /* path */
  218.             LogName = optarg;
  219.             break;
  220.         case '?':
  221.         default:
  222.             usage();
  223.         }
  224.     if (argc -= optind)
  225.         usage();
  226.  
  227.     if (!Debug)
  228.         daemon(0, 0);
  229.     else
  230.         setlinebuf(stdout);
  231.  
  232.     consfile.f_type = F_CONSOLE;
  233.     (void) strcpy(consfile.f_un.f_fname, ctty);
  234.     (void) gethostname(LocalHostName, sizeof LocalHostName);
  235.     if (p = index(LocalHostName, '.')) {
  236.         *p++ = '\0';
  237.         LocalDomain = p;
  238.     }
  239.     else
  240.         LocalDomain = "";
  241.     (void) signal(SIGTERM, die);
  242.     (void) signal(SIGINT, Debug ? die : SIG_IGN);
  243.     (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
  244.     (void) signal(SIGCHLD, reapchild);
  245.     (void) signal(SIGALRM, domark);
  246.     (void) alarm(TIMERINTVL);
  247.     (void) unlink(LogName);
  248.  
  249.     bzero((char *)&sunx, sizeof(sunx));
  250.     sunx.sun_family = AF_UNIX;
  251.     (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
  252.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  253.     if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
  254.         sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
  255.         strlen(sunx.sun_path)) < 0 ||
  256.         chmod(LogName, 0666) < 0) {
  257.         (void) sprintf(line, "cannot create %s", LogName);
  258.         logerror(line);
  259.         dprintf("cannot create %s (%d)\n", LogName, errno);
  260.         die(0);
  261.     }
  262.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  263.     if (finet >= 0) {
  264.         struct servent *sp;
  265.  
  266.         sp = getservbyname("syslog", "udp");
  267.         if (sp == NULL) {
  268.             errno = 0;
  269.             logerror("syslog/udp: unknown service");
  270.             die(0);
  271.         }
  272.         sin.sin_family = AF_INET;
  273.         sin.sin_port = LogPort = sp->s_port;
  274.         if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  275.             logerror("bind");
  276.             if (!Debug)
  277.                 die(0);
  278.         } else {
  279.             inetm = FDMASK(finet);
  280.             InetInuse = 1;
  281.         }
  282.     }
  283.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
  284.         klogm = FDMASK(fklog);
  285.     else {
  286.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  287.         klogm = 0;
  288.     }
  289.  
  290.     /* tuck my process id away */
  291.     fp = fopen(PidFile, "w");
  292.     if (fp != NULL) {
  293.         fprintf(fp, "%d\n", getpid());
  294.         (void) fclose(fp);
  295.     }
  296.  
  297.     dprintf("off & running....\n");
  298.  
  299.     init();
  300.     (void) signal(SIGHUP, init);
  301.  
  302.     for (;;) {
  303.         int nfds, readfds = FDMASK(funix) | inetm | klogm;
  304.  
  305.         errno = 0;
  306.         dprintf("readfds = %#x\n", readfds);
  307.         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
  308.             (fd_set *) NULL, (struct timeval *) NULL);
  309.         if (nfds == 0)
  310.             continue;
  311.         if (nfds < 0) {
  312.             if (errno != EINTR)
  313.                 logerror("select");
  314.             continue;
  315.         }
  316.         dprintf("got a message (%d, %#x)\n", nfds, readfds);
  317.         if (readfds & klogm) {
  318.             i = read(fklog, line, sizeof(line) - 1);
  319.             if (i > 0) {
  320.                 line[i] = '\0';
  321.                 printsys(line);
  322.             } else if (i < 0 && errno != EINTR) {
  323.                 logerror("klog");
  324.                 fklog = -1;
  325.                 klogm = 0;
  326.             }
  327.         }
  328.         if (readfds & FDMASK(funix)) {
  329.             len = sizeof fromunix;
  330.             i = recvfrom(funix, line, MAXLINE, 0,
  331.                 (struct sockaddr *) &fromunix, &len);
  332.             if (i > 0) {
  333.                 line[i] = '\0';
  334.                 printline(LocalHostName, line);
  335.             } else if (i < 0 && errno != EINTR)
  336.                 logerror("recvfrom unix");
  337.         }
  338.         if (readfds & inetm) {
  339.             len = sizeof frominet;
  340.             i = recvfrom(finet, line, MAXLINE, 0,
  341.                 (struct sockaddr *) &frominet, &len);
  342.             if (i > 0) {
  343.                 extern char *cvthname();
  344.  
  345.                 line[i] = '\0';
  346.                 printline(cvthname(&frominet), line);
  347.             } else if (i < 0 && errno != EINTR)
  348.                 logerror("recvfrom inet");
  349.         } 
  350.     }
  351. }
  352.  
  353. usage()
  354. {
  355.     (void) fprintf(stderr,
  356.         "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
  357.     exit(1);
  358. }
  359.  
  360. /*
  361.  * Take a raw input line, decode the message, and print the message
  362.  * on the appropriate log files.
  363.  */
  364.  
  365. printline(hname, msg)
  366.     char *hname;
  367.     char *msg;
  368. {
  369.     register char *p, *q;
  370.     register int c;
  371.     char line[MAXLINE + 1];
  372.     int pri;
  373.  
  374.     /* test for special codes */
  375.     pri = DEFUPRI;
  376.     p = msg;
  377.     if (*p == '<') {
  378.         pri = 0;
  379.         while (isdigit(*++p))
  380.             pri = 10 * pri + (*p - '0');
  381.         if (*p == '>')
  382.             ++p;
  383.     }
  384.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  385.         pri = DEFUPRI;
  386.  
  387.     /* don't allow users to log kernel messages */
  388.     if (LOG_FAC(pri) == LOG_KERN)
  389.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  390.  
  391.     q = line;
  392.  
  393.     while ((c = *p++ & 0177) != '\0' &&
  394.         q < &line[sizeof(line) - 1])
  395.         if (iscntrl(c))
  396.             if (c == '\n')
  397.                 *q++ = ' ';
  398.             else if (c == '\t')
  399.                 *q++ = '\t';
  400.             else {
  401.                 *q++ = '^';
  402.                 *q++ = c ^ 0100;
  403.             }
  404.         else
  405.             *q++ = c;
  406.     *q = '\0';
  407.  
  408.     logmsg(pri, line, hname, 0);
  409. }
  410.  
  411. /*
  412.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  413.  */
  414.  
  415. printsys(msg)
  416.     char *msg;
  417. {
  418.     register char *p, *q;
  419.     register int c;
  420.     char line[MAXLINE + 1];
  421.     int pri, flags;
  422.     char *lp;
  423.  
  424.     (void) strcpy(line, "vmunix: ");
  425.     lp = line + strlen(line);
  426.     for (p = msg; *p != '\0'; ) {
  427.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  428.         pri = DEFSPRI;
  429.         if (*p == '<') {
  430.             pri = 0;
  431.             while (isdigit(*++p))
  432.                 pri = 10 * pri + (*p - '0');
  433.             if (*p == '>')
  434.                 ++p;
  435.         } else {
  436.             /* kernel printf's come out on console */
  437.             flags |= IGN_CONS;
  438.         }
  439.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  440.             pri = DEFSPRI;
  441.         q = lp;
  442.         while (*p != '\0' && (c = *p++) != '\n' &&
  443.             q < &line[MAXLINE])
  444.             *q++ = c;
  445.         *q = '\0';
  446.         logmsg(pri, line, LocalHostName, flags);
  447.     }
  448. }
  449.  
  450. time_t    now;
  451.  
  452. /*
  453.  * Log a message to the appropriate log files, users, etc. based on
  454.  * the priority.
  455.  */
  456.  
  457. logmsg(pri, msg, from, flags)
  458.     int pri;
  459.     char *msg, *from;
  460.     int flags;
  461. {
  462.     register struct filed *f;
  463.     int fac, prilev;
  464.     int omask, msglen;
  465.     char *timestamp;
  466.     time_t time();
  467.  
  468.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  469.         pri, flags, from, msg);
  470.  
  471.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  472.  
  473.     /*
  474.      * Check to see if msg looks non-standard.
  475.      */
  476.     msglen = strlen(msg);
  477.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  478.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  479.         flags |= ADDDATE;
  480.  
  481.     (void) time(&now);
  482.     if (flags & ADDDATE)
  483.         timestamp = ctime(&now) + 4;
  484.     else {
  485.         timestamp = msg;
  486.         msg += 16;
  487.         msglen -= 16;
  488.     }
  489.  
  490.     /* extract facility and priority level */
  491.     if (flags & MARK)
  492.         fac = LOG_NFACILITIES;
  493.     else
  494.         fac = LOG_FAC(pri);
  495.     prilev = LOG_PRI(pri);
  496.  
  497.     /* log the message to the particular outputs */
  498.     if (!Initialized) {
  499.         f = &consfile;
  500.         f->f_file = open(ctty, O_WRONLY, 0);
  501.  
  502.         if (f->f_file >= 0) {
  503.             fprintlog(f, flags, msg);
  504.             (void) close(f->f_file);
  505.         }
  506.         (void) sigsetmask(omask);
  507.         return;
  508.     }
  509.     for (f = Files; f; f = f->f_next) {
  510.         /* skip messages that are incorrect priority */
  511.         if (f->f_pmask[fac] < prilev ||
  512.             f->f_pmask[fac] == INTERNAL_NOPRI)
  513.             continue;
  514.  
  515.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  516.             continue;
  517.  
  518.         /* don't output marks to recently written files */
  519.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  520.             continue;
  521.  
  522.         /*
  523.          * suppress duplicate lines to this file
  524.          */
  525.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  526.             !strcmp(msg, f->f_prevline) &&
  527.             !strcmp(from, f->f_prevhost)) {
  528.             (void) strncpy(f->f_lasttime, timestamp, 15);
  529.             f->f_prevcount++;
  530.             dprintf("msg repeated %d times, %ld sec of %d\n",
  531.                 f->f_prevcount, now - f->f_time,
  532.                 repeatinterval[f->f_repeatcount]);
  533.             /*
  534.              * If domark would have logged this by now,
  535.              * flush it now (so we don't hold isolated messages),
  536.              * but back off so we'll flush less often
  537.              * in the future.
  538.              */
  539.             if (now > REPEATTIME(f)) {
  540.                 fprintlog(f, flags, (char *)NULL);
  541.                 BACKOFF(f);
  542.             }
  543.         } else {
  544.             /* new line, save it */
  545.             if (f->f_prevcount)
  546.                 fprintlog(f, 0, (char *)NULL);
  547.             f->f_repeatcount = 0;
  548.             (void) strncpy(f->f_lasttime, timestamp, 15);
  549.             (void) strncpy(f->f_prevhost, from,
  550.                     sizeof(f->f_prevhost));
  551.             if (msglen < MAXSVLINE) {
  552.                 f->f_prevlen = msglen;
  553.                 f->f_prevpri = pri;
  554.                 (void) strcpy(f->f_prevline, msg);
  555.                 fprintlog(f, flags, (char *)NULL);
  556.             } else {
  557.                 f->f_prevline[0] = 0;
  558.                 f->f_prevlen = 0;
  559.                 fprintlog(f, flags, msg);
  560.             }
  561.         }
  562.     }
  563.     (void) sigsetmask(omask);
  564. }
  565.  
  566. fprintlog(f, flags, msg)
  567.     register struct filed *f;
  568.     int flags;
  569.     char *msg;
  570. {
  571.     struct iovec iov[6];
  572.     register struct iovec *v;
  573.     register int l;
  574.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  575.  
  576.     v = iov;
  577.     if (f->f_type == F_WALL) {
  578.         v->iov_base = greetings;
  579.         v->iov_len = sprintf(greetings,
  580.             "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  581.             f->f_prevhost, ctime(&now));
  582.         v++;
  583.         v->iov_base = "";
  584.         v->iov_len = 0;
  585.         v++;
  586.     } else {
  587.         v->iov_base = f->f_lasttime;
  588.         v->iov_len = 15;
  589.         v++;
  590.         v->iov_base = " ";
  591.         v->iov_len = 1;
  592.         v++;
  593.     }
  594.     v->iov_base = f->f_prevhost;
  595.     v->iov_len = strlen(v->iov_base);
  596.     v++;
  597.     v->iov_base = " ";
  598.     v->iov_len = 1;
  599.     v++;
  600.  
  601.     if (msg) {
  602.         v->iov_base = msg;
  603.         v->iov_len = strlen(msg);
  604.     } else if (f->f_prevcount > 1) {
  605.         v->iov_base = repbuf;
  606.         v->iov_len = sprintf(repbuf, "last message repeated %d times",
  607.             f->f_prevcount);
  608.     } else {
  609.         v->iov_base = f->f_prevline;
  610.         v->iov_len = f->f_prevlen;
  611.     }
  612.     v++;
  613.  
  614.     dprintf("Logging to %s", TypeNames[f->f_type]);
  615.     f->f_time = now;
  616.  
  617.     switch (f->f_type) {
  618.     case F_UNUSED:
  619.         dprintf("\n");
  620.         break;
  621.  
  622.     case F_FORW:
  623.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  624.         l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
  625.             iov[0].iov_base, iov[4].iov_base);
  626.         if (l > MAXLINE)
  627.             l = MAXLINE;
  628.         if (sendto(finet, line, l, 0,
  629.             (struct sockaddr *)&f->f_un.f_forw.f_addr,
  630.             sizeof f->f_un.f_forw.f_addr) != l) {
  631.             int e = errno;
  632.             (void) close(f->f_file);
  633.             f->f_type = F_UNUSED;
  634.             errno = e;
  635.             logerror("sendto");
  636.         }
  637.         break;
  638.  
  639.     case F_CONSOLE:
  640.         if (flags & IGN_CONS) {
  641.             dprintf(" (ignored)\n");
  642.             break;
  643.         }
  644.         /* FALLTHROUGH */
  645.  
  646.     case F_TTY:
  647.     case F_FILE:
  648.         dprintf(" %s\n", f->f_un.f_fname);
  649.         if (f->f_type != F_FILE) {
  650.             v->iov_base = "\r\n";
  651.             v->iov_len = 2;
  652.         } else {
  653.             v->iov_base = "\n";
  654.             v->iov_len = 1;
  655.         }
  656.     again:
  657.         if (writev(f->f_file, iov, 6) < 0) {
  658.             int e = errno;
  659.             (void) close(f->f_file);
  660.             /*
  661.              * Check for errors on TTY's due to loss of tty
  662.              */
  663.             if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
  664.                 f->f_file = open(f->f_un.f_fname,
  665.                     O_WRONLY|O_APPEND, 0);
  666.                 if (f->f_file < 0) {
  667.                     f->f_type = F_UNUSED;
  668.                     logerror(f->f_un.f_fname);
  669.                 } else
  670.                     goto again;
  671.             } else {
  672.                 f->f_type = F_UNUSED;
  673.                 errno = e;
  674.                 logerror(f->f_un.f_fname);
  675.             }
  676.         } else if (flags & SYNC_FILE)
  677.             (void) fsync(f->f_file);
  678.         break;
  679.  
  680.     case F_USERS:
  681.     case F_WALL:
  682.         dprintf("\n");
  683.         v->iov_base = "\r\n";
  684.         v->iov_len = 2;
  685.         wallmsg(f, iov);
  686.         break;
  687.     }
  688.     f->f_prevcount = 0;
  689. }
  690.  
  691. /*
  692.  *  WALLMSG -- Write a message to the world at large
  693.  *
  694.  *    Write the specified message to either the entire
  695.  *    world, or a list of approved users.
  696.  */
  697.  
  698. wallmsg(f, iov)
  699.     register struct filed *f;
  700.     struct iovec *iov;
  701. {
  702.     static int reenter;            /* avoid calling ourselves */
  703.     register FILE *uf;
  704.     register int i;
  705.     struct utmp ut;
  706.     char *p, *ttymsg();
  707.  
  708.     if (reenter++)
  709.         return;
  710.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  711.         logerror(_PATH_UTMP);
  712.         reenter = 0;
  713.         return;
  714.     }
  715.     /* NOSTRICT */
  716.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  717.         if (ut.ut_name[0] == '\0')
  718.             continue;
  719.         if (f->f_type == F_WALL) {
  720.             if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  721.                 errno = 0;    /* already in msg */
  722.                 logerror(p);
  723.             }
  724.             continue;
  725.         }
  726.         /* should we send the message to this user? */
  727.         for (i = 0; i < MAXUNAMES; i++) {
  728.             if (!f->f_un.f_uname[i][0])
  729.                 break;
  730.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  731.                 UT_NAMESIZE)) {
  732.                 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  733.                     errno = 0;    /* already in msg */
  734.                     logerror(p);
  735.                 }
  736.                 break;
  737.             }
  738.         }
  739.     }
  740.     (void) fclose(uf);
  741.     reenter = 0;
  742. }
  743.  
  744. void
  745. reapchild()
  746. {
  747.     union wait status;
  748.  
  749.     while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
  750.         ;
  751. }
  752.  
  753. /*
  754.  * Return a printable representation of a host address.
  755.  */
  756. char *
  757. cvthname(f)
  758.     struct sockaddr_in *f;
  759. {
  760.     struct hostent *hp;
  761.     register char *p;
  762.     extern char *inet_ntoa();
  763.  
  764.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  765.  
  766.     if (f->sin_family != AF_INET) {
  767.         dprintf("Malformed from address\n");
  768.         return ("???");
  769.     }
  770.     hp = gethostbyaddr((char *)&f->sin_addr,
  771.         sizeof(struct in_addr), f->sin_family);
  772.     if (hp == 0) {
  773.         dprintf("Host name for your address (%s) unknown\n",
  774.             inet_ntoa(f->sin_addr));
  775.         return (inet_ntoa(f->sin_addr));
  776.     }
  777.     if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  778.         *p = '\0';
  779.     return (hp->h_name);
  780. }
  781.  
  782. void
  783. domark()
  784. {
  785.     register struct filed *f;
  786.     time_t time();
  787.  
  788.     now = time((time_t *)NULL);
  789.     MarkSeq += TIMERINTVL;
  790.     if (MarkSeq >= MarkInterval) {
  791.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  792.         MarkSeq = 0;
  793.     }
  794.  
  795.     for (f = Files; f; f = f->f_next) {
  796.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  797.             dprintf("flush %s: repeated %d times, %d sec.\n",
  798.                 TypeNames[f->f_type], f->f_prevcount,
  799.                 repeatinterval[f->f_repeatcount]);
  800.             fprintlog(f, 0, (char *)NULL);
  801.             BACKOFF(f);
  802.         }
  803.     }
  804.     (void) alarm(TIMERINTVL);
  805. }
  806.  
  807. /*
  808.  * Print syslogd errors some place.
  809.  */
  810. logerror(type)
  811.     char *type;
  812. {
  813.     char buf[100], *strerror();
  814.  
  815.     if (errno)
  816.         (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
  817.     else
  818.         (void) sprintf(buf, "syslogd: %s", type);
  819.     errno = 0;
  820.     dprintf("%s\n", buf);
  821.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  822. }
  823.  
  824. void
  825. die(sig)
  826. {
  827.     register struct filed *f;
  828.     char buf[100];
  829.  
  830.     for (f = Files; f != NULL; f = f->f_next) {
  831.         /* flush any pending output */
  832.         if (f->f_prevcount)
  833.             fprintlog(f, 0, (char *)NULL);
  834.     }
  835.     if (sig) {
  836.         dprintf("syslogd: exiting on signal %d\n", sig);
  837.         (void) sprintf(buf, "exiting on signal %d", sig);
  838.         errno = 0;
  839.         logerror(buf);
  840.     }
  841.     (void) unlink(LogName);
  842.     exit(0);
  843. }
  844.  
  845. /*
  846.  *  INIT -- Initialize syslogd from configuration table
  847.  */
  848.  
  849. void
  850. init()
  851. {
  852.     register int i;
  853.     register FILE *cf;
  854.     register struct filed *f, *next, **nextp;
  855.     register char *p;
  856.     char cline[BUFSIZ];
  857.  
  858.     dprintf("init\n");
  859.  
  860.     /*
  861.      *  Close all open log files.
  862.      */
  863.     Initialized = 0;
  864.     for (f = Files; f != NULL; f = next) {
  865.         /* flush any pending output */
  866.         if (f->f_prevcount)
  867.             fprintlog(f, 0, (char *)NULL);
  868.  
  869.         switch (f->f_type) {
  870.           case F_FILE:
  871.           case F_TTY:
  872.           case F_CONSOLE:
  873.           case F_FORW:
  874.             (void) close(f->f_file);
  875.             break;
  876.         }
  877.         next = f->f_next;
  878.         free((char *) f);
  879.     }
  880.     Files = NULL;
  881.     nextp = &Files;
  882.  
  883.     /* open the configuration file */
  884.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  885.         dprintf("cannot open %s\n", ConfFile);
  886.         *nextp = (struct filed *)calloc(1, sizeof(*f));
  887.         cfline("*.ERR\t/dev/console", *nextp);
  888.         (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
  889.         cfline("*.PANIC\t*", (*nextp)->f_next);
  890.         Initialized = 1;
  891.         return;
  892.     }
  893.  
  894.     /*
  895.      *  Foreach line in the conf table, open that file.
  896.      */
  897.     f = NULL;
  898.     while (fgets(cline, sizeof cline, cf) != NULL) {
  899.         /*
  900.          * check for end-of-section, comments, strip off trailing
  901.          * spaces and newline character.
  902.          */
  903.         for (p = cline; isspace(*p); ++p);
  904.         if (*p == NULL || *p == '#')
  905.             continue;
  906.         for (p = index(cline, '\0'); isspace(*--p););
  907.         *++p = '\0';
  908.         f = (struct filed *)calloc(1, sizeof(*f));
  909.         *nextp = f;
  910.         nextp = &f->f_next;
  911.         cfline(cline, f);
  912.     }
  913.  
  914.     /* close the configuration file */
  915.     (void) fclose(cf);
  916.  
  917.     Initialized = 1;
  918.  
  919.     if (Debug) {
  920.         for (f = Files; f; f = f->f_next) {
  921.             for (i = 0; i <= LOG_NFACILITIES; i++)
  922.                 if (f->f_pmask[i] == INTERNAL_NOPRI)
  923.                     printf("X ");
  924.                 else
  925.                     printf("%d ", f->f_pmask[i]);
  926.             printf("%s: ", TypeNames[f->f_type]);
  927.             switch (f->f_type) {
  928.             case F_FILE:
  929.             case F_TTY:
  930.             case F_CONSOLE:
  931.                 printf("%s", f->f_un.f_fname);
  932.                 break;
  933.  
  934.             case F_FORW:
  935.                 printf("%s", f->f_un.f_forw.f_hname);
  936.                 break;
  937.  
  938.             case F_USERS:
  939.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  940.                     printf("%s, ", f->f_un.f_uname[i]);
  941.                 break;
  942.             }
  943.             printf("\n");
  944.         }
  945.     }
  946.  
  947.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  948.     dprintf("syslogd: restarted\n");
  949. }
  950.  
  951. /*
  952.  * Crack a configuration file line
  953.  */
  954.  
  955. cfline(line, f)
  956.     char *line;
  957.     register struct filed *f;
  958. {
  959.     register char *p;
  960.     register char *q;
  961.     register int i;
  962.     char *bp;
  963.     int pri;
  964.     struct hostent *hp;
  965.     char buf[MAXLINE], ebuf[100];
  966.  
  967.     dprintf("cfline(%s)\n", line);
  968.  
  969.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  970.  
  971.     /* clear out file entry */
  972.     bzero((char *) f, sizeof *f);
  973.     for (i = 0; i <= LOG_NFACILITIES; i++)
  974.         f->f_pmask[i] = INTERNAL_NOPRI;
  975.  
  976.     /* scan through the list of selectors */
  977.     for (p = line; *p && *p != '\t';) {
  978.  
  979.         /* find the end of this facility name list */
  980.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  981.             continue;
  982.  
  983.         /* collect priority name */
  984.         for (bp = buf; *q && !index("\t,;", *q); )
  985.             *bp++ = *q++;
  986.         *bp = '\0';
  987.  
  988.         /* skip cruft */
  989.         while (index(", ;", *q))
  990.             q++;
  991.  
  992.         /* decode priority name */
  993.         if (*buf == '*')
  994.             pri = LOG_PRIMASK + 1;
  995.         else {
  996.             pri = decode(buf, prioritynames);
  997.             if (pri < 0) {
  998.                 (void) sprintf(ebuf,
  999.                     "unknown priority name \"%s\"", buf);
  1000.                 logerror(ebuf);
  1001.                 return;
  1002.             }
  1003.         }
  1004.  
  1005.         /* scan facilities */
  1006.         while (*p && !index("\t.;", *p)) {
  1007.             for (bp = buf; *p && !index("\t,;.", *p); )
  1008.                 *bp++ = *p++;
  1009.             *bp = '\0';
  1010.             if (*buf == '*')
  1011.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1012.                     f->f_pmask[i] = pri;
  1013.             else {
  1014.                 i = decode(buf, facilitynames);
  1015.                 if (i < 0) {
  1016.                     (void) sprintf(ebuf,
  1017.                         "unknown facility name \"%s\"",
  1018.                         buf);
  1019.                     logerror(ebuf);
  1020.                     return;
  1021.                 }
  1022.                 f->f_pmask[i >> 3] = pri;
  1023.             }
  1024.             while (*p == ',' || *p == ' ')
  1025.                 p++;
  1026.         }
  1027.  
  1028.         p = q;
  1029.     }
  1030.  
  1031.     /* skip to action part */
  1032.     while (*p == '\t')
  1033.         p++;
  1034.  
  1035.     switch (*p)
  1036.     {
  1037.     case '@':
  1038.         if (!InetInuse)
  1039.             break;
  1040.         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
  1041.         hp = gethostbyname(p);
  1042.         if (hp == NULL) {
  1043.             extern int h_errno, h_nerr;
  1044.             extern char **h_errlist;
  1045.  
  1046.             logerror((u_int)h_errno < h_nerr ?
  1047.                 h_errlist[h_errno] : "Unknown error");
  1048.             break;
  1049.         }
  1050.         bzero((char *) &f->f_un.f_forw.f_addr,
  1051.              sizeof f->f_un.f_forw.f_addr);
  1052.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1053.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1054.         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
  1055.         f->f_type = F_FORW;
  1056.         break;
  1057.  
  1058.     case '/':
  1059.         (void) strcpy(f->f_un.f_fname, p);
  1060.         if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
  1061.             f->f_file = F_UNUSED;
  1062.             logerror(p);
  1063.             break;
  1064.         }
  1065.         if (isatty(f->f_file))
  1066.             f->f_type = F_TTY;
  1067.         else
  1068.             f->f_type = F_FILE;
  1069.         if (strcmp(p, ctty) == 0)
  1070.             f->f_type = F_CONSOLE;
  1071.         break;
  1072.  
  1073.     case '*':
  1074.         f->f_type = F_WALL;
  1075.         break;
  1076.  
  1077.     default:
  1078.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1079.             for (q = p; *q && *q != ','; )
  1080.                 q++;
  1081.             (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1082.             if ((q - p) > UT_NAMESIZE)
  1083.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1084.             else
  1085.                 f->f_un.f_uname[i][q - p] = '\0';
  1086.             while (*q == ',' || *q == ' ')
  1087.                 q++;
  1088.             p = q;
  1089.         }
  1090.         f->f_type = F_USERS;
  1091.         break;
  1092.     }
  1093. }
  1094.  
  1095.  
  1096. /*
  1097.  *  Decode a symbolic name to a numeric value
  1098.  */
  1099.  
  1100. decode(name, codetab)
  1101.     char *name;
  1102.     CODE *codetab;
  1103. {
  1104.     register CODE *c;
  1105.     register char *p;
  1106.     char buf[40];
  1107.  
  1108.     if (isdigit(*name))
  1109.         return (atoi(name));
  1110.  
  1111.     (void) strcpy(buf, name);
  1112.     for (p = buf; *p; p++)
  1113.         if (isupper(*p))
  1114.             *p = tolower(*p);
  1115.     for (c = codetab; c->c_name; c++)
  1116.         if (!strcmp(buf, c->c_name))
  1117.             return (c->c_val);
  1118.  
  1119.     return (-1);
  1120. }
  1121.