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