home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / syslogd / syslogd.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-22  |  26.1 KB  |  1,162 lines

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