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