home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / syslog2b.zip / syslogd1.c < prev   
C/C++ Source or Header  |  1995-09-25  |  33KB  |  1,407 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.  * Wed Sep 14 21:56:59 1994: Applied patches from Alan Modra
  34.  * (alan@spri.levels.unisa.edu.au):
  35.  * 1) Add O_CREAT to open flags so that syslogd doesn't complain about
  36.  *    non-existent files
  37.  * 2) Modified f_pmask initialisation and testing to allow logging of
  38.  *    messages at a particular priority level, rather that all messages
  39.  *    at or above a given priority level.
  40.  *
  41.  * Sat Jun 3 12:48:16 1995: Applied patches from
  42.  * Jochen.Hein@informatik.tu-clausthal.de to allow spaces *AND* tabs to
  43.  * separate the selector from the action. This means that no whitespace is
  44.  * allowed inside the selector.
  45.  * */
  46.  
  47. #ifndef lint
  48. char copyright[] =
  49. "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  50.  All rights reserved.\n";
  51. #endif /* not lint */
  52.  
  53. #ifndef lint
  54. static char sccsid[] = "@(#)syslogd.c    5.45 (Berkeley) 3/2/91";
  55. #endif /* not lint */
  56.  
  57. /*
  58.  *  syslogd -- log system messages
  59.  *
  60.  * This program implements a system log. It takes a series of lines.
  61.  * Each line may have a priority, signified as "<n>" as
  62.  * the first characters of the line.  If this is
  63.  * not present, a default priority is used.
  64.  *
  65.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  66.  * cause it to reread its configuration file.
  67.  *
  68.  * Defined Constants:
  69.  *
  70.  * MAXLINE -- the maximimum line length that can be handled.
  71.  * DEFUPRI -- the default priority for user messages
  72.  * DEFSPRI -- the default priority for kernel messages
  73.  *
  74.  * Author: Eric Allman
  75.  * extensive changes by Ralph Campbell
  76.  * more extensive changes by Eric Allman (again)
  77.  *
  78.  * Modified, Sun Mar  7 15:21:13 1993, faith@cs.unc.edu for Linux:
  79.  *
  80.  * SUN_LEN_MISSING:      struct sockaddr does not have sun_len
  81.  * SYSLOG_STREAM:        syslog is implemented using stream sockets
  82.  * SYSLOG_INET:          support inet logging
  83.  * KLOG_STREAM:          kernel logging uses a stream device
  84.  * STATUS_BROKEN:        use "int status" instead of "union wait status"
  85.  * RE_INSTALL_SIGNAL:    signal() does *not* remain installed
  86.  * SYS_MSGBUF_H_MISSING: sys/msgbuf.h is missing
  87.  * FSYNC_MISSING:        fsync() is missing 
  88.  * KERNEL_NAME:          what the kernel is usually called
  89.  *
  90.  * Original Linux version by Rik Faith <faith@cs.unc.edu>
  91.  * with changes by Rick Sladkey <jrs@world.std.com> and
  92.  * Rick <pclink@qus102.qld.npb.telecom.com.au>.  Anyone else
  93.  * named Rick who wants to chip in?  :-)
  94.  * More corrections by Neal Becker <neal@ctd.comsat.com> Sun Jan 16, 1994
  95.  * Patches from Jochen Hein (Jochen.Hein@informatik.tu-clausthal.de) to treat
  96.  *   spaces and tabs the same, applied Sat Mar 11 10:09:24 1995
  97.  */
  98.  
  99. #ifdef __linux__
  100. #define SUN_LEN_MISSING
  101. #define SYSLOG_STREAM
  102. #define SYSLOG_INET
  103. #define KLOG_STREAM
  104. #undef  STATUS_BROKEN
  105. #define RE_INSTALL_SIGNAL
  106. #define SYS_MSGBUF_H_MISSING
  107. #undef  FSYNC_MISSING
  108. #define KERNEL_NAME    "linux"
  109. #endif
  110.  
  111. #define    MAXLINE        1024        /* maximum line length */
  112. #define    MAXSVLINE    120        /* maximum saved line length */
  113. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  114. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  115. #define TIMERINTVL    30        /* interval for checking flush, mark */
  116.  
  117. #include <sys/param.h>
  118. #include <sys/errno.h>
  119. #include <sys/ioctl.h>
  120. #include <sys/stat.h>
  121. #include <sys/wait.h>
  122. #include <sys/socket.h>
  123. #include <sys/file.h>
  124. #ifdef SYS_MSGBUF_H_MISSING
  125. #define MSG_BSIZE (MAXLINE*2)
  126. #else
  127. #include <sys/msgbuf.h>
  128. #endif
  129. #include <sys/uio.h>
  130. #include <sys/un.h>
  131. #include <sys/time.h>
  132. #include <sys/resource.h>
  133. #include <sys/signal.h>
  134.  
  135. #include <netinet/in.h>
  136. #include <netdb.h>
  137.  
  138. #include <utmp.h>
  139. #include <setjmp.h>
  140. #include <stdio.h>
  141. #include <ctype.h>
  142. #include <string.h>
  143. #include <unistd.h>
  144. #include <paths.h>
  145.  
  146. #define SYSLOG_NAMES
  147. #include <sys/syslog.h>
  148.  
  149. char    *LogName = _PATH_LOG;
  150. char    *ConfFile = _PATH_LOGCONF;
  151.  
  152. #ifdef __linux__
  153. #define CONFORM_TO_FSSTND
  154. #include "pathnames.h"
  155. #endif
  156.  
  157. #ifdef CONFORM_TO_FSSTND
  158. char    *PidFile = "/var/run/syslog.pid";
  159. #else
  160. char    *PidFile = _PATH_LOGPID;
  161. #endif
  162.  
  163. char    ctty[] = _PATH_CONSOLE;
  164.  
  165. #define FDMASK(fd)    (1 << (fd))
  166.  
  167. #define    dprintf        if (Debug) printf
  168.  
  169. #define MAXUNAMES    20    /* maximum number of user names */
  170.  
  171. /*
  172.  * Flags to logmsg().
  173.  */
  174.  
  175. #define IGN_CONS    0x001    /* don't print on console */
  176. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  177. #define ADDDATE        0x004    /* add a date to the message */
  178. #define MARK        0x008    /* this message is a mark */
  179.  
  180. /*
  181.  * This structure represents the files that will have log
  182.  * copies printed.
  183.  */
  184.  
  185. struct filed {
  186.     struct    filed *f_next;        /* next in linked list */
  187.     short    f_type;            /* entry type, see below */
  188.     short    f_file;            /* file descriptor */
  189.     time_t    f_time;            /* time this was last written */
  190.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  191.     union {
  192.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  193.         struct {
  194.             char    f_hname[MAXHOSTNAMELEN+1];
  195.             struct sockaddr_in    f_addr;
  196.         } f_forw;        /* forwarding address */
  197.         char    f_fname[MAXPATHLEN];
  198.     } f_un;
  199.     char    f_prevline[MAXSVLINE];        /* last message logged */
  200.     char    f_lasttime[16];            /* time of last occurrence */
  201.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  202.     int    f_prevpri;            /* pri of f_prevline */
  203.     int    f_prevlen;            /* length of f_prevline */
  204.     int    f_prevcount;            /* repetition cnt of prevline */
  205.     int    f_repeatcount;            /* number of "repeated" msgs */
  206. };
  207.  
  208. /*
  209.  * Intervals at which we flush out "message repeated" messages,
  210.  * in seconds after previous message is logged.  After each flush,
  211.  * we move to the next interval until we reach the largest.
  212.  */
  213. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  214. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  215. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  216. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  217.                  (f)->f_repeatcount = MAXREPEAT; \
  218.             }
  219.  
  220. /* values for f_type */
  221. #define F_UNUSED    0        /* unused entry */
  222. #define F_FILE        1        /* regular file */
  223. #define F_TTY        2        /* terminal */
  224. #define F_CONSOLE    3        /* console terminal */
  225. #define F_FORW        4        /* remote machine */
  226. #define F_USERS        5        /* list of users */
  227. #define F_WALL        6        /* everyone logged on */
  228.  
  229. char    *TypeNames[7] = {
  230.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  231.     "FORW",        "USERS",    "WALL"
  232. };
  233.  
  234. struct    filed *Files;
  235. struct    filed consfile;
  236.  
  237. int    Debug;            /* debug flag */
  238. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  239. char    *LocalDomain;        /* our local domain name */
  240. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  241. #ifdef SYSLOG_INET
  242. int    finet;            /* Internet datagram socket */
  243. #endif /* SYSLOG_INET */
  244. int    LogPort;        /* port number for INET connections */
  245. int    Initialized = 0;    /* set when we have initialized ourselves */
  246. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  247. int    MarkSeq = 0;        /* mark sequence number */
  248.  
  249. extern    int errno;
  250. extern    char *ctime(), *index(), *calloc();
  251.  
  252. main(argc, argv)
  253.     int argc;
  254.     char **argv;
  255. {
  256.     register int i;
  257.     register char *p;
  258.     int funix, fklog, len;
  259.     struct sockaddr_un sunx, fromunix;
  260.     struct sockaddr_in sin, frominet;
  261.     FILE *fp;
  262.     int ch;
  263.     char line[MSG_BSIZE + 1];
  264.     extern int optind;
  265.     extern char *optarg;
  266.     void die(), domark(), init(), reapchild();
  267. #ifdef SYSLOG_STREAM
  268.     fd_set unixm;
  269.     int fd;
  270. #endif /* SYSLOG_STREAM */
  271.  
  272.     while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
  273.         switch((char)ch) {
  274.         case 'd':        /* debug */
  275.             Debug++;
  276.             break;
  277.         case 'f':        /* configuration file */
  278.             ConfFile = optarg;
  279.             break;
  280.         case 'm':        /* mark interval */
  281.             MarkInterval = atoi(optarg) * 60;
  282.             break;
  283.         case 'p':        /* path */
  284.             LogName = optarg;
  285.             break;
  286.         case '?':
  287.         default:
  288.             usage();
  289.         }
  290.     if (argc -= optind)
  291.         usage();
  292.  
  293.     if (!Debug)
  294.         daemon(0, 0);
  295.     else
  296.         setlinebuf(stdout);
  297.  
  298.     consfile.f_type = F_CONSOLE;
  299.     (void) strcpy(consfile.f_un.f_fname, ctty);
  300.     (void) gethostname(LocalHostName, sizeof LocalHostName);
  301.     if (p = index(LocalHostName, '.')) {
  302.         *p++ = '\0';
  303.         LocalDomain = p;
  304.     }
  305.     else
  306.         LocalDomain = "";
  307.     (void) signal(SIGTERM, die);
  308.     (void) signal(SIGINT, Debug ? die : SIG_IGN);
  309.     (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
  310.     (void) signal(SIGCHLD, reapchild);
  311.     (void) signal(SIGALRM, domark);
  312.     (void) alarm(TIMERINTVL);
  313.     (void) unlink(LogName);
  314.  
  315.     bzero((char *)&sunx, sizeof(sunx));
  316.     sunx.sun_family = AF_UNIX;
  317.     (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
  318. #ifdef SYSLOG_STREAM
  319.     funix = socket(AF_UNIX, SOCK_STREAM, 0);
  320.     if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
  321.         sizeof(sunx)) < 0 || listen(funix, 5) < 0 ||
  322. #else /* !SYSLOG_STREAM */
  323.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  324.     if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
  325.         sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
  326.         strlen(sunx.sun_path)) < 0 ||
  327. #endif /* !SYSLOG_STREAM */
  328.         chmod(LogName, 0666) < 0) {
  329.         (void) sprintf(line, "cannot create %s", LogName);
  330.         logerror(line);
  331.         dprintf("cannot create %s (%d)\n", LogName, errno);
  332.         die(0);
  333.     }
  334. #ifdef SYSLOG_INET
  335.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  336.     if (finet >= 0) {
  337.         struct servent *sp;
  338.  
  339.         sp = getservbyname("syslog", "udp");
  340.         if (sp == NULL) {
  341.             errno = 0;
  342.             logerror("syslog/udp: unknown service");
  343.         }
  344.         else {
  345.             bzero((char *) &sin, sizeof(sin));
  346.             sin.sin_family = AF_INET;
  347.             sin.sin_port = LogPort = sp->s_port;
  348.             if (bind(finet, (struct sockaddr *) &sin,
  349.                  sizeof(sin)) < 0)
  350.                 logerror("bind");
  351.             else
  352.                 InetInuse = 1;
  353.         }
  354.         if (!InetInuse)
  355.             finet = -1;
  356.     }
  357. #endif /* SYSLOG_INET */
  358.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0)
  359.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  360.  
  361.     /* tuck my process id away */
  362.     fp = fopen(PidFile, "w");
  363.     if (fp != NULL) {
  364.         fprintf(fp, "%d\n", getpid());
  365.         (void) fclose(fp);
  366.     }
  367.  
  368.     dprintf("off & running....\n");
  369.  
  370.     init();
  371. #ifndef RE_INSTALL_SIGNAL    /* init installs itself as the handler */
  372.     (void) signal(SIGHUP, init);
  373. #endif                /* !RE_INSTALL_SIGNAL */
  374. #ifdef SYSLOG_STREAM
  375.     FD_ZERO(&unixm);
  376. #endif /* SYSLOG_STREAM */
  377.  
  378.     for (;;) {
  379.         int nfds;
  380.         fd_set readfds;
  381.  
  382. #ifdef SYSLOG_STREAM
  383.         readfds = unixm;
  384. #else /* !SYSLOG_STREAM */
  385.         FD_ZERO(&readfds);
  386. #endif /* !SYSLOG_STREAM */
  387.         if (funix >= 0)
  388.             FD_SET(funix, &readfds);
  389.         if (fklog >= 0)
  390.             FD_SET(fklog, &readfds);
  391. #ifdef SYSLOG_INET
  392.         if (finet >= 0)
  393.             FD_SET(finet, &readfds);
  394. #endif /* SYSLOG_INET */
  395.  
  396.         errno = 0;
  397.         dprintf("readfds = %#x\n", *((long *)&readfds));
  398.         nfds = select(FD_SETSIZE, &readfds, (fd_set *) NULL,
  399.             (fd_set *) NULL, (struct timeval *) NULL);
  400.         if (nfds == 0)
  401.             continue;
  402.         if (nfds < 0) {
  403.             if (errno != EINTR)
  404.                 logerror("select");
  405.             continue;
  406.         }
  407.         dprintf("got a message (%d, %#x)\n", nfds, *((long *)&readfds));
  408.  
  409. #ifdef KLOG_STREAM
  410.         if (FD_ISSET(fklog, &readfds)) {
  411.             nfds--;
  412.             for (;;) {
  413.                 i = klogread(fklog, line, sizeof(line) - 1);
  414.                 if (i > 0) {
  415.                     line[i] = '\0';
  416.                     printsys(line);
  417.                 }
  418.                 else {
  419.                     if (i < 0 && errno != EINTR) {
  420.                         logerror("klog");
  421.                         fklog = -1;
  422.                     }
  423.                     break;
  424.                 }
  425.             }
  426.         }
  427. #else /* !KLOG_STREAM */
  428.         if (FD_ISSET(fklog, &readfds)) {
  429.             nfds--;
  430.             i = read(fklog, line, sizeof(line) - 1);
  431.             if (i > 0) {
  432.                 line[i] = '\0';
  433.                 printsys(line);
  434.             } else if (i < 0 && errno != EINTR) {
  435.                 logerror("klog");
  436.                 fklog = -1;
  437.             }
  438.         }
  439. #endif /* !KLOG_STREAM */
  440.  
  441. #ifdef SYSLOG_STREAM
  442.                 /* Accept a new unix connection. */
  443.                 if (FD_ISSET(funix, &readfds)) {
  444.             nfds--;
  445.             len = sizeof fromunix;
  446.             if ((fd = accept(funix, (struct sockaddr *) &fromunix,
  447.                      &len)) >= 0) {
  448.                 FD_SET(fd, &unixm);
  449.                 dprintf("new stream connect (%d)\n", fd);
  450.             }
  451.             else
  452.                 logerror("accept");
  453.                 }
  454.         /* Recv from existing connections. */
  455.         for (fd = 0; nfds > 0 && fd < FD_SETSIZE; fd++) {
  456.             if (FD_ISSET(fd, &unixm) && FD_ISSET(fd, &readfds)) {
  457.                 nfds--;
  458.                 dprintf("message from stream (%d)\n", fd);
  459.                 i = read(fd, line, MAXLINE);
  460.                 if (i > 0) {
  461.                     line[i] = '\0';
  462.                     printmulti(LocalHostName, line, i);
  463.                 }
  464.                 else if (i == 0) {
  465.                     dprintf("stream closed (%d)\n", fd);
  466.                     close(fd);
  467.                     FD_CLR(fd, &unixm);
  468.                 }
  469.                 else if (i < 0 && errno != EINTR) {
  470.                     logerror("recv stream");
  471.                     close(fd);
  472.                     FD_CLR(fd, &unixm);
  473.                 }
  474.             }
  475.         }
  476. #else /* !SYSLOG_STREAM */
  477.         if (FD_ISSET(funix, &readfds)) {
  478.             nfds--;
  479.             len = sizeof fromunix;
  480.             i = recvfrom(funix, line, MAXLINE, 0,
  481.                 (struct sockaddr *) &fromunix, &len);
  482.             if (i > 0) {
  483.                 line[i] = '\0';
  484.                 printmulti(LocalHostName, line,i);
  485.             } else if (i < 0 && errno != EINTR)
  486.                 logerror("recvfrom unix");
  487.         }
  488. #endif /* !SYSLOG_STREAM */
  489.  
  490. #ifdef SYSLOG_INET
  491.         if (FD_ISSET(finet, &readfds)) {
  492.             nfds--;
  493.             len = sizeof frominet;
  494.             i = recvfrom(finet, line, MAXLINE, 0,
  495.                 (struct sockaddr *) &frominet, &len);
  496.             if (i > 0) {
  497.                 extern char *cvthname();
  498.  
  499.                 line[i] = '\0';
  500.                 printmulti(cvthname(&frominet), line,i);
  501.             } else if (i < 0 && errno != EINTR)
  502.                 logerror("recvfrom inet");
  503.         }
  504. #endif /* SYSLOG_INET */
  505.         if (nfds != 0)
  506.             logerror("loose cannon");
  507.     }
  508. }
  509.  
  510. usage()
  511. {
  512.     (void) fprintf(stderr,
  513.         "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
  514.     exit(1);
  515. }
  516.  
  517. /*
  518.  * Break up null terminated lines for printline.
  519.  */
  520.  
  521. printmulti(hname, msg, len)
  522.         char *hname;
  523.         char *msg;
  524.     int  len;
  525. {
  526.    int  i;
  527.    char *pt;
  528.  
  529.    dprintf("strlen = %d, len = %d\n", strlen(msg), len );
  530.    for (pt = msg, i = 0; i < len; i++) {
  531.       if (msg[i] == '\0') {
  532.      printline(hname,pt);
  533.      pt = &msg[i+1];
  534.       }
  535.    }
  536. }
  537.  
  538. /*
  539.  * Take a raw input line, decode the message, and print the message
  540.  * on the appropriate log files.
  541.  */
  542.  
  543. printline(hname, msg)
  544.     char *hname;
  545.     char *msg;
  546. {
  547.     register char *p, *q;
  548.     register int c;
  549.     char line[MAXLINE + 1];
  550.     int pri;
  551.  
  552.     /* test for special codes */
  553.     pri = DEFUPRI;
  554.     p = msg;
  555.     if (*p == '<') {
  556.         pri = 0;
  557.         while (isdigit(*++p))
  558.             pri = 10 * pri + (*p - '0');
  559.         if (*p == '>')
  560.             ++p;
  561.     }
  562.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  563.         pri = DEFUPRI;
  564.  
  565.     /* don't allow users to log kernel messages */
  566.     if (LOG_FAC(pri) == LOG_KERN)
  567.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  568.  
  569.     q = line;
  570.  
  571.     while ((c = *p++ & 0177) != '\0' &&
  572.         q < &line[sizeof(line) - 1])
  573.         if (iscntrl(c)) {
  574.             if (c == '\n')
  575.                 *q++ = ' ';
  576.             else if (c == '\r')
  577.                     *q++ = ' ';
  578.             else if (c == '\t')
  579.                 *q++ = '\t';
  580.             else {
  581.                 *q++ = '^';
  582.                 *q++ = c ^ 0100;
  583.             }
  584.         }
  585.         else
  586.             *q++ = c;
  587.     *q = '\0';
  588.  
  589.     logmsg(pri, line, hname, 0);
  590. }
  591.  
  592. /*
  593.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  594.  */
  595.  
  596. printsys(msg)
  597.     char *msg;
  598. {
  599.     register char *p, *q;
  600.     register int c;
  601.     char line[MAXLINE + 1];
  602.     int pri, flags;
  603.     char *lp;
  604.  
  605. #ifdef KERNEL_NAME
  606.     (void) sprintf(line, "%s: ", KERNEL_NAME);
  607. #else /* !KERNEL_NAME */
  608.     (void) strcpy(line, "vmunix: ");
  609. #endif /* !KERNEL_NAME */
  610.  
  611.     lp = line + strlen(line);
  612.     for (p = msg; *p != '\0'; ) {
  613.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  614.         pri = DEFSPRI;
  615.         if (*p == '<') {
  616.             pri = 0;
  617.             while (isdigit(*++p))
  618.                 pri = 10 * pri + (*p - '0');
  619.             if (*p == '>')
  620.                 ++p;
  621.         } else {
  622.             /* kernel printf's come out on console */
  623.             flags |= IGN_CONS;
  624.         }
  625.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  626.             pri = DEFSPRI;
  627.         q = lp;
  628.         while (*p != '\0' && (c = *p++) != '\n' &&
  629.             q < &line[MAXLINE])
  630.             if (iscntrl(c)) {
  631.                 if (c == '\n')
  632.                     *q++ = ' ';
  633.                 else if (c == '\r')
  634.                     *q++ = ' ';
  635.                 else if (c == '\t')
  636.                     *q++ = '\t';
  637.                 else {
  638.                     *q++ = '^';
  639.                     *q++ = c ^ 0100;
  640.                 }
  641.             }
  642.             else
  643.                 *q++ = c;
  644.         *q = '\0';
  645.         logmsg(pri, line, LocalHostName, flags);
  646.     }
  647. }
  648.  
  649. time_t    now;
  650.  
  651. /*
  652.  * Log a message to the appropriate log files, users, etc. based on
  653.  * the priority.
  654.  */
  655.  
  656. logmsg(pri, msg, from, flags)
  657.     int pri;
  658.     char *msg, *from;
  659.     int flags;
  660. {
  661.     register struct filed *f;
  662.     int fac, prilev;
  663.     int omask, msglen;
  664.     char *timestamp;
  665.     time_t time();
  666.  
  667.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  668.         pri, flags, from, msg);
  669.  
  670.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  671.  
  672.     /*
  673.      * Check to see if msg looks non-standard.
  674.      */
  675.     msglen = strlen(msg);
  676.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  677.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  678.         flags |= ADDDATE;
  679.  
  680.     (void) time(&now);
  681.     if (flags & ADDDATE)
  682.         timestamp = ctime(&now) + 4;
  683.     else {
  684.         timestamp = msg;
  685.         msg += 16;
  686.         msglen -= 16;
  687.     }
  688.  
  689.     /* extract facility and priority level */
  690.     if (flags & MARK)
  691.         fac = LOG_NFACILITIES;
  692.     else
  693.         fac = LOG_FAC(pri);
  694.     prilev = 1 << (LOG_PRIMASK - LOG_PRI(pri));
  695.  
  696.     /* log the message to the particular outputs */
  697.     if (!Initialized) {
  698.         f = &consfile;
  699. #ifdef O_NOCTTY
  700.         f->f_file = open(ctty, O_WRONLY|O_NOCTTY, 0);
  701. #else /* !O_NOCTTY */
  702.         f->f_file = open(ctty, O_WRONLY, 0);
  703. #endif /* !O_NOCTTY */
  704.  
  705.         if (f->f_file >= 0) {
  706.             fprintlog(f, flags, msg);
  707.             (void) close(f->f_file);
  708.         }
  709.         (void) sigsetmask(omask);
  710.         return;
  711.     }
  712.     for (f = Files; f; f = f->f_next) {
  713.         /* skip messages that are incorrect priority */
  714.         if (!(f->f_pmask[fac] & prilev))
  715.             continue;
  716.  
  717.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  718.             continue;
  719.  
  720.         /* don't output marks to recently written files */
  721.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  722.             continue;
  723.  
  724.         /*
  725.          * suppress duplicate lines to this file
  726.          */
  727.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  728.             !strcmp(msg, f->f_prevline) &&
  729.             !strcmp(from, f->f_prevhost)) {
  730.             (void) strncpy(f->f_lasttime, timestamp, 15);
  731.             f->f_prevcount++;
  732.             dprintf("msg repeated %d times, %ld sec of %d\n",
  733.                 f->f_prevcount, now - f->f_time,
  734.                 repeatinterval[f->f_repeatcount]);
  735.             /*
  736.              * If domark would have logged this by now,
  737.              * flush it now (so we don't hold isolated messages),
  738.              * but back off so we'll flush less often
  739.              * in the future.
  740.              */
  741.             if (now > REPEATTIME(f)) {
  742.                 fprintlog(f, flags, (char *)NULL);
  743.                 BACKOFF(f);
  744.             }
  745.         } else {
  746.             /* new line, save it */
  747.             if (f->f_prevcount)
  748.                 fprintlog(f, 0, (char *)NULL);
  749.             f->f_repeatcount = 0;
  750.             (void) strncpy(f->f_lasttime, timestamp, 15);
  751.             (void) strncpy(f->f_prevhost, from,
  752.                     sizeof(f->f_prevhost));
  753.             if (msglen < MAXSVLINE) {
  754.                 f->f_prevlen = msglen;
  755.                 f->f_prevpri = pri;
  756.                 (void) strcpy(f->f_prevline, msg);
  757.                 fprintlog(f, flags, (char *)NULL);
  758.             } else {
  759.                 f->f_prevline[0] = 0;
  760.                 f->f_prevlen = 0;
  761.                 fprintlog(f, flags, msg);
  762.             }
  763.         }
  764.     }
  765.     (void) sigsetmask(omask);
  766. }
  767.  
  768. fprintlog(f, flags, msg)
  769.     register struct filed *f;
  770.     int flags;
  771.     char *msg;
  772. {
  773.     struct iovec iov[6];
  774.     register struct iovec *v;
  775.     register int l;
  776.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  777.  
  778.     v = iov;
  779.     if (f->f_type == F_WALL) {
  780.         v->iov_base = greetings;
  781.         v->iov_len = sprintf(greetings,
  782.             "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  783.             f->f_prevhost, ctime(&now));
  784.         v++;
  785.         v->iov_base = "";
  786.         v->iov_len = 0;
  787.         v++;
  788.     } else {
  789.         v->iov_base = f->f_lasttime;
  790.         v->iov_len = 15;
  791.         v++;
  792.         v->iov_base = " ";
  793.         v->iov_len = 1;
  794.         v++;
  795.     }
  796.     v->iov_base = f->f_prevhost;
  797.     v->iov_len = strlen(v->iov_base);
  798.     v++;
  799.     v->iov_base = " ";
  800.     v->iov_len = 1;
  801.     v++;
  802.  
  803.     if (msg) {
  804.         v->iov_base = msg;
  805.         v->iov_len = strlen(msg);
  806.     } else if (f->f_prevcount > 1) {
  807.         v->iov_base = repbuf;
  808.         v->iov_len = sprintf(repbuf, "last message repeated %d times",
  809.             f->f_prevcount);
  810.     } else {
  811.         v->iov_base = f->f_prevline;
  812.         v->iov_len = f->f_prevlen;
  813.     }
  814.     v++;
  815.  
  816.     dprintf("Logging to %s", TypeNames[f->f_type]);
  817.     f->f_time = now;
  818.  
  819.     switch (f->f_type) {
  820.     case F_UNUSED:
  821.         dprintf("\n");
  822.         break;
  823.  
  824.     case F_FORW:
  825.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  826.         l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
  827.             iov[0].iov_base, iov[4].iov_base);
  828.         if (l > MAXLINE)
  829.             l = MAXLINE;
  830.         if (sendto(finet, line, l, 0,
  831.             (struct sockaddr *)&f->f_un.f_forw.f_addr,
  832.             sizeof f->f_un.f_forw.f_addr) != l) {
  833.             int e = errno;
  834.             (void) close(f->f_file);
  835.             f->f_type = F_UNUSED;
  836.             errno = e;
  837.             logerror("sendto");
  838.         }
  839.         break;
  840.  
  841.     case F_CONSOLE:
  842.         if (flags & IGN_CONS) {
  843.             dprintf(" (ignored)\n");
  844.             break;
  845.         }
  846.         /* FALLTHROUGH */
  847.  
  848.     case F_TTY:
  849.     case F_FILE:
  850.         dprintf(" %s\n", f->f_un.f_fname);
  851.         if (f->f_type != F_FILE) {
  852.             v->iov_base = "\r\n";
  853.             v->iov_len = 2;
  854.         } else {
  855.             v->iov_base = "\n";
  856.             v->iov_len = 1;
  857.         }
  858.     again:
  859.         if (writev(f->f_file, iov, 6) < 0) {
  860.             int e = errno;
  861.             (void) close(f->f_file);
  862.             /*
  863.              * Check for errors on TTY's due to loss of tty
  864.              */
  865.             if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
  866.                 f->f_file = open(f->f_un.f_fname,
  867.                     O_WRONLY|O_APPEND, 0);
  868.                 if (f->f_file < 0) {
  869.                     f->f_type = F_UNUSED;
  870.                     logerror(f->f_un.f_fname);
  871.                 } else
  872.                     goto again;
  873.             } else {
  874.                 f->f_type = F_UNUSED;
  875.                 errno = e;
  876.                 logerror(f->f_un.f_fname);
  877.             }
  878.         }
  879. #ifdef FSYNC_MISSING
  880.         else if (flags & SYNC_FILE)
  881.             (void) sync();
  882. #else
  883.         else if (flags & SYNC_FILE)
  884.             (void) fsync(f->f_file);
  885. #endif
  886.         break;
  887.  
  888.     case F_USERS:
  889.     case F_WALL:
  890.         dprintf("\n");
  891.         v->iov_base = "\r\n";
  892.         v->iov_len = 2;
  893.         wallmsg(f, iov);
  894.         break;
  895.     }
  896.     f->f_prevcount = 0;
  897. }
  898.  
  899. /*
  900.  *  WALLMSG -- Write a message to the world at large
  901.  *
  902.  *    Write the specified message to either the entire
  903.  *    world, or a list of approved users.
  904.  */
  905.  
  906. wallmsg(f, iov)
  907.     register struct filed *f;
  908.     struct iovec *iov;
  909. {
  910.     static int reenter;            /* avoid calling ourselves */
  911.     register FILE *uf;
  912.     register int i;
  913.     struct utmp ut;
  914.     char *p, *ttymsg();
  915.  
  916.     if (reenter++)
  917.         return;
  918.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  919.         logerror(_PATH_UTMP);
  920.         reenter = 0;
  921.         return;
  922.     }
  923.     /* NOSTRICT */
  924.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  925.         if (ut.ut_name[0] == '\0')
  926.             continue;
  927. #ifdef USER_PROCESS
  928.         if (ut.ut_type != USER_PROCESS)
  929.             continue;
  930. #endif
  931.         if (f->f_type == F_WALL) {
  932.             if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  933.                 errno = 0;    /* already in msg */
  934.                 logerror(p);
  935.             }
  936.             continue;
  937.         }
  938.         /* should we send the message to this user? */
  939.         for (i = 0; i < MAXUNAMES; i++) {
  940.             if (!f->f_un.f_uname[i][0])
  941.                 break;
  942.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  943.                 UT_NAMESIZE)) {
  944.                 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  945.                     errno = 0;    /* already in msg */
  946.                     logerror(p);
  947.                 }
  948.                 break;
  949.             }
  950.         }
  951.     }
  952.     (void) fclose(uf);
  953.     reenter = 0;
  954. }
  955.  
  956. void
  957. reapchild()
  958. {
  959. #ifdef STATUS_BROKEN
  960.     int status;
  961. #else
  962.     union wait status;
  963. #endif
  964.  
  965.     while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
  966.         ;
  967. }
  968.  
  969. /*
  970.  * Return a printable representation of a host address.
  971.  */
  972. char *
  973. cvthname(f)
  974.     struct sockaddr_in *f;
  975. {
  976.     struct hostent *hp;
  977.     register char *p;
  978.     extern char *inet_ntoa();
  979.  
  980.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  981.  
  982.     if (f->sin_family != AF_INET) {
  983.         dprintf("Malformed from address\n");
  984.         return ("???");
  985.     }
  986.     hp = gethostbyaddr((char *)&f->sin_addr,
  987.         sizeof(struct in_addr), f->sin_family);
  988.     if (hp == 0) {
  989.         dprintf("Host name for your address (%s) unknown\n",
  990.             inet_ntoa(f->sin_addr));
  991.         return (inet_ntoa(f->sin_addr));
  992.     }
  993.     if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  994.         *p = '\0';
  995.     return ((char *) hp->h_name);
  996. }
  997.  
  998. void
  999. domark()
  1000. {
  1001.     register struct filed *f;
  1002.     time_t time();
  1003.  
  1004.     now = time((time_t *)NULL);
  1005.     MarkSeq += TIMERINTVL;
  1006.     if (MarkSeq >= MarkInterval) {
  1007.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  1008.         MarkSeq = 0;
  1009.     }
  1010.  
  1011.     for (f = Files; f; f = f->f_next) {
  1012.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  1013.             dprintf("flush %s: repeated %d times, %d sec.\n",
  1014.                 TypeNames[f->f_type], f->f_prevcount,
  1015.                 repeatinterval[f->f_repeatcount]);
  1016.             fprintlog(f, 0, (char *)NULL);
  1017.             BACKOFF(f);
  1018.         }
  1019.     }
  1020. #ifdef RE_INSTALL_SIGNAL
  1021.         (void) signal(SIGALRM, domark);
  1022. #endif
  1023.     (void) alarm(TIMERINTVL);
  1024. }
  1025.  
  1026. /*
  1027.  * Print syslogd errors some place.
  1028.  */
  1029. logerror(type)
  1030.     char *type;
  1031. {
  1032.     char buf[100], *strerror();
  1033.  
  1034.     if (errno)
  1035.         (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
  1036.     else
  1037.         (void) sprintf(buf, "syslogd: %s", type);
  1038.     errno = 0;
  1039.     dprintf("%s\n", buf);
  1040.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  1041. }
  1042.  
  1043. void
  1044. die(sig)
  1045. {
  1046.     register struct filed *f;
  1047.     char buf[100];
  1048.  
  1049.     for (f = Files; f != NULL; f = f->f_next) {
  1050.         /* flush any pending output */
  1051.         if (f->f_prevcount)
  1052.             fprintlog(f, 0, (char *)NULL);
  1053.     }
  1054.     if (sig) {
  1055.         dprintf("syslogd: exiting on signal %d\n", sig);
  1056.         (void) sprintf(buf, "exiting on signal %d", sig);
  1057.         errno = 0;
  1058.         logerror(buf);
  1059.     }
  1060.     (void) unlink(LogName);
  1061.     exit(0);
  1062. }
  1063.  
  1064. /*
  1065.  *  INIT -- Initialize syslogd from configuration table
  1066.  */
  1067.  
  1068. void
  1069. init()
  1070. {
  1071.     register int i;
  1072.     register FILE *cf;
  1073.     register struct filed *f, *next, **nextp;
  1074.     register char *p;
  1075.     char cline[BUFSIZ];
  1076.  
  1077.     dprintf("init\n");
  1078.  
  1079.     /*
  1080.      *  Close all open log files.
  1081.      */
  1082.     Initialized = 0;
  1083.     for (f = Files; f != NULL; f = next) {
  1084.         /* flush any pending output */
  1085.         if (f->f_prevcount)
  1086.             fprintlog(f, 0, (char *)NULL);
  1087.  
  1088.         switch (f->f_type) {
  1089.           case F_FILE:
  1090.           case F_TTY:
  1091.           case F_CONSOLE:
  1092.           case F_FORW:
  1093.             (void) close(f->f_file);
  1094.             break;
  1095.         }
  1096.         next = f->f_next;
  1097.         free((char *) f);
  1098.     }
  1099.     Files = NULL;
  1100.     nextp = &Files;
  1101.  
  1102.     /* open the configuration file */
  1103.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  1104.         dprintf("cannot open %s\n", ConfFile);
  1105.         *nextp = (struct filed *)calloc(1, sizeof(*f));
  1106.         cfline("*.ERR\t/dev/console", *nextp);
  1107.         (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
  1108.         cfline("*.PANIC\t*", (*nextp)->f_next);
  1109.         Initialized = 1;
  1110.         return;
  1111.     }
  1112.  
  1113.     /*
  1114.      *  Foreach line in the conf table, open that file.
  1115.      */
  1116.     f = NULL;
  1117.     while (fgets(cline, sizeof cline, cf) != NULL) {
  1118.         /*
  1119.          * check for end-of-section, comments, strip off trailing
  1120.          * spaces and newline character.
  1121.          */
  1122.         for (p = cline; isspace(*p); ++p);
  1123.         if (*p == '\0' || *p == '#')
  1124.             continue;
  1125.         for (p = index(cline, '\0'); isspace(*--p););
  1126.         *++p = '\0';
  1127.         f = (struct filed *)calloc(1, sizeof(*f));
  1128.         *nextp = f;
  1129.         nextp = &f->f_next;
  1130.         cfline(cline, f);
  1131.     }
  1132.  
  1133.     /* close the configuration file */
  1134.     (void) fclose(cf);
  1135.  
  1136.     Initialized = 1;
  1137.  
  1138.     if (Debug) {
  1139.         for (f = Files; f; f = f->f_next) {
  1140.             for (i = 0; i <= LOG_NFACILITIES; i++)
  1141.                 if (f->f_pmask[i] == 0)
  1142.                     printf("X ");
  1143.                 else
  1144.                     printf("0x%02x ", f->f_pmask[i]);
  1145.             printf("%s: ", TypeNames[f->f_type]);
  1146.             switch (f->f_type) {
  1147.             case F_FILE:
  1148.             case F_TTY:
  1149.             case F_CONSOLE:
  1150.                 printf("%s", f->f_un.f_fname);
  1151.                 break;
  1152.  
  1153.             case F_FORW:
  1154.                 printf("%s", f->f_un.f_forw.f_hname);
  1155.                 break;
  1156.  
  1157.             case F_USERS:
  1158.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  1159.                     printf("%s, ", f->f_un.f_uname[i]);
  1160.                 break;
  1161.             }
  1162.             printf("\n");
  1163.         }
  1164.     }
  1165.  
  1166.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  1167.     dprintf("syslogd: restarted\n");
  1168. #ifdef RE_INSTALL_SIGNAL
  1169.     (void) signal(SIGHUP, init);
  1170. #endif                /* RE_INSTALL_SIGNAL */
  1171. }
  1172.  
  1173. /*
  1174.  * Crack a configuration file line
  1175.  */
  1176.  
  1177. cfline(line, f)
  1178.     char *line;
  1179.     register struct filed *f;
  1180. {
  1181.     register char *p;
  1182.     register char *q;
  1183.     register int i;
  1184.     char *bp;
  1185.     int pri;
  1186.     struct hostent *hp;
  1187.     char buf[MAXLINE], ebuf[100];
  1188.  
  1189.     dprintf("cfline(%s)\n", line);
  1190.  
  1191.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  1192.  
  1193.     /* clear out file entry */
  1194.     bzero((char *) f, sizeof *f);
  1195.     for (i = 0; i <= LOG_NFACILITIES; i++)
  1196.         f->f_pmask[i] = 0;
  1197.  
  1198.     /* scan through the list of selectors */
  1199.     for (p = line; *p && *p != '\t' && *p != ' ';) {
  1200.  
  1201.         /* find the end of this facility name list */
  1202.         for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
  1203.             continue;
  1204.  
  1205.         /* collect priority name */
  1206.         for (bp = buf; *q && !index("\t,; ", *q); )
  1207.             *bp++ = *q++;
  1208.         *bp = '\0';
  1209.  
  1210.         /* skip cruft */
  1211.         while (index(",;", *q)) /* spaces no longer allowed! */
  1212.             q++;
  1213.  
  1214.         /* decode priority name */
  1215.         if (*buf == '*')
  1216.             pri = -1;
  1217.         else {
  1218.                         pri = decode(*buf == '=' ? buf+1 : buf, prioritynames);
  1219.                         if (pri == INTERNAL_NOPRI)
  1220.                                 pri = 0;
  1221.                         else if (pri < 0 || pri > LOG_PRIMASK) {
  1222.                 (void) sprintf(ebuf,
  1223.                     "unknown priority name \"%s\"", buf);
  1224.                 logerror(ebuf);
  1225.                 return;
  1226.             }
  1227.             else
  1228.                                 pri = (*buf == '=' ? 1 : -1) << (LOG_PRIMASK - pri);
  1229.                   
  1230.         }
  1231.  
  1232.         /* scan facilities */
  1233.         while (*p && !index("\t.; ", *p)) {
  1234.             for (bp = buf; *p && !index("\t,;. ", *p); )
  1235.                 *bp++ = *p++;
  1236.             *bp = '\0';
  1237.             if (*buf == '*')
  1238.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1239.                                         if (pri == 0)
  1240.                                                 f->f_pmask[i] = pri;
  1241.                                         else
  1242.                                                 f->f_pmask[i] |= pri;
  1243.             else {
  1244.                 i = decode(buf, facilitynames);
  1245.                 if (i < 0) {
  1246.                     (void) sprintf(ebuf,
  1247.                         "unknown facility name \"%s\"",
  1248.                         buf);
  1249.                     logerror(ebuf);
  1250.                     return;
  1251.                 }
  1252.                                 if (pri == 0)
  1253.                                         f->f_pmask[i >> 3] = pri;
  1254.                                 else
  1255.                                        f->f_pmask[i >> 3] |= pri;
  1256.             }
  1257.             while (*p == ',' || *p == ' ')
  1258.                 p++;
  1259.         }
  1260.  
  1261.         p = q;
  1262.     }
  1263.  
  1264.     /* skip to action part */
  1265.     while (*p == '\t' || *p == ' ')
  1266.         p++;
  1267.  
  1268.     switch (*p)
  1269.     {
  1270.     case '@':
  1271.         if (!InetInuse)
  1272.             break;
  1273.         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
  1274.         hp = gethostbyname(p);
  1275.         if (hp == NULL) {
  1276.             extern int h_errno, h_nerr;
  1277.             extern char **h_errlist;
  1278.  
  1279.             logerror((u_int)h_errno < h_nerr ?
  1280.                 h_errlist[h_errno] : "Unknown error");
  1281.             break;
  1282.         }
  1283.         bzero((char *) &f->f_un.f_forw.f_addr,
  1284.              sizeof f->f_un.f_forw.f_addr);
  1285.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1286.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1287.         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
  1288.         f->f_type = F_FORW;
  1289.         break;
  1290.  
  1291.     case '/':
  1292.         (void) strcpy(f->f_un.f_fname, p);
  1293. #ifdef O_NOCTTY
  1294.                 if ((f->f_file = open(p,
  1295.                       O_CREAT|O_WRONLY|O_APPEND|O_NOCTTY,
  1296.                       0644)) < 0) {
  1297. #else /* !O_NOCTTY */
  1298.                 if ((f->f_file = open(p,
  1299.                       O_CREAT|O_WRONLY|O_APPEND, 0644)) < 0) {
  1300. #endif /* !O_NOCTTY */
  1301.             f->f_file = F_UNUSED;
  1302.             logerror(p);
  1303.             break;
  1304.         }
  1305.         if (isatty(f->f_file))
  1306.             f->f_type = F_TTY;
  1307.         else
  1308.             f->f_type = F_FILE;
  1309.         if (strcmp(p, ctty) == 0)
  1310.             f->f_type = F_CONSOLE;
  1311.         break;
  1312.  
  1313.     case '*':
  1314.         f->f_type = F_WALL;
  1315.         break;
  1316.  
  1317.     default:
  1318.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1319.             for (q = p; *q && *q != ','; )
  1320.                 q++;
  1321.             (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1322.             if ((q - p) > UT_NAMESIZE)
  1323.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1324.             else
  1325.                 f->f_un.f_uname[i][q - p] = '\0';
  1326.             while (*q == ',' || *q == ' ')
  1327.                 q++;
  1328.             p = q;
  1329.         }
  1330.         f->f_type = F_USERS;
  1331.         break;
  1332.     }
  1333. }
  1334.  
  1335.  
  1336. /*
  1337.  *  Decode a symbolic name to a numeric value
  1338.  */
  1339.  
  1340. decode(name, codetab)
  1341.     char *name;
  1342.     CODE *codetab;
  1343. {
  1344.     register CODE *c;
  1345.     register char *p;
  1346.     char buf[40];
  1347.  
  1348.     if (isdigit(*name))
  1349.         return (atoi(name));
  1350.  
  1351.     (void) strcpy(buf, name);
  1352.     for (p = buf; *p; p++)
  1353.         if (isupper(*p))
  1354.             *p = tolower(*p);
  1355.     for (c = codetab; c->c_name; c++)
  1356.         if (!strcmp(buf, c->c_name))
  1357.             return (c->c_val);
  1358.  
  1359.     return (-1);
  1360. }
  1361.  
  1362. #ifdef KLOG_STREAM
  1363.  
  1364. int klogread(fd, buf, size)
  1365.     int fd;
  1366.     char *buf;
  1367.     int size;
  1368. {
  1369.     static char line[MAXLINE];
  1370.     static char *pos = line;
  1371.  
  1372.     int i;
  1373.     char *obuf = buf;
  1374.     char *s;
  1375.     char *end;
  1376.     *pos = '\0';    
  1377.     if (!(end = strchr(line, '\n'))) {
  1378.         struct timeval tv;
  1379.         fd_set readfds;
  1380.  
  1381.         tv.tv_sec = tv.tv_usec = 0;
  1382.         FD_ZERO(&readfds);
  1383.         FD_SET(fd, &readfds);
  1384.         i = select(fd + 1, (fd_set *) &readfds, (fd_set *) NULL,
  1385.             (fd_set *) NULL, &tv);
  1386.         if (i <= 0)
  1387.             return i;
  1388.         i = read(fd, pos, sizeof(line) - 1 - (pos - line));
  1389.         if (i <= 0)
  1390.             return i;
  1391.         pos += i;
  1392.         *pos = '\0';
  1393.         if (!(end = strchr(line, '\n')))
  1394.             return 0;
  1395.     }
  1396.     for (s = line; s < end; s++)
  1397.         if (*s != '\r')
  1398.             *buf++ = *s;
  1399.     end++;
  1400.     for (s = line; end < pos; s++)
  1401.         *s = *end++;
  1402.     pos = s;
  1403.     return (buf - obuf);
  1404. }
  1405.  
  1406. #endif /* KLOG_STREAM */
  1407.