LCOV - code coverage report
Current view: top level - src - syslogd.c (source / functions) Hit Total Coverage
Test: GNU inetutils Lines: 515 1054 48.9 %
Date: 2015-05-12 15:20:19 Functions: 20 26 76.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* syslogd - log system messages
       2             :   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
       3             :   2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software
       4             :   Foundation, Inc.
       5             : 
       6             :   This file is part of GNU Inetutils.
       7             : 
       8             :   GNU Inetutils is free software: you can redistribute it and/or modify
       9             :   it under the terms of the GNU General Public License as published by
      10             :   the Free Software Foundation, either version 3 of the License, or (at
      11             :   your option) any later version.
      12             : 
      13             :   GNU Inetutils is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :   General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU General Public License
      19             :   along with this program.  If not, see `http://www.gnu.org/licenses/'. */
      20             : 
      21             : /*
      22             :  * Copyright (c) 1983, 1988, 1993, 1994
      23             :  *      The Regents of the University of California.  All rights reserved.
      24             :  *
      25             :  * Redistribution and use in source and binary forms, with or without
      26             :  * modification, are permitted provided that the following conditions
      27             :  * are met:
      28             :  * 1. Redistributions of source code must retain the above copyright
      29             :  *    notice, this list of conditions and the following disclaimer.
      30             :  * 2. Redistributions in binary form must reproduce the above copyright
      31             :  *    notice, this list of conditions and the following disclaimer in the
      32             :  *    documentation and/or other materials provided with the distribution.
      33             :  * 3. Neither the name of the University nor the names of its contributors
      34             :  *    may be used to endorse or promote products derived from this software
      35             :  *    without specific prior written permission.
      36             :  *
      37             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      38             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      39             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      40             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      41             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      42             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      43             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      44             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      45             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      46             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      47             :  * SUCH DAMAGE.
      48             :  */
      49             : 
      50             : /*
      51             :  *  syslogd -- log system messages
      52             :  *
      53             :  * This program implements a system log. It takes a series of lines.
      54             :  * Each line may have a priority, signified as "<n>" as the first
      55             :  * characters of the line.  If this is not present, a default priority
      56             :  * is used.
      57             :  *
      58             :  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup)
      59             :  * will cause it to reread its configuration file.
      60             :  *
      61             :  * Defined Constants:
      62             :  *
      63             :  * MAXLINE -- the maximum line length that can be handled.
      64             :  * DEFUPRI -- the default priority for user messages
      65             :  * DEFSPRI -- the default priority for kernel messages
      66             :  *
      67             :  * Author: Eric Allman
      68             :  * extensive changes by Ralph Campbell
      69             :  * more extensive changes by Eric Allman (again)
      70             :  */
      71             : 
      72             : #include <config.h>
      73             : 
      74             : #define IOVCNT          6       /* size of the iovec array */
      75             : #define MAXLINE         1024    /* Maximum line length.  */
      76             : #define MAXSVLINE       240     /* Maximum saved line length.  */
      77             : #define DEFUPRI         (LOG_USER|LOG_NOTICE)
      78             : #define DEFSPRI         (LOG_KERN|LOG_CRIT)
      79             : #define TIMERINTVL      30      /* Interval for checking flush, mark.  */
      80             : #define TTYMSGTIME      10      /* Time out passed to ttymsg.  */
      81             : 
      82             : #include <sys/param.h>
      83             : #include <sys/ioctl.h>
      84             : #include <sys/stat.h>
      85             : #include <sys/wait.h>
      86             : #include <sys/socket.h>
      87             : #include <sys/uio.h>
      88             : #include <sys/un.h>
      89             : #include <sys/time.h>
      90             : #include <time.h>
      91             : #include <sys/resource.h>
      92             : #include <poll.h>
      93             : #include <sys/types.h>
      94             : 
      95             : #include <netinet/in.h>
      96             : #include <netdb.h>
      97             : #include <arpa/inet.h>
      98             : 
      99             : #include <argp.h>
     100             : #include <ctype.h>
     101             : #include <errno.h>
     102             : #include <fcntl.h>
     103             : #include <setjmp.h>
     104             : #include <signal.h>
     105             : #include <stdio.h>
     106             : #include <stdlib.h>
     107             : #include <string.h>
     108             : #include <dirent.h>
     109             : #include <unistd.h>
     110             : 
     111             : #include <stdarg.h>
     112             : 
     113             : #define SYSLOG_NAMES
     114             : #include <syslog.h>
     115             : #ifndef HAVE_SYSLOG_INTERNAL
     116             : # include "logprio.h"
     117             : #endif
     118             : 
     119             : #ifndef LOG_MAKEPRI
     120             : #  define LOG_MAKEPRI(fac, p)   ((fac) | (p))
     121             : #endif
     122             : 
     123             : #include <error.h>
     124             : #include <progname.h>
     125             : #include <libinetutils.h>
     126             : #include <readutmp.h>             /* May define UTMP_NAME_FUNCTION.  */
     127             : #include "unused-parameter.h"
     128             : #include "xalloc.h"
     129             : 
     130             : /* A mask of all facilities mentioned explicitly in the configuration file
     131             :  *
     132             :  * This is used to support a virtual facility "**" that covers all the rest,
     133             :  * so that messages to unexpected facilities won't be lost when "*" is
     134             :  * not logged to a file.
     135             :  */
     136             : int facilities_seen;
     137             : 
     138             : char *selector;                 /* Program origin to select.  */
     139             : 
     140             : const char *ConfFile = PATH_LOGCONF;    /* Default Configuration file.  */
     141             : const char *ConfDir = PATH_LOGCONFD;    /* Default Configuration directory.  */
     142             : const char *PidFile = PATH_LOGPID;      /* Default path to tuck pid.  */
     143             : char ctty[] = PATH_CONSOLE;     /* Default console to send message info.  */
     144             : 
     145             : static int dbg_output;          /* If true, print debug output in debug mode.  */
     146             : static int restart;             /* If 1, indicates SIGHUP was dropped.  */
     147             : 
     148             : /* Unix socket family to listen.  */
     149             : struct funix
     150             : {
     151             :   const char *name;
     152             :   int fd;
     153             : } *funix;
     154             : 
     155             : size_t nfunix;                  /* Number of unix sockets in the funix array.  */
     156             : 
     157             : /*
     158             :  * Flags to logmsg().
     159             :  */
     160             : 
     161             : #define IGN_CONS        0x001   /* Don't print on console.  */
     162             : #define SYNC_FILE       0x002   /* Do fsync on file after printing.  */
     163             : #define ADDDATE         0x004   /* Add a date to the message.  */
     164             : #define MARK            0x008   /* This message is a mark.  */
     165             : 
     166             : /* This structure represents the files that will have log copies
     167             :    printed.  */
     168             : 
     169             : struct filed
     170             : {
     171             :   struct filed *f_next;         /* Next in linked list.  */
     172             :   short f_type;                 /* Entry type, see below.  */
     173             :   short f_file;                 /* File descriptor.  */
     174             :   time_t f_time;                /* Time this was last written.  */
     175             :   unsigned char f_pmask[LOG_NFACILITIES + 1];   /* Priority mask.  */
     176             :   union
     177             :   {
     178             :     struct
     179             :     {
     180             :       int f_nusers;
     181             :       char **f_unames;
     182             :     } f_user;                   /* Send a message to a user.  */
     183             :     struct
     184             :     {
     185             :       char *f_hname;
     186             :       struct sockaddr_storage f_addr;
     187             :       socklen_t f_addrlen;
     188             :     } f_forw;                   /* Forwarding address.  */
     189             :     char *f_fname;              /* Name use for Files|Pipes|TTYs.  */
     190             :   } f_un;
     191             :   char f_prevline[MAXSVLINE];   /* Last message logged.  */
     192             :   char f_lasttime[16];          /* Time of last occurrence.  */
     193             :   char *f_prevhost;             /* Host from which recd.  */
     194             :   char *f_progname;             /* Submitting program.  */
     195             :   int f_prognlen;               /* Length of the same.  */
     196             :   int f_prevpri;                /* Pri of f_prevline.  */
     197             :   int f_prevlen;                /* Length of f_prevline.  */
     198             :   int f_prevcount;              /* Repetition cnt of prevline.  */
     199             :   size_t f_repeatcount;         /* Number of "repeated" msgs.  */
     200             :   int f_flags;                  /* Additional flags see below.  */
     201             : };
     202             : 
     203             : struct filed *Files;            /* Linked list of files to log to.  */
     204             : struct filed consfile;          /* Console `file'.  */
     205             : 
     206             : /* Values for f_type.  */
     207             : #define F_UNUSED        0       /* Unused entry.  */
     208             : #define F_FILE          1       /* Regular file.  */
     209             : #define F_TTY           2       /* Terminal.  */
     210             : #define F_CONSOLE       3       /* Console terminal.  */
     211             : #define F_FORW          4       /* Remote machine.  */
     212             : #define F_USERS         5       /* List of users.  */
     213             : #define F_WALL          6       /* Everyone logged on.  */
     214             : #define F_FORW_SUSP     7       /* Suspended host forwarding.  */
     215             : #define F_FORW_UNKN     8       /* Unknown host forwarding.  */
     216             : #define F_PIPE          9       /* Named pipe.  */
     217             : 
     218             : const char *TypeNames[] = {
     219             :   "UNUSED",
     220             :   "FILE",
     221             :   "TTY",
     222             :   "CONSOLE",
     223             :   "FORW",
     224             :   "USERS",
     225             :   "WALL",
     226             :   "FORW(SUSPENDED)",
     227             :   "FORW(UNKNOWN)",
     228             :   "PIPE"
     229             : };
     230             : 
     231             : /* Flags in filed.f_flags.  */
     232             : #define OMIT_SYNC       0x001   /* Omit fsync after printing.  */
     233             : 
     234             : /* Constants for the F_FORW_UNKN retry feature.  */
     235             : #define INET_SUSPEND_TIME 180   /* Number of seconds between attempts.  */
     236             : #define INET_RETRY_MAX  10      /* Number of times to try gethostbyname().  */
     237             : 
     238             : /* Intervals at which we flush out "message repeated" messages, in
     239             :  seconds after previous message is logged.  After each flush, we move
     240             :  to the next interval until we reach the largest.  */
     241             : 
     242             : int repeatinterval[] = { 30, 60 };      /* Number of seconds before flush.  */
     243             : 
     244             : #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
     245             : #define REPEATTIME(f)   ((f)->f_time + repeatinterval[(f)->f_repeatcount])
     246             : #define BACKOFF(f)      { if (++(f)->f_repeatcount > MAXREPEAT) \
     247             :                                  (f)->f_repeatcount = MAXREPEAT; \
     248             :                         }
     249             : 
     250             : /* Delimiter in arguments to command line options `-s' and `-l'.  */
     251             : #define LIST_DELIMITER  ':'
     252             : 
     253             : extern int waitdaemon (int nochdir, int noclose, int maxwait);
     254             : 
     255             : void cfline (const char *, struct filed *);
     256             : const char *cvthname (struct sockaddr *, socklen_t);
     257             : int decode (const char *, CODE *);
     258             : void die (int);
     259             : void doexit (int);
     260             : void domark (int);
     261             : void find_inet_port (const char *);
     262             : void fprintlog (struct filed *, const char *, int, const char *);
     263             : static int load_conffile (const char *, struct filed **);
     264             : static int load_confdir (const char *, struct filed **);
     265             : void init (int);
     266             : void logerror (const char *);
     267             : void logmsg (int, const char *, const char *, int);
     268             : void printline (const char *, const char *);
     269             : void printsys (const char *);
     270             : char *ttymsg (struct iovec *, int, char *, int);
     271             : void wallmsg (struct filed *, struct iovec *);
     272             : char **crunch_list (char **oldlist, char *list);
     273             : char *textpri (int pri);
     274             : void dbg_toggle (int);
     275             : static void dbg_printf (const char *, ...);
     276             : void trigger_restart (int);
     277             : static void add_funix (const char *path);
     278             : static int create_unix_socket (const char *path);
     279             : static void create_inet_socket (int af, int fd46[2]);
     280             : 
     281             : char *LocalHostName;            /* Our hostname.  */
     282             : char *LocalDomain;              /* Our local domain name.  */
     283             : char *BindAddress = NULL;       /* Binding address for INET listeners.
     284             :                                  * The default is a wildcard address.  */
     285             : char *BindPort = NULL;          /* Optional non-standard port, instead
     286             :                                  * of the usual 514/udp.  */
     287             : #ifdef IPPORT_SYSLOG
     288             : char portstr[8];                /* Fallback port number.  */
     289             : #endif
     290             : char addrstr[INET6_ADDRSTRLEN]; /* Common address presentation.  */
     291             : char addrname[NI_MAXHOST];      /* Common name lookup.  */
     292             : int usefamily = AF_INET;        /* Address family for INET services.
     293             :                                  * Each of the values `AF_INET' and `AF_INET6'
     294             :                                  * produces a single-stacked server.  */
     295             : int finet[2] = {-1, -1};        /* Internet datagram socket fd.  */
     296             : #define IU_FD_IP4       0       /* Indices for the address families.  */
     297             : #define IU_FD_IP6       1
     298             : int fklog = -1;                 /* Kernel log device fd.  */
     299             : char *LogPortText = NULL;       /* Service/port for INET connections.  */
     300             : char *LogForwardPort = NULL;    /* Target port for message forwarding.  */
     301             : int Initialized;                /* True when we are initialized. */
     302             : int MarkInterval = 20 * 60;     /* Interval between marks in seconds.  */
     303             : int MarkSeq;                    /* Mark sequence number.  */
     304             : 
     305             : int Debug;                      /* True if in debug mode.  */
     306             : int AcceptRemote;               /* Receive messages that come via UDP.  */
     307             : char **StripDomains;            /* Domains to be stripped before logging.  */
     308             : char **LocalHosts;              /* Hosts to be logged by their hostname.  */
     309             : int NoDetach;                   /* Don't run in background and detach
     310             :                                    from ctty. */
     311             : int NoHops = 1;                 /* Bounce syslog messages for other hosts.  */
     312             : int NoKLog;                     /* Don't attempt to log kernel device.  */
     313             : int NoUnixAF;                   /* Don't listen to unix sockets. */
     314             : int NoForward;                  /* Don't forward messages.  */
     315             : time_t now;                     /* Time use for mark and forward supending.  */
     316             : int force_sync;                 /* GNU/Linux behaviour to sync on every line.
     317             :                                    This off by default. Set to 1 to enable.  */
     318             : int set_local_time = 0;         /* Record local time, not message time.  */
     319             : 
     320             : const char args_doc[] = "";
     321             : const char doc[] = "Log system messages.";
     322             : 
     323             : /* Define keys for long options that do not have short counterparts. */
     324             : enum {
     325             :   OPT_NO_FORWARD = 256,
     326             :   OPT_NO_KLOG,
     327             :   OPT_NO_UNIXAF,
     328             :   OPT_IPANY
     329             : };
     330             : 
     331             : static struct argp_option argp_options[] = {
     332             : #define GRP 0
     333             :   /* Not sure about the long name. Maybe move into conffile even. */
     334             :   {NULL, 'a', "SOCKET", 0, "add unix socket to listen to (up to 19)", GRP+1},
     335             :   {NULL, 'l', "HOSTLIST", 0, "log hosts in HOSTLIST by their hostname", GRP+1},
     336             :   {NULL, 's', "DOMAINLIST", 0, "list of domains which should be stripped "
     337             :    "from the FQDN of hosts before logging their name", GRP+1},
     338             :   {"debug", 'd', NULL, 0, "print debug information (implies --no-detach)",
     339             :    GRP+1},
     340             :   {"hop", 'h', NULL, 0, "forward messages from remote hosts", GRP+1},
     341             :   {"inet", 'r', NULL, 0, "receive remote messages via internet domain socket",
     342             :    GRP+1},
     343             :   {"ipv4", '4', NULL, 0, "restrict to IPv4 transport (default)", GRP+1},
     344             :   {"ipv6", '6', NULL, 0, "restrict to IPv6 transport", GRP+1},
     345             :   {"ipany", OPT_IPANY, NULL, 0, "allow transport with IPv4 and IPv6", GRP+1},
     346             :   {"bind", 'b', "ADDR", 0, "bind listener to this address/name", GRP+1},
     347             :   {"bind-port", 'B', "PORT", 0, "bind listener to this port", GRP+1},
     348             :   {"mark", 'm', "INTVL", 0, "specify timestamp interval in minutes"
     349             :    " (0 for no timestamping)", GRP+1},
     350             :   {"no-detach", 'n', NULL, 0, "do not enter daemon mode", GRP+1},
     351             :   {"no-forward", OPT_NO_FORWARD, NULL, 0, "do not forward any messages "
     352             :    "(overrides --hop)", GRP+1},
     353             : #ifdef PATH_KLOG
     354             :   {"no-klog", OPT_NO_KLOG, NULL, 0, "do not listen to kernel log device "
     355             :    PATH_KLOG, GRP+1},
     356             : #endif
     357             :   {"no-unixaf", OPT_NO_UNIXAF, NULL, 0, "do not listen on unix domain "
     358             :    "sockets (overrides -a and -p)", GRP+1},
     359             :   {"pidfile", 'P', "FILE", 0, "override pidfile (default: "
     360             :    PATH_LOGPID ")", GRP+1},
     361             :   {"rcfile", 'f', "FILE", 0, "override configuration file (default: "
     362             :    PATH_LOGCONF ")",
     363             :    GRP+1},
     364             :   {"rcdir", 'D', "DIR", 0, "override configuration directory (default: "
     365             :    PATH_LOGCONFD ")", GRP+1},
     366             :   {"socket", 'p', "FILE", 0, "override default unix domain socket " PATH_LOG,
     367             :    GRP+1},
     368             :   {"sync", 'S', NULL, 0, "force a file sync on every line", GRP+1},
     369             :   {"local-time", 'T', NULL, 0, "set local time on received messages", GRP+1},
     370             : #undef GRP
     371             :   {NULL, 0, NULL, 0, NULL, 0}
     372             : };
     373             : 
     374             : static error_t
     375          15 : parse_opt (int key, char *arg, struct argp_state *state)
     376             : {
     377             :   char *endptr;
     378             :   int v;
     379             : 
     380          15 :   switch (key)
     381             :     {
     382             :     case 'a':
     383           2 :       add_funix (arg);
     384           2 :       break;
     385             : 
     386             :     case 'l':
     387           0 :       LocalHosts = crunch_list (LocalHosts, arg);
     388           0 :       break;
     389             : 
     390             :     case 's':
     391           0 :       StripDomains = crunch_list (StripDomains, arg);
     392           0 :       break;
     393             : 
     394             :     case 'd':
     395           0 :       Debug = 1;
     396           0 :       NoDetach = 1;
     397           0 :       break;
     398             : 
     399             :     case 'h':
     400           1 :       NoHops = 0;
     401           1 :       break;
     402             : 
     403             :     case 'r':
     404           1 :       AcceptRemote = 1;
     405           1 :       break;
     406             : 
     407             :     case '4':
     408           0 :       usefamily = AF_INET;
     409           0 :       break;
     410             : 
     411             :     case '6':
     412           0 :       usefamily = AF_INET6;
     413           0 :       break;
     414             : 
     415             :     case OPT_IPANY:
     416           1 :       usefamily = AF_UNSPEC;
     417           1 :       break;
     418             : 
     419             :     case 'b':
     420           0 :       BindAddress = arg;
     421           0 :       break;
     422             : 
     423             :     case 'B':
     424           1 :       BindPort = arg;
     425           1 :       break;
     426             : 
     427             :     case 'm':
     428           0 :       v = strtol (arg, &endptr, 10);
     429           0 :       if (*endptr)
     430           0 :         argp_error (state, "invalid value (`%s' near `%s')", arg, endptr);
     431           0 :       MarkInterval = v * 60;
     432           0 :       break;
     433             : 
     434             :     case 'n':
     435           0 :       NoDetach = 1;
     436           0 :       break;
     437             : 
     438             :     case OPT_NO_FORWARD:
     439           0 :       NoForward = 1;
     440           0 :       break;
     441             : 
     442             :     case OPT_NO_KLOG:
     443           0 :       NoKLog = 1;
     444           0 :       break;
     445             : 
     446             :     case OPT_NO_UNIXAF:
     447           0 :       NoUnixAF = 1;
     448           0 :       break;
     449             : 
     450             :     case 'P':
     451           1 :       PidFile = arg;
     452           1 :       break;
     453             : 
     454             :     case 'f':
     455           1 :       ConfFile = arg;
     456           1 :       break;
     457             : 
     458             :     case 'D':
     459           1 :       ConfDir = arg;
     460           1 :       break;
     461             : 
     462             :     case 'p':
     463           1 :       funix[0].name = arg;
     464           1 :       funix[0].fd = -1;
     465           1 :       break;
     466             : 
     467             :     case 'S':
     468           0 :       force_sync = 1;
     469           0 :       break;
     470             : 
     471             :     case 'T':
     472           0 :       set_local_time = 1;
     473           0 :       break;
     474             : 
     475             :     default:
     476           5 :       return ARGP_ERR_UNKNOWN;
     477             :     }
     478             : 
     479          10 :   return 0;
     480             : }
     481             : 
     482             : static struct argp argp =
     483             :   {argp_options, parse_opt, args_doc, doc, NULL, NULL, NULL};
     484             : 
     485             : int
     486           1 : main (int argc, char *argv[])
     487             : {
     488             :   size_t i;
     489             :   FILE *fp;
     490             :   char *p;
     491             :   char line[MAXLINE + 1];
     492             :   char kline[MAXLINE + 1];
     493           1 :   int kline_len = 0;
     494           1 :   pid_t ppid = 0;               /* We run in debug mode and didn't fork.  */
     495             :   struct pollfd *fdarray;
     496           1 :   unsigned long nfds = 0;
     497             : #ifdef HAVE_SIGACTION
     498             :   struct sigaction sa;
     499             : #endif
     500             : 
     501           1 :   set_program_name (argv[0]);
     502             : 
     503             :   /* Initialize PATH_LOG as the first element of the unix sockets array.  */
     504           1 :   add_funix (PATH_LOG);
     505             : 
     506             :   /* Parse command line */
     507           1 :   iu_argp_init ("syslogd", default_program_authors);
     508           1 :   argp_parse (&argp, argc, argv, 0, NULL, NULL);
     509             : 
     510             :   /* Check desired port, if in demand at all.  */
     511           1 :   find_inet_port (BindPort);
     512             : 
     513             :   /* Daemonise, if not, set the buffering for line buffer.  */
     514           1 :   if (!NoDetach)
     515             :     {
     516             :       /* History: According to the GNU/Linux sysklogd ChangeLogs "Wed
     517             :          Feb 14 12:42:09 CST 1996: Dr. Wettstein Parent process of
     518             :          syslogd does not exit until child process has finished
     519             :          initialization process.  This allows rc.* startup to pause
     520             :          until syslogd facility is up and operating."
     521             : 
     522             :          IMO, the GNU/Linux distributors should fix there booting
     523             :          sequence.  But we still keep the approach.  */
     524           1 :       signal (SIGTERM, doexit);
     525           1 :       ppid = waitdaemon (0, 0, 30);
     526           1 :       if (ppid < 0)
     527           0 :         error (EXIT_FAILURE, errno, "could not become daemon");
     528             :     }
     529             :   else
     530             :     {
     531           0 :       if (Debug)
     532           0 :         dbg_output = 1;
     533           0 :       setvbuf (stdout, 0, _IOLBF, 0);
     534             :     }
     535             : 
     536             :   /* Get our hostname.  */
     537           1 :   LocalHostName = localhost ();
     538           1 :   if (LocalHostName == NULL)
     539           0 :     error (EXIT_FAILURE, errno, "can't get local host name");
     540             : 
     541             :   /* Get the domainname.  */
     542           1 :   p = strchr (LocalHostName, '.');
     543           1 :   if (p != NULL)
     544             :     {
     545           1 :       *p++ = '\0';
     546           1 :       LocalDomain = p;
     547             :     }
     548             :   else
     549             :     {
     550             :       struct addrinfo hints, *rp;
     551             :       int err;
     552             : 
     553           0 :       memset (&hints, 0, sizeof (hints));
     554           0 :       hints.ai_family = AF_UNSPEC;      /* Family is irrelevant.  */
     555           0 :       hints.ai_flags = AI_CANONNAME;
     556             : 
     557             :       /* Try to resolve the domainname by calling DNS.  */
     558           0 :       err = getaddrinfo (LocalHostName, NULL, &hints, &rp);
     559           0 :       if (err == 0)
     560             :         {
     561             :           /* Override what we had */
     562           0 :           free (LocalHostName);
     563           0 :           LocalHostName = strdup (rp->ai_canonname);
     564           0 :           p = strchr (LocalHostName, '.');
     565           0 :           if (p != NULL)
     566             :             {
     567           0 :               *p++ = '\0';
     568           0 :               LocalDomain = p;
     569             :             }
     570           0 :           freeaddrinfo (rp);
     571             :         }
     572           0 :       if (LocalDomain == NULL)
     573           0 :         LocalDomain = strdup ("");
     574             :     }
     575             : 
     576           1 :   consfile.f_type = F_CONSOLE;
     577           1 :   consfile.f_un.f_fname = strdup (ctty);
     578             : 
     579           1 :   signal (SIGTERM, die);
     580           1 :   signal (SIGINT, NoDetach ? die : SIG_IGN);
     581           1 :   signal (SIGQUIT, NoDetach ? die : SIG_IGN);
     582             : 
     583             : #ifdef HAVE_SIGACTION
     584             :   /* Register repeatable actions portably!  */
     585           1 :   sa.sa_flags = SA_RESTART;
     586           1 :   sigemptyset (&sa.sa_mask);
     587             : 
     588           1 :   sa.sa_handler = domark;
     589           1 :   (void) sigaction (SIGALRM, &sa, NULL);
     590             : 
     591           1 :   sa.sa_handler = NoDetach ? dbg_toggle : SIG_IGN;
     592           1 :   (void) sigaction (SIGUSR1, &sa, NULL);
     593             : #else /* !HAVE_SIGACTION */
     594             :   signal (SIGALRM, domark);
     595             :   signal (SIGUSR1, NoDetach ? dbg_toggle : SIG_IGN);
     596             : #endif
     597             : 
     598           1 :   alarm (TIMERINTVL);
     599             : 
     600             :   /* We add  3 = 1(klog) + 2(inet,inet6), even if they may stay unused.  */
     601           1 :   fdarray = (struct pollfd *) malloc ((nfunix + 3) * sizeof (*fdarray));
     602           1 :   if (fdarray == NULL)
     603           0 :     error (EXIT_FAILURE, errno, "can't allocate fd table");
     604             : 
     605             :   /* read configuration file */
     606           1 :   init (0);
     607             : 
     608             : #ifdef PATH_KLOG
     609             :   /* Initialize kernel logging and add to the list.  */
     610           1 :   if (!NoKLog)
     611             :     {
     612           1 :       fklog = open (PATH_KLOG, O_RDONLY, 0);
     613           1 :       if (fklog >= 0)
     614             :         {
     615           0 :           fdarray[nfds].fd = fklog;
     616           0 :           fdarray[nfds].events = POLLIN | POLLPRI;
     617           0 :           nfds++;
     618           0 :           dbg_printf ("Klog open %s\n", PATH_KLOG);
     619             :         }
     620             :       else
     621           1 :         dbg_printf ("Can't open %s: %s\n", PATH_KLOG, strerror (errno));
     622             :     }
     623             : #endif
     624             : 
     625             :   /* Initialize unix sockets.  */
     626           1 :   if (!NoUnixAF)
     627             :     {
     628           4 :       for (i = 0; i < nfunix; i++)
     629             :         {
     630           3 :           funix[i].fd = create_unix_socket (funix[i].name);
     631           3 :           if (funix[i].fd >= 0)
     632             :             {
     633           2 :               fdarray[nfds].fd = funix[i].fd;
     634           2 :               fdarray[nfds].events = POLLIN | POLLPRI;
     635           2 :               nfds++;
     636           2 :               dbg_printf ("Opened UNIX socket `%s'.\n", funix[i].name);
     637             :             }
     638             :           else
     639           1 :             dbg_printf ("Can't open %s: %s\n", funix[i].name,
     640           1 :                         strerror (errno));
     641             :         }
     642             :     }
     643             : 
     644             :   /* Initialize inet socket and add it to the list.  */
     645           1 :   if (AcceptRemote)
     646             :     {
     647           1 :       create_inet_socket (usefamily, finet);
     648           1 :       if (finet[IU_FD_IP4] >= 0)
     649             :         {
     650             :           /* IPv4 socket is present.  */
     651           1 :           fdarray[nfds].fd = finet[IU_FD_IP4];
     652           1 :           fdarray[nfds].events = POLLIN | POLLPRI;
     653           1 :           nfds++;
     654           1 :           dbg_printf ("Opened syslog UDP/IPv4 port.\n");
     655             :         }
     656           1 :       if (finet[IU_FD_IP6] >= 0)
     657             :         {
     658             :           /* IPv6 socket is present.  */
     659           1 :           fdarray[nfds].fd = finet[IU_FD_IP6];
     660           1 :           fdarray[nfds].events = POLLIN | POLLPRI;
     661           1 :           nfds++;
     662           1 :           dbg_printf ("Opened syslog UDP/IPv6 port.\n");
     663             :         }
     664           1 :       if (finet[IU_FD_IP4] < 0 && finet[IU_FD_IP6] < 0)
     665           0 :         dbg_printf ("Can't open UDP port: %s\n", strerror (errno));
     666             :     }
     667             : 
     668             :   /* Tuck my process id away.  */
     669           1 :   fp = fopen (PidFile, "w");
     670           1 :   if (fp != NULL)
     671             :     {
     672           1 :       fprintf (fp, "%d\n", (int) getpid ());
     673           1 :       fclose (fp);
     674             :     }
     675             : 
     676           1 :   dbg_printf ("off & running....\n");
     677             : 
     678             : #ifdef HAVE_SIGACTION
     679             :   /* `sa' has been cleared already.  */
     680           1 :   sa.sa_handler = trigger_restart;
     681           1 :   (void) sigaction (SIGHUP, &sa, NULL);
     682             : #else /* !HAVE_SIGACTION */
     683             :   signal (SIGHUP, trigger_restart);
     684             : #endif
     685             : 
     686           1 :   if (NoDetach)
     687             :     {
     688           0 :       dbg_output = 1;
     689           0 :       dbg_printf ("Debugging is disabled. Send SIGUSR1 to PID=%d "
     690             :                   "to turn on debugging.\n", (int) getpid ());
     691           0 :       dbg_output = 0;
     692             :     }
     693             : 
     694             :   /* If we're doing waitdaemon(), tell the parent to exit,
     695             :      we are ready to roll.  */
     696           1 :   if (ppid)
     697           1 :     kill (ppid, SIGTERM);
     698             : 
     699             :   for (;;)
     700             :     {
     701             :       int nready;
     702          16 :       nready = poll (fdarray, nfds, -1);
     703          15 :       if (nready == 0)          /* ??  noop */
     704           0 :         continue;
     705             : 
     706             :       /* Sighup was dropped.  */
     707          15 :       if (restart)
     708             :         {
     709           1 :           dbg_printf ("\nReceived SIGHUP, restarting syslogd.\n");
     710           1 :           init (0);
     711           1 :           restart = 0;
     712           1 :           continue;
     713             :         }
     714             : 
     715          14 :       if (nready < 0)
     716             :         {
     717           0 :           if (errno != EINTR)
     718           0 :             logerror ("poll");
     719           0 :           continue;
     720             :         }
     721             : 
     722             :       /*dbg_printf ("got a message (%d)\n", nready); */
     723             : 
     724          70 :       for (i = 0; i < nfds; i++)
     725          56 :         if (fdarray[i].revents & (POLLIN | POLLPRI))
     726             :           {
     727             :             int result;
     728             :             socklen_t len;
     729          14 :             if (fdarray[i].fd == -1)
     730           0 :               continue;
     731          14 :             else if (fdarray[i].fd == fklog)
     732             :               {
     733           0 :                 result = read (fdarray[i].fd, &kline[kline_len],
     734             :                                sizeof (kline) - kline_len - 1);
     735             : 
     736           0 :                 if (result > 0)
     737             :                   {
     738           0 :                     kline_len += result;
     739             :                   }
     740           0 :                 else if (result < 0 && errno != EINTR)
     741             :                   {
     742           0 :                     logerror ("klog");
     743           0 :                     fdarray[i].fd = fklog = -1;
     744             :                   }
     745             : 
     746             :                 while (1)
     747             :                   {
     748             :                     char *bol, *eol;
     749             : 
     750           0 :                     kline[kline_len] = '\0';
     751             : 
     752           0 :                     for (bol = kline, eol = strchr (kline, '\n'); eol;
     753           0 :                          bol = eol, eol = strchr (bol, '\n'))
     754             :                       {
     755           0 :                         *(eol++) = '\0';
     756           0 :                         kline_len -= (eol - bol);
     757           0 :                         printsys (bol);
     758             :                       }
     759             : 
     760             :                     /* This loop makes sure the daemon won't lock up
     761             :                      * on null bytes in the klog stream.  They still hurt
     762             :                      * efficiency, acting like a message separator that
     763             :                      * forces a shift-and-reiterate when the buffer was
     764             :                      * never full.
     765             :                      */
     766           0 :                     while (kline_len && !*bol)
     767             :                       {
     768           0 :                         bol++;
     769           0 :                         kline_len--;
     770             :                       }
     771             : 
     772           0 :                     if (!kline_len)
     773           0 :                       break;
     774             : 
     775           0 :                     if (bol != kline)
     776             :                       {
     777             :                         /* shift the partial line to start of buffer, so
     778             :                          * we can re-iterate.
     779             :                          */
     780           0 :                         memmove (kline, bol, kline_len);
     781             :                       }
     782             :                     else
     783             :                       {
     784           0 :                         if (kline_len < MAXLINE)
     785           0 :                           break;
     786             : 
     787             :                         /* The pathological case of a single message that
     788             :                          * overfills our buffer.  The best we can do is
     789             :                          * log it in pieces.
     790             :                          */
     791           0 :                         printsys (kline);
     792             : 
     793             :                         /* Clone priority signal if present
     794             :                          * We merely shift the kline_len pointer after
     795             :                          * it so the next chunk is written after it.
     796             :                          *
     797             :                          * strchr(kline,'>') is not used as it would allow
     798             :                          * a pathological line ending in '>' to cause an
     799             :                          * endless loop.
     800             :                          */
     801           0 :                         if (kline[0] == '<'
     802           0 :                             && isdigit (kline[1]) && kline[2] == '>')
     803           0 :                           kline_len = 3;
     804             :                         else
     805           0 :                           kline_len = 0;
     806             :                       }
     807           0 :                   }
     808             :               }
     809          14 :             else if (fdarray[i].fd == finet[IU_FD_IP4]
     810          11 :                      || fdarray[i].fd == finet[IU_FD_IP6])
     811           4 :               {
     812             :                 struct sockaddr_storage frominet;
     813             :                 /*dbg_printf ("inet message\n"); */
     814           4 :                 len = sizeof (frominet);
     815           4 :                 memset (line, '\0', sizeof (line));
     816           4 :                 result = recvfrom (fdarray[i].fd, line, MAXLINE, 0,
     817             :                                    (struct sockaddr *) &frominet, &len);
     818           4 :                 if (result > 0)
     819             :                   {
     820           4 :                     line[result] = '\0';
     821           4 :                     printline (cvthname ((struct sockaddr *) &frominet, len), line);
     822             :                   }
     823           0 :                 else if (result < 0 && errno != EINTR)
     824           0 :                   logerror ("recvfrom inet");
     825             :               }
     826             :             else
     827             :               {
     828             :                 struct sockaddr_un fromunix;
     829             :                 /*dbg_printf ("unix message\n"); */
     830          10 :                 len = sizeof (fromunix);
     831          10 :                 result = recvfrom (fdarray[i].fd, line, MAXLINE, 0,
     832             :                                    (struct sockaddr *) &fromunix, &len);
     833          10 :                 if (result > 0)
     834             :                   {
     835          10 :                     line[result] = '\0';
     836          10 :                     printline (LocalHostName, line);
     837             :                   }
     838           0 :                 else if (result < 0 && errno != EINTR)
     839           0 :                   logerror ("recvfrom unix");
     840             :               }
     841             :           }
     842          42 :         else if (fdarray[i].revents & POLLNVAL)
     843             :           {
     844           0 :             logerror ("poll nval\n");
     845           0 :             fdarray[i].fd = -1;
     846             :           }
     847          42 :         else if (fdarray[i].revents & POLLERR)
     848           0 :           logerror ("poll err\n");
     849          42 :         else if (fdarray[i].revents & POLLHUP)
     850           0 :           logerror ("poll hup\n");
     851          15 :     }                           /* for (;;) */
     852             : }                               /* main */
     853             : 
     854             : #ifndef SUN_LEN
     855             : # define SUN_LEN(unp) (strlen((unp)->sun_path) + 3)
     856             : #endif
     857             : 
     858             : static void
     859           3 : add_funix (const char *name)
     860             : {
     861           3 :   funix = realloc (funix, (nfunix + 1) * sizeof (*funix));
     862           3 :   if (funix == NULL)
     863           0 :     error (EXIT_FAILURE, errno, "cannot allocate space for unix sockets");
     864             : 
     865           3 :   funix[nfunix].name = name;
     866           3 :   funix[nfunix].fd = -1;
     867           3 :   nfunix++;
     868           3 : }
     869             : 
     870             : static int
     871           3 : create_unix_socket (const char *path)
     872             : {
     873             :   int fd;
     874             :   struct sockaddr_un sunx;
     875             :   char line[MAXLINE + 1];
     876             : 
     877           3 :   if (path[0] == '\0')
     878           0 :     return -1;
     879             : 
     880           3 :   if (strlen (path) >= sizeof (sunx.sun_path))
     881             :     {
     882           1 :       snprintf (line, sizeof (line), "UNIX socket name too long: %s", path);
     883           1 :       logerror (line);
     884           1 :       return -1;
     885             :     }
     886             : 
     887           2 :   unlink (path);
     888             : 
     889           2 :   memset (&sunx, 0, sizeof (sunx));
     890           2 :   sunx.sun_family = AF_UNIX;
     891           2 :   strncpy (sunx.sun_path, path, sizeof (sunx.sun_path) - 1);
     892           2 :   fd = socket (AF_UNIX, SOCK_DGRAM, 0);
     893           2 :   if (fd < 0 || bind (fd, (struct sockaddr *) &sunx, SUN_LEN (&sunx)) < 0
     894           2 :       || chmod (path, 0666) < 0)
     895             :     {
     896           0 :       snprintf (line, sizeof (line), "cannot create %s", path);
     897           0 :       logerror (line);
     898           0 :       dbg_printf ("cannot create %s: %s\n", path, strerror (errno));
     899           0 :       close (fd);
     900           0 :       fd = -1;
     901             :     }
     902           2 :   return fd;
     903             : }
     904             : 
     905             : static void
     906           1 : create_inet_socket (int af, int fd46[2])
     907             : {
     908           1 :   int err, fd = -1;
     909             :   struct addrinfo hints, *rp, *ai;
     910             : 
     911             :   /* Invalidate old descriptors.  */
     912           1 :   fd46[IU_FD_IP4] = fd46[IU_FD_IP6] = -1;
     913             : 
     914           1 :   if (!LogPortText)
     915             :     {
     916           0 :       dbg_printf ("No listen port has been accepted.\n");
     917           0 :       return;
     918             :     }
     919             : 
     920           1 :   memset (&hints, 0, sizeof (hints));
     921           1 :   hints.ai_family = af;
     922           1 :   hints.ai_socktype = SOCK_DGRAM;
     923           1 :   hints.ai_flags = AI_PASSIVE;
     924             : 
     925           1 :   err = getaddrinfo (BindAddress, LogPortText, &hints, &rp);
     926           1 :   if (err)
     927             :     {
     928           0 :       logerror ("lookup error, suspending inet service");
     929           0 :       return;
     930             :     }
     931             : 
     932           3 :   for (ai = rp; ai; ai = ai->ai_next)
     933             :     {
     934           2 :       int yes = 1;
     935             : 
     936           2 :       fd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     937           2 :       if (fd < 0)
     938           0 :         continue;
     939             : 
     940           2 :       err = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes));
     941           2 :       if (err < 0)
     942           0 :         logerror ("failed to set SO_REUSEADDR");
     943             : 
     944           2 :       if (ai->ai_family == AF_INET6)
     945             :         {
     946             :           /* Avoid dual stacked sockets.  Better to use distinct sockets.  */
     947           1 :           (void) setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof (yes));
     948             :         }
     949             : 
     950           2 :       if (bind (fd, ai->ai_addr, ai->ai_addrlen) < 0)
     951             :         {
     952           0 :           close (fd);
     953           0 :           fd = -1;
     954           0 :           continue;
     955             :         }
     956             :       /* Register any success.  */
     957           2 :       if (ai->ai_family == AF_INET && fd46[IU_FD_IP4] < 0)
     958           1 :         fd46[IU_FD_IP4] = fd;
     959           1 :       else if (ai->ai_family == AF_INET6 && fd46[IU_FD_IP6] < 0)
     960           1 :         fd46[IU_FD_IP6] = fd;
     961             :     }
     962           1 :   freeaddrinfo (rp);
     963             : 
     964           1 :   if (fd46[IU_FD_IP4] < 0 && fd46[IU_FD_IP6] < 0)
     965             :     {
     966           0 :       logerror ("inet service, failed lookup.");
     967           0 :       return;
     968             :     }
     969           1 :   return;
     970             : }
     971             : 
     972             : char **
     973           0 : crunch_list (char **oldlist, char *list)
     974             : {
     975             :   int count, i;
     976             :   char *p, *q;
     977             : 
     978           0 :   p = list;
     979             : 
     980             :   /* Strip off trailing delimiters.  */
     981           0 :   while (p[strlen (p) - 1] == LIST_DELIMITER)
     982             :     {
     983           0 :       p[strlen (p) - 1] = '\0';
     984             :     }
     985             :   /* Cut off leading delimiters.  */
     986           0 :   while (p[0] == LIST_DELIMITER)
     987             :     {
     988           0 :       p++;
     989             :     }
     990             : 
     991             :   /* Bailout early the string is empty.  */
     992           0 :   if (*p == '\0')
     993           0 :     return oldlist;
     994             : 
     995             :   /* Count delimiters to calculate elements.  */
     996           0 :   for (count = 1, i = 0; p[i]; i++)
     997           0 :     if (p[i] == LIST_DELIMITER)
     998           0 :       count++;
     999             : 
    1000             :   /* Count how many we add in the old list.  */
    1001           0 :   for (i = 0; oldlist && oldlist[i]; i++)
    1002             :     ;
    1003             : 
    1004             :   /* allocate enough space */
    1005           0 :   oldlist = (char **) realloc (oldlist, (i + count + 1) * sizeof (*oldlist));
    1006           0 :   if (oldlist == NULL)
    1007           0 :     error (EXIT_FAILURE, errno, "can't allocate memory");
    1008             : 
    1009             :   /*
    1010             :      We now can assume that the first and last
    1011             :      characters are different from any delimiters,
    1012             :      so we don't have to care about it anymore.  */
    1013             : 
    1014             :   /* Start from where we left last time.  */
    1015           0 :   for (count = i; (q = strchr (p, LIST_DELIMITER)) != NULL;
    1016           0 :        count++, p = q, p++)
    1017             :     {
    1018           0 :       oldlist[count] = (char *) malloc ((q - p + 1) * sizeof (char));
    1019           0 :       if (oldlist[count] == NULL)
    1020           0 :         error (EXIT_FAILURE, errno, "can't allocate memory");
    1021             : 
    1022           0 :       strncpy (oldlist[count], p, q - p);
    1023           0 :       oldlist[count][q - p] = '\0';
    1024             :     }
    1025             : 
    1026             :   /* take the last one */
    1027           0 :   oldlist[count] = (char *) xmalloc ((strlen (p) + 1) * sizeof (char));
    1028           0 :   if (oldlist[count] == NULL)
    1029           0 :     error (EXIT_FAILURE, errno, "can't allocate memory");
    1030             : 
    1031           0 :   strcpy (oldlist[count], p);
    1032             : 
    1033           0 :   oldlist[++count] = NULL;      /* terminate the array with a NULL */
    1034             : 
    1035           0 :   if (Debug)
    1036             :     {
    1037           0 :       for (count = 0; oldlist[count]; count++)
    1038           0 :         printf ("#%d: %s\n", count, oldlist[count]);
    1039             :     }
    1040           0 :   return oldlist;
    1041             : }
    1042             : 
    1043             : /* Take a raw input line, decode the message, and print the message on
    1044             :    the appropriate log files.  */
    1045             : void
    1046          14 : printline (const char *hname, const char *msg)
    1047             : {
    1048             :   int c, pri;
    1049             :   const char *p;
    1050             :   char *q, line[MAXLINE + 1];
    1051             : 
    1052             :   /* test for special codes */
    1053          14 :   pri = DEFUPRI;
    1054          14 :   p = msg;
    1055          14 :   if (*p == '<')
    1056             :     {
    1057          14 :       pri = 0;
    1058          58 :       while (isdigit (*++p))
    1059          30 :         pri = 10 * pri + (*p - '0');
    1060          14 :       if (*p == '>')
    1061          14 :         ++p;
    1062             :     }
    1063             : 
    1064             :   /* This overrides large positive and overflowing negative values.  */
    1065          14 :   if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
    1066           0 :     pri = DEFUPRI;
    1067             : 
    1068             :   /* Avoid undefined facilities.  */
    1069          14 :   if (LOG_FAC (pri) > LOG_NFACILITIES)
    1070           1 :     pri = DEFUPRI;
    1071             : 
    1072             :   /* Do not allow users to log kernel messages.  */
    1073          14 :   if (LOG_FAC (pri) == (LOG_KERN >> 3))
    1074           0 :     pri = LOG_MAKEPRI (LOG_USER, LOG_PRI (pri));
    1075             : 
    1076          14 :   q = line;
    1077        1088 :   while ((c = *p++) != '\0' && q < &line[sizeof (line) - 1])
    1078        1060 :     if (iscntrl (c))
    1079           0 :       if (c == '\n')
    1080           0 :         *q++ = ' ';
    1081           0 :       else if (c == '\t')
    1082           0 :         *q++ = '\t';
    1083           0 :       else if (c >= 0177)
    1084           0 :         *q++ = c;
    1085             :       else
    1086             :         {
    1087           0 :           *q++ = '^';
    1088           0 :           *q++ = c ^ 0100;
    1089             :         }
    1090             :     else
    1091        1060 :       *q++ = c;
    1092          14 :   *q = '\0';
    1093             : 
    1094             :   /* This for the default behaviour on GNU/Linux syslogd who
    1095             :      sync on every line.  */
    1096          14 :   if (force_sync)
    1097           0 :     logmsg (pri, line, hname, SYNC_FILE);
    1098             :   else
    1099          14 :     logmsg (pri, line, hname, 0);
    1100          14 : }
    1101             : 
    1102             : /* Take a raw input line from /dev/klog, split and format similar to
    1103             :    syslog().  */
    1104             : void
    1105           0 : printsys (const char *msg)
    1106             : {
    1107             :   int c, pri, flags;
    1108             :   char *lp, *q, line[MAXLINE + 1];
    1109             :   const char *p;
    1110             : 
    1111           0 :   strcpy (line, "vmunix: ");
    1112           0 :   lp = line + strlen (line);
    1113           0 :   for (p = msg; *p != '\0';)
    1114             :     {
    1115           0 :       flags = SYNC_FILE | ADDDATE;      /* Fsync after write.  */
    1116           0 :       pri = DEFSPRI;
    1117           0 :       if (*p == '<')
    1118             :         {
    1119           0 :           pri = 0;
    1120           0 :           while (isdigit (*++p))
    1121           0 :             pri = 10 * pri + (*p - '0');
    1122           0 :           if (*p == '>')
    1123           0 :             ++p;
    1124             :         }
    1125             :       else
    1126             :         {
    1127             :           /* kernel printf's come out on console */
    1128           0 :           flags |= IGN_CONS;
    1129             :         }
    1130           0 :       if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
    1131           0 :         pri = DEFSPRI;
    1132           0 :       q = lp;
    1133           0 :       while (*p != '\0' && (c = *p++) != '\n' && q < &line[MAXLINE])
    1134           0 :         *q++ = c;
    1135           0 :       *q = '\0';
    1136           0 :       logmsg (pri, line, LocalHostName, flags);
    1137             :     }
    1138           0 : }
    1139             : 
    1140             : /* Decode a priority into textual information like auth.emerg.  */
    1141             : char *
    1142          24 : textpri (int pri)
    1143             : {
    1144             :   static char res[20];
    1145             :   CODE *c_pri, *c_fac;
    1146             : 
    1147         319 :   for (c_fac = facilitynames; c_fac->c_name
    1148         566 :        && !(c_fac->c_val == LOG_FAC (pri) << 3); c_fac++);
    1149         178 :   for (c_pri = prioritynames; c_pri->c_name
    1150         284 :        && !(c_pri->c_val == LOG_PRI (pri)); c_pri++);
    1151             : 
    1152          24 :   snprintf (res, sizeof (res), "%s.%s", c_fac->c_name, c_pri->c_name);
    1153             : 
    1154          24 :   return res;
    1155             : }
    1156             : 
    1157             : /* Log a message to the appropriate log files, users, etc. based on
    1158             :    the priority.  */
    1159             : void
    1160          24 : logmsg (int pri, const char *msg, const char *from, int flags)
    1161             : {
    1162             :   struct filed *f;
    1163             :   int fac, msglen, prilev;
    1164             : #ifdef HAVE_SIGACTION
    1165             :   sigset_t sigs, osigs;
    1166             : #else
    1167             :   int omask;
    1168             : #endif
    1169             : 
    1170             :   const char *timestamp;
    1171             : 
    1172          24 :   dbg_printf ("(logmsg): %s (%d), flags %x, from %s, msg %s\n",
    1173             :               textpri (pri), pri, flags, from, msg);
    1174             : 
    1175             : #ifdef HAVE_SIGACTION
    1176          24 :   sigemptyset (&sigs);
    1177          24 :   sigaddset (&sigs, SIGHUP);
    1178          24 :   sigaddset (&sigs, SIGALRM);
    1179          24 :   sigprocmask (SIG_BLOCK, &sigs, &osigs);
    1180             : #else
    1181             :   omask = sigblock (sigmask (SIGHUP) | sigmask (SIGALRM));
    1182             : #endif
    1183             : 
    1184             :   /* Check to see if msg looks non-standard.  */
    1185          24 :   msglen = strlen (msg);
    1186          38 :   if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
    1187          28 :       msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
    1188          10 :     flags |= ADDDATE;
    1189             : 
    1190          24 :   time (&now);
    1191          24 :   if (flags & ADDDATE)
    1192          10 :     timestamp = ctime (&now) + 4;
    1193             :   else
    1194             :     {
    1195          14 :       if (set_local_time)
    1196           0 :         timestamp = ctime (&now) + 4;
    1197             :       else
    1198          14 :         timestamp = msg;
    1199          14 :       msg += 16;
    1200          14 :       msglen -= 16;
    1201             :     }
    1202             : 
    1203             :   /* Extract facility and priority level.  */
    1204          24 :   if (flags & MARK)
    1205             : #ifdef INTERNAL_MARK
    1206           0 :     fac = LOG_FAC (INTERNAL_MARK);
    1207             : #else
    1208             :     fac = LOG_NFACILITIES;
    1209             : #endif
    1210             :   else
    1211          24 :     fac = LOG_FAC (pri);
    1212          24 :   prilev = LOG_PRI (pri);
    1213             : 
    1214             :   /* Log the message to the particular outputs. */
    1215          24 :   if (!Initialized)
    1216             :     {
    1217           6 :       f = &consfile;
    1218           6 :       f->f_file = open (ctty, O_WRONLY, 0);
    1219           6 :       f->f_prevhost = strdup (LocalHostName);
    1220           6 :       if (f->f_file >= 0)
    1221             :         {
    1222           6 :           fprintlog (f, from, flags, msg);
    1223           6 :           close (f->f_file);
    1224             :         }
    1225             : #ifdef HAVE_SIGACTION
    1226           6 :       sigprocmask (SIG_SETMASK, &osigs, 0);
    1227             : #else
    1228             :       sigsetmask (omask);
    1229             : #endif
    1230          30 :       return;
    1231             :     }
    1232         129 :   for (f = Files; f; f = f->f_next)
    1233             :     {
    1234             :       /* Skip messages that are incorrect priority. */
    1235         111 :       if (!(f->f_pmask[fac] & LOG_MASK (prilev)))
    1236          75 :         continue;
    1237             : 
    1238          36 :       if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
    1239           0 :         continue;
    1240             : 
    1241             :       /* Don't output marks to recently written files.  */
    1242          36 :       if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
    1243           0 :         continue;
    1244             : 
    1245          36 :       if (f->f_progname)
    1246             :         {
    1247             :           /* The usual, and desirable, formattings are:
    1248             :            *
    1249             :            *   prg: message text
    1250             :            *   prg[PIDNO]: message text
    1251             :            */
    1252             : 
    1253             :           /* Skip on selector mismatch.  */
    1254           0 :           if (strncmp (msg, f->f_progname, f->f_prognlen))
    1255           0 :             continue;
    1256             : 
    1257             :           /* Avoid matching on prefixes.  */
    1258           0 :           if (isalnum (msg[f->f_prognlen])
    1259           0 :               || msg[f->f_prognlen] == '-'
    1260           0 :               || msg[f->f_prognlen] == '_')
    1261           0 :             continue;
    1262             :         }
    1263             : 
    1264             :       /* Suppress duplicate lines to this file.  */
    1265          36 :       if ((flags & MARK) == 0 && msglen == f->f_prevlen && f->f_prevhost
    1266           2 :           && !strcmp (msg, f->f_prevline) && !strcmp (from, f->f_prevhost))
    1267             :         {
    1268           0 :           strncpy (f->f_lasttime, timestamp, sizeof (f->f_lasttime) - 1);
    1269           0 :           f->f_prevcount++;
    1270           0 :           dbg_printf ("msg repeated %d times, %ld sec of %d\n",
    1271           0 :                       f->f_prevcount, now - f->f_time,
    1272           0 :                       repeatinterval[f->f_repeatcount]);
    1273             :           /* If domark would have logged this by now, flush it now (so we
    1274             :              don't hold isolated messages), but back off so we'll flush
    1275             :              less often in the future.  */
    1276           0 :           if (now > REPEATTIME (f))
    1277             :             {
    1278           0 :               fprintlog (f, from, flags, (char *) NULL);
    1279           0 :               BACKOFF (f);
    1280             :             }
    1281             :         }
    1282             :       else
    1283             :         {
    1284             :           /* New line, save it.  */
    1285          36 :           if (f->f_prevcount)
    1286           0 :             fprintlog (f, from, 0, (char *) NULL);
    1287          36 :           f->f_repeatcount = 0;
    1288          36 :           strncpy (f->f_lasttime, timestamp, sizeof (f->f_lasttime) - 1);
    1289          36 :           free (f->f_prevhost);
    1290          36 :           f->f_prevhost = strdup (from);
    1291          36 :           if (msglen < MAXSVLINE)
    1292             :             {
    1293          36 :               f->f_prevlen = msglen;
    1294          36 :               f->f_prevpri = pri;
    1295          36 :               strcpy (f->f_prevline, msg);
    1296          36 :               fprintlog (f, from, flags, (char *) NULL);
    1297             :             }
    1298             :           else
    1299             :             {
    1300           0 :               f->f_prevline[0] = 0;
    1301           0 :               f->f_prevlen = 0;
    1302           0 :               fprintlog (f, from, flags, msg);
    1303             :             }
    1304             :         }
    1305             :     }
    1306             : #ifdef HAVE_SIGACTION
    1307          18 :   sigprocmask (SIG_SETMASK, &osigs, 0);
    1308             : #else
    1309             :   sigsetmask (omask);
    1310             : #endif
    1311             : }
    1312             : 
    1313             : void
    1314          42 : fprintlog (struct filed *f, const char *from, int flags, const char *msg)
    1315             : {
    1316             :   struct iovec iov[IOVCNT];
    1317             :   struct iovec *v;
    1318             :   int l;
    1319             :   char line[MAXLINE + 1], repbuf[80], greetings[200];
    1320             :   time_t fwd_suspend;
    1321             : 
    1322          42 :   v = iov;
    1323             :   /* Be paranoid.  */
    1324          42 :   memset (v, 0, sizeof (struct iovec) * IOVCNT);
    1325          42 :   if (f->f_type == F_WALL)
    1326             :     {
    1327           0 :       v->iov_base = greetings;
    1328           0 :       snprintf (greetings, sizeof (greetings),
    1329             :                 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
    1330             :                 f->f_prevhost, ctime (&now));
    1331           0 :       v->iov_len = strlen (greetings);
    1332           0 :       v++;
    1333           0 :       v->iov_base = (char *) "";
    1334           0 :       v->iov_len = 0;
    1335           0 :       v++;
    1336             :     }
    1337             :   else
    1338             :     {
    1339          42 :       v->iov_base = f->f_lasttime;
    1340          42 :       v->iov_len = sizeof (f->f_lasttime) - 1;
    1341          42 :       v++;
    1342          42 :       v->iov_base = (char *) " ";
    1343          42 :       v->iov_len = 1;
    1344          42 :       v++;
    1345             :     }
    1346          42 :   if (f->f_prevhost)
    1347             :     {
    1348          42 :       v->iov_base = f->f_prevhost;
    1349          42 :       v->iov_len = strlen (v->iov_base);
    1350          42 :       v++;
    1351             :     }
    1352          42 :   v->iov_base = (char *) " ";
    1353          42 :   v->iov_len = 1;
    1354          42 :   v++;
    1355             : 
    1356          42 :   if (msg)
    1357             :     {
    1358           6 :       v->iov_base = (char *) msg;
    1359           6 :       v->iov_len = strlen (msg);
    1360             :     }
    1361          36 :   else if (f->f_prevcount > 1)
    1362             :     {
    1363           0 :       v->iov_base = repbuf;
    1364           0 :       snprintf (repbuf, sizeof (repbuf), "last message repeated %d times",
    1365             :                 f->f_prevcount);
    1366           0 :       v->iov_len = strlen (repbuf);
    1367             :     }
    1368             :   else
    1369             :     {
    1370          36 :       v->iov_base = f->f_prevline;
    1371          36 :       v->iov_len = f->f_prevlen;
    1372             :     }
    1373          42 :   v++;
    1374             : 
    1375          42 :   dbg_printf ("Logging to %s", TypeNames[f->f_type]);
    1376             : 
    1377          42 :   switch (f->f_type)
    1378             :     {
    1379             :     case F_UNUSED:
    1380           7 :       f->f_time = now;
    1381           7 :       dbg_printf ("\n");
    1382           7 :       break;
    1383             : 
    1384             :     case F_FORW_SUSP:
    1385           0 :       fwd_suspend = time ((time_t *) 0) - f->f_time;
    1386           0 :       if (fwd_suspend >= INET_SUSPEND_TIME)
    1387             :         {
    1388           0 :           dbg_printf ("\nForwarding suspension over, retrying FORW ");
    1389           0 :           f->f_type = F_FORW;
    1390           0 :           goto f_forw;
    1391             :         }
    1392             :       else
    1393             :         {
    1394           0 :           dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
    1395           0 :           dbg_printf ("Forwarding suspension not over, time left: %d.\n",
    1396             :                       INET_SUSPEND_TIME - fwd_suspend);
    1397             :         }
    1398           0 :       break;
    1399             : 
    1400             :     case F_FORW_UNKN:
    1401           0 :       dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
    1402           0 :       fwd_suspend = time ((time_t *) 0) - f->f_time;
    1403           0 :       if (fwd_suspend >= INET_SUSPEND_TIME)
    1404             :         {
    1405             :           struct addrinfo hints, *rp;
    1406             :           int err;
    1407             : 
    1408           0 :           memset (&hints, 0, sizeof (hints));
    1409           0 :           hints.ai_family = usefamily;
    1410             : #ifdef AI_ADDRCONFIG
    1411           0 :           if (usefamily == AF_UNSPEC)
    1412           0 :             hints.ai_flags |= AI_ADDRCONFIG;
    1413             : #endif
    1414           0 :           err = getaddrinfo (f->f_un.f_forw.f_hname, LogForwardPort,
    1415             :                              &hints, &rp);
    1416           0 :           if (err)
    1417             :             {
    1418           0 :               dbg_printf ("Failure: %s\n", gai_strerror (err));
    1419           0 :               dbg_printf ("Retries: %d\n", f->f_prevcount);
    1420           0 :               if (--f->f_prevcount < 0)
    1421             :                 {
    1422           0 :                   f->f_type = F_UNUSED;
    1423           0 :                   free (f->f_un.f_forw.f_hname);
    1424           0 :                   f->f_un.f_forw.f_hname = NULL;
    1425             :                 }
    1426             :             }
    1427             :           else
    1428             :             {
    1429           0 :               dbg_printf ("%s found, resuming.\n", f->f_un.f_forw.f_hname);
    1430           0 :               f->f_un.f_forw.f_addrlen = rp->ai_addrlen;
    1431           0 :               memcpy (&f->f_un.f_forw.f_addr, rp->ai_addr, rp->ai_addrlen);
    1432           0 :               freeaddrinfo (rp);
    1433           0 :               f->f_prevcount = 0;
    1434           0 :               f->f_type = F_FORW;
    1435           0 :               goto f_forw;
    1436             :             }
    1437             :         }
    1438             :       else
    1439           0 :         dbg_printf ("Forwarding suspension not over, time left: %d\n",
    1440             :                     INET_SUSPEND_TIME - fwd_suspend);
    1441           0 :       break;
    1442             : 
    1443             :     case F_FORW:
    1444             :     f_forw:
    1445           0 :       dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
    1446           0 :       if (strcasecmp (from, LocalHostName) && NoHops)
    1447           0 :         dbg_printf ("Not forwarding remote message.\n");
    1448           0 :       else if (NoForward)
    1449           0 :         dbg_printf ("Not forwarding because forwarding is disabled.\n");
    1450             :       else
    1451             :         {
    1452             :           int temp_finet, *pfinet;      /* PFINET points to active fd.  */
    1453             : 
    1454           0 :           if (f->f_un.f_forw.f_addr.ss_family == AF_INET)
    1455           0 :             pfinet = &finet[IU_FD_IP4];
    1456             :           else  /* AF_INET6 */
    1457           0 :             pfinet = &finet[IU_FD_IP6];
    1458             : 
    1459           0 :           temp_finet = *pfinet;
    1460             : 
    1461           0 :           if (temp_finet < 0)
    1462             :             {
    1463             :               int err;
    1464             :               struct addrinfo hints, *rp;
    1465             : 
    1466             :               /* Forwarding needs a temporary socket.
    1467             :                * The source port is fixed!  */
    1468           0 :               memset (&hints, 0, sizeof (hints));
    1469           0 :               hints.ai_family = f->f_un.f_forw.f_addr.ss_family;
    1470           0 :               hints.ai_socktype = SOCK_DGRAM;
    1471           0 :               hints.ai_flags = AI_PASSIVE;
    1472             : 
    1473           0 :               err = getaddrinfo (NULL, LogForwardPort, &hints, &rp);
    1474           0 :               if (err)
    1475             :                 {
    1476           0 :                   dbg_printf ("Not forwarding due to lookup failure: %s.\n",
    1477             :                               gai_strerror(err));
    1478           0 :                   break;
    1479             :                 }
    1480           0 :               temp_finet = socket (rp->ai_family, rp->ai_socktype,
    1481           0 :                                    rp->ai_protocol);
    1482           0 :               if (temp_finet < 0)
    1483             :                 {
    1484           0 :                   dbg_printf ("Not forwarding due to socket failure.\n");
    1485           0 :                   freeaddrinfo (rp);
    1486           0 :                   break;
    1487             :                 }
    1488             : 
    1489           0 :               err = bind (temp_finet, rp->ai_addr, rp->ai_addrlen);
    1490           0 :               freeaddrinfo (rp);
    1491           0 :               if (err)
    1492             :                 {
    1493           0 :                   dbg_printf ("Not forwarding due to bind error: %s.\n",
    1494           0 :                               strerror (errno));
    1495           0 :                   break;
    1496             :                 }
    1497             :             } /* Creation of temporary outgoing socket since "finet < 0" */
    1498             : 
    1499           0 :           f->f_time = now;
    1500           0 :           snprintf (line, sizeof (line), "<%d>%.15s %s",
    1501           0 :                     f->f_prevpri, (char *) iov[0].iov_base,
    1502           0 :                     (char *) iov[4].iov_base);
    1503           0 :           l = strlen (line);
    1504           0 :           if (l > MAXLINE)
    1505           0 :             l = MAXLINE;
    1506           0 :           if (sendto (temp_finet, line, l, 0,
    1507           0 :                       (struct sockaddr *) &f->f_un.f_forw.f_addr,
    1508           0 :                       f->f_un.f_forw.f_addrlen) != l)
    1509             :             {
    1510           0 :               int e = errno;
    1511           0 :               dbg_printf ("INET sendto error: %d = %s.\n", e, strerror (e));
    1512           0 :               f->f_type = F_FORW_SUSP;
    1513           0 :               errno = e;
    1514           0 :               logerror ("sendto");
    1515             :             }
    1516             : 
    1517           0 :           if (*pfinet < 0)
    1518           0 :             close (temp_finet); /* Only temporary socket may be closed.  */
    1519             :         }
    1520           0 :       break;
    1521             : 
    1522             :     case F_CONSOLE:
    1523           6 :       f->f_time = now;
    1524           6 :       if (flags & IGN_CONS)
    1525             :         {
    1526           0 :           dbg_printf (" (ignored)\n");
    1527           0 :           break;
    1528             :         }
    1529             : 
    1530             :     case F_TTY:
    1531             :     case F_FILE:
    1532             :     case F_PIPE:
    1533          35 :       f->f_time = now;
    1534          35 :       dbg_printf (" %s\n", f->f_un.f_fname);
    1535          35 :       if (f->f_type == F_TTY || f->f_type == F_CONSOLE)
    1536             :         {
    1537           6 :           v->iov_base = (char *) "\r\n";
    1538           6 :           v->iov_len = 2;
    1539             :         }
    1540             :       else
    1541             :         {
    1542          29 :           v->iov_base = (char *) "\n";
    1543          29 :           v->iov_len = 1;
    1544             :         }
    1545             :     again:
    1546          35 :       if (writev (f->f_file, iov, IOVCNT) < 0)
    1547             :         {
    1548           0 :           int e = errno;
    1549             : 
    1550             :           /* XXX: If a named pipe is full, ignore it.  */
    1551           0 :           if (f->f_type == F_PIPE && e == EAGAIN)
    1552           0 :             break;
    1553             : 
    1554           0 :           close (f->f_file);
    1555             :           /* Check for errors on TTY's due to loss of tty. */
    1556           0 :           if ((e == EIO || e == EBADF)
    1557           0 :               && (f->f_type == F_TTY || f->f_type == F_CONSOLE))
    1558             :             {
    1559           0 :               f->f_file = open (f->f_un.f_fname, O_WRONLY | O_APPEND, 0);
    1560           0 :               if (f->f_file < 0)
    1561             :                 {
    1562           0 :                   f->f_type = F_UNUSED;
    1563           0 :                   logerror (f->f_un.f_fname);
    1564           0 :                   free (f->f_un.f_fname);
    1565           0 :                   f->f_un.f_fname = NULL;
    1566             :                 }
    1567             :               else
    1568           0 :                 goto again;
    1569             :             }
    1570             :           else
    1571             :             {
    1572           0 :               f->f_type = F_UNUSED;
    1573           0 :               errno = e;
    1574           0 :               logerror (f->f_un.f_fname);
    1575           0 :               free (f->f_un.f_fname);
    1576           0 :               f->f_un.f_fname = NULL;
    1577             :             }
    1578             :         }
    1579          35 :       else if ((flags & SYNC_FILE) && !(f->f_flags & OMIT_SYNC))
    1580           0 :         fsync (f->f_file);
    1581          35 :       break;
    1582             : 
    1583             :     case F_USERS:
    1584             :     case F_WALL:
    1585           0 :       f->f_time = now;
    1586           0 :       dbg_printf ("\n");
    1587           0 :       v->iov_base = (char *) "\r\n";
    1588           0 :       v->iov_len = 2;
    1589           0 :       wallmsg (f, iov);
    1590           0 :       break;
    1591             :     }
    1592             : 
    1593          42 :   if (f->f_type != F_FORW_UNKN)
    1594          42 :     f->f_prevcount = 0;
    1595          42 : }
    1596             : 
    1597             : /* Write the specified message to either the entire world,
    1598             :  * or to a list of approved users.  */
    1599             : void
    1600           0 : wallmsg (struct filed *f, struct iovec *iov)
    1601             : {
    1602             :   static int reenter;           /* Avoid calling ourselves.  */
    1603             :   STRUCT_UTMP *utp;
    1604             : #if defined UTMP_NAME_FUNCTION || !defined HAVE_GETUTXENT
    1605             :   STRUCT_UTMP *utmpbuf;
    1606             :   size_t utmp_count;
    1607             : #endif /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
    1608             :   int i;
    1609             :   char *p;
    1610             :   char line[sizeof (utp->ut_line) + 1];
    1611             : 
    1612           0 :   if (reenter++)
    1613           0 :     return;
    1614             : 
    1615             : #if !defined UTMP_NAME_FUNCTION && defined HAVE_GETUTXENT
    1616             :   setutxent ();
    1617             : 
    1618             :   while ((utp = getutxent ()))
    1619             : #else /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
    1620           0 :   if (read_utmp (UTMP_FILE, &utmp_count, &utmpbuf,
    1621             :                  READ_UTMP_USER_PROCESS | READ_UTMP_CHECK_PIDS) < 0)
    1622             :     {
    1623           0 :       logerror ("opening utmp file");
    1624           0 :       return;
    1625             :     }
    1626             : 
    1627           0 :   for (utp = utmpbuf; utp < utmpbuf + utmp_count; utp++)
    1628             : #endif /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
    1629             :     {
    1630           0 :       strncpy (line, utp->ut_line, sizeof (utp->ut_line));
    1631           0 :       line[sizeof (utp->ut_line)] = '\0';
    1632           0 :       if (f->f_type == F_WALL)
    1633             :         {
    1634             :           /* Note we're using our own version of ttymsg
    1635             :              which does a double fork () to not have
    1636             :              zombies.  No need to waitpid().  */
    1637           0 :           p = ttymsg (iov, IOVCNT, line, TTYMSGTIME);
    1638           0 :           if (p != NULL)
    1639             :             {
    1640           0 :               errno = 0;        /* Already in message. */
    1641           0 :               logerror (p);
    1642             :             }
    1643           0 :           continue;
    1644             :         }
    1645             :       /* Should we send the message to this user? */
    1646           0 :       for (i = 0; i < f->f_un.f_user.f_nusers; i++)
    1647           0 :         if (!strncmp (f->f_un.f_user.f_unames[i], UT_USER (utp),
    1648             :                       sizeof (UT_USER (utp))))
    1649             :           {
    1650           0 :             p = ttymsg (iov, IOVCNT, line, TTYMSGTIME);
    1651           0 :             if (p != NULL)
    1652             :               {
    1653           0 :                 errno = 0;      /* Already in message. */
    1654           0 :                 logerror (p);
    1655             :               }
    1656           0 :             break;
    1657             :           }
    1658             :     }
    1659             : #if defined UTMP_NAME_FUNCTION || !defined HAVE_GETUTXENT
    1660           0 :   free (utmpbuf);
    1661             : #else /* !UTMP_NAME_FUNCTION && HAVE_GETUTXENT */
    1662             :   endutxent ();
    1663             : #endif
    1664           0 :   reenter = 0;
    1665             : }
    1666             : 
    1667             : /* Return a printable representation of a host address.  */
    1668             : const char *
    1669           4 : cvthname (struct sockaddr *f, socklen_t len)
    1670             : {
    1671             :   int err;
    1672             :   char *p;
    1673             : 
    1674           4 :   err = getnameinfo (f, len, addrstr, sizeof (addrstr),
    1675             :                      NULL, 0, NI_NUMERICHOST);
    1676           4 :   if (err)
    1677             :     {
    1678           0 :       dbg_printf ("Malformed from address: %s.\n",
    1679             :                   gai_strerror (err));
    1680           0 :       return "???";
    1681             :     }
    1682             : 
    1683           4 :   dbg_printf ("cvthname(%s)\n", addrstr);
    1684             : 
    1685           4 :   err = getnameinfo (f, len, addrname, sizeof (addrname),
    1686             :                      NULL, 0, NI_NAMEREQD);
    1687           4 :   if (err)
    1688             :     {
    1689           0 :       dbg_printf ("Host name for your address (%s) unknown.\n", addrstr);
    1690           0 :       return addrstr;
    1691             :     }
    1692             : 
    1693           4 :   p = strchr (addrname, '.');
    1694           4 :   if (p != NULL)
    1695             :     {
    1696           4 :       if (strcasecmp (p + 1, LocalDomain) == 0)
    1697           0 :         *p = '\0';
    1698             :       else
    1699             :         {
    1700             :           int count;
    1701             : 
    1702           4 :           if (StripDomains)
    1703             :             {
    1704           0 :               count = 0;
    1705           0 :               while (StripDomains[count])
    1706             :                 {
    1707           0 :                   if (strcasecmp (p + 1, StripDomains[count]) == 0)
    1708             :                     {
    1709           0 :                       *p = '\0';
    1710           0 :                       return addrname;
    1711             :                     }
    1712           0 :                   count++;
    1713             :                 }
    1714             :             }
    1715           4 :           if (LocalHosts)
    1716             :             {
    1717           0 :               count = 0;
    1718           0 :               while (LocalHosts[count])
    1719             :                 {
    1720           0 :                   if (strcasecmp (addrname, LocalHosts[count]) == 0)
    1721             :                     {
    1722           0 :                       *p = '\0';
    1723           0 :                       return addrname;
    1724             :                     }
    1725           0 :                   count++;
    1726             :                 }
    1727             :             }
    1728             :         }
    1729             :     }
    1730           4 :   return addrname;
    1731             : }
    1732             : 
    1733             : void
    1734           0 : domark (int signo _GL_UNUSED_PARAMETER)
    1735             : {
    1736             :   struct filed *f;
    1737             : 
    1738           0 :   now = time ((time_t *) NULL);
    1739           0 :   if (MarkInterval > 0)
    1740             :     {
    1741           0 :       MarkSeq += TIMERINTVL;
    1742           0 :       if (MarkSeq >= MarkInterval)
    1743             :         {
    1744           0 :           logmsg (LOG_INFO, "-- MARK --", LocalHostName, ADDDATE | MARK);
    1745           0 :           MarkSeq = 0;
    1746             :         }
    1747             :     }
    1748             : 
    1749           0 :   for (f = Files; f; f = f->f_next)
    1750             :     {
    1751           0 :       if (f->f_prevcount && now >= REPEATTIME (f))
    1752             :         {
    1753           0 :           dbg_printf ("flush %s: repeated %d times, %d sec.\n",
    1754           0 :                       TypeNames[f->f_type], f->f_prevcount,
    1755           0 :                       repeatinterval[f->f_repeatcount]);
    1756           0 :           fprintlog (f, LocalHostName, 0, (char *) NULL);
    1757           0 :           BACKOFF (f);
    1758             :         }
    1759             :     }
    1760             : 
    1761             : #ifndef HAVE_SIGACTION
    1762             :   signal (SIGALRM, domark);
    1763             : #endif
    1764           0 :   alarm (TIMERINTVL);
    1765           0 : }
    1766             : 
    1767             : /* Print syslogd errors some place.  */
    1768             : void
    1769           8 : logerror (const char *type)
    1770             : {
    1771             :   char buf[100];
    1772             : 
    1773           8 :   if (errno)
    1774           1 :     snprintf (buf, sizeof (buf), "syslogd: %s: %s", type, strerror (errno));
    1775             :   else
    1776           7 :     snprintf (buf, sizeof (buf), "syslogd: %s", type);
    1777           8 :   errno = 0;
    1778           8 :   dbg_printf ("%s\n", buf);
    1779           8 :   logmsg (LOG_SYSLOG | LOG_ERR, buf, LocalHostName, ADDDATE);
    1780           8 : }
    1781             : 
    1782             : void
    1783           0 : doexit (int signo _GL_UNUSED_PARAMETER)
    1784             : {
    1785           0 :   _exit (EXIT_SUCCESS);
    1786             : }
    1787             : 
    1788             : void
    1789           1 : die (int signo)
    1790             : {
    1791             :   struct filed *f;
    1792           1 :   int was_initialized = Initialized;
    1793             :   char buf[100];
    1794             :   size_t i;
    1795             : 
    1796           1 :   Initialized = 0;              /* Don't log SIGCHLDs. */
    1797           6 :   for (f = Files; f != NULL; f = f->f_next)
    1798             :     {
    1799             :       /* Flush any pending output.  */
    1800           5 :       if (f->f_prevcount)
    1801           0 :         fprintlog (f, LocalHostName, 0, (char *) NULL);
    1802             :     }
    1803           1 :   Initialized = was_initialized;
    1804           1 :   if (signo)
    1805             :     {
    1806           1 :       dbg_printf ("%s: exiting on signal %d\n",
    1807             :                   program_invocation_name, signo);
    1808           1 :       snprintf (buf, sizeof (buf), "exiting on signal %d", signo);
    1809           1 :       errno = 0;
    1810           1 :       logerror (buf);
    1811             :     }
    1812             : 
    1813           1 :   if (fklog >= 0)
    1814           0 :     close (fklog);
    1815             : 
    1816           4 :   for (i = 0; i < nfunix; i++)
    1817           3 :     if (funix[i].fd >= 0)
    1818             :       {
    1819           2 :         close (funix[i].fd);
    1820           2 :         if (funix[i].name)
    1821           2 :           unlink (funix[i].name);
    1822             :       }
    1823             : 
    1824           1 :   if (finet[IU_FD_IP4] >= 0)
    1825           1 :     close (finet[IU_FD_IP4]);
    1826           1 :   if (finet[IU_FD_IP6] >= 0)
    1827           1 :     close (finet[IU_FD_IP6]);
    1828             : 
    1829           1 :   exit (EXIT_SUCCESS);
    1830             : }
    1831             : 
    1832             : /*
    1833             :  * Return zero on error.
    1834             :  */
    1835             : static int
    1836           4 : load_conffile (const char *filename, struct filed **nextp)
    1837             : {
    1838             :   FILE *cf;
    1839             :   struct filed *f;
    1840             : #ifndef LINE_MAX
    1841             : # define LINE_MAX 2048
    1842             : #endif
    1843           4 :   size_t line_max = LINE_MAX;
    1844             :   char *cbuf;
    1845             :   char *cline;
    1846           4 :   int cont_line = 0;
    1847             : 
    1848             :   /* Beware: Do not assume *nextp to be NULL.  */
    1849             : 
    1850             :   /* Open the configuration file.  */
    1851           4 :   cf = fopen (filename, "r");
    1852           4 :   if (cf == NULL)
    1853             :     {
    1854           0 :       dbg_printf ("cannot open %s\n", filename);
    1855             : 
    1856             :       /* Add emergency logging if everything else was missing.  */
    1857           0 :       if (*nextp == NULL)
    1858             :         {
    1859             :           /* Send LOG_ERR to the system console.  */
    1860           0 :           f = (struct filed *) calloc (1, sizeof (*f));
    1861           0 :           cfline ("*.ERR\t" PATH_CONSOLE, f);         /* Erases *f!  */
    1862             : 
    1863             :           /* Below that, send LOG_EMERG to all users.  */
    1864           0 :           f->f_next = (struct filed *) calloc (1, sizeof (*f));
    1865           0 :           cfline ("*.PANIC\t*", f->f_next);        /* Erases *(f->f_next)!  */
    1866             : 
    1867           0 :           *nextp = f;   /* Return this minimal table to the caller.  */
    1868             :         }
    1869             : 
    1870           0 :       Initialized = 1;
    1871           0 :       return 1;
    1872             :     }
    1873             : 
    1874             :   /* Allocate a buffer for line parsing.  */
    1875           4 :   cbuf = malloc (line_max);
    1876           4 :   if (cbuf == NULL)
    1877             :     {
    1878             :       /* There is no graceful recovery here.  */
    1879           0 :       dbg_printf ("cannot allocate space for configuration\n");
    1880           0 :       fclose (cf);
    1881           0 :       return 0;
    1882             :     }
    1883           4 :   cline = cbuf;
    1884             : 
    1885             :   /* Reset selecting program.  */
    1886           4 :   free (selector);
    1887           4 :   selector = NULL;
    1888             : 
    1889             :   /* Line parsing :
    1890             :      - skip comments,
    1891             :      - strip off trailing spaces,
    1892             :      - skip empty lines,
    1893             :      - glob leading spaces,
    1894             :      - readjust buffer if line is too big,
    1895             :      - deal with continuation lines, last char is '\' .  */
    1896          29 :   while (fgets (cline, line_max - (cline - cbuf), cf) != NULL)
    1897             :     {
    1898             :       char *p;
    1899          21 :       size_t len = strlen (cline);
    1900             : 
    1901             :       /* If this is a continuation line, skip leading whitespace for
    1902             :          compatibility with sysklogd.  Note that this requires
    1903             :          whitespace before the backslash in the previous line if you
    1904             :          want to separate the selector from the action.  */
    1905          21 :       if (cont_line)
    1906             :         {
    1907           1 :           char *start = cline;
    1908           5 :           while (*start == ' ' || *start == '\t')
    1909           3 :             start++;
    1910           1 :           len = len - (start - cline);
    1911           1 :           memmove (cline, start, len + 1);
    1912           1 :           cont_line = 0;
    1913             :         }
    1914             : 
    1915             :       /* No newline, so the line is too big for the buffer.  Readjust.  */
    1916          21 :       if (strchr (cline, '\n') == NULL)
    1917             :         {
    1918           0 :           size_t offset = cline - cbuf;
    1919             :           char *tmp;
    1920           0 :           tmp = realloc (cbuf, line_max * 2);
    1921           0 :           if (tmp == NULL)
    1922             :             {
    1923             :               /* Sigh ...  */
    1924           0 :               dbg_printf ("cannot allocate space configuration\n");
    1925           0 :               fclose (cf);
    1926           0 :               free (cbuf);
    1927           0 :               return 0;
    1928             :             }
    1929             :           else
    1930           0 :             cbuf = tmp;
    1931           0 :           line_max *= 2;
    1932           0 :           cline = cbuf + offset + len - 1;
    1933           0 :           continue;
    1934             :         }
    1935             :       else
    1936          21 :         cline = cbuf;
    1937             : 
    1938             :       /* Glob the leading spaces.  */
    1939          21 :       for (p = cline; isspace (*p); ++p)
    1940             :         ;
    1941             : 
    1942             :       /* Record program selector.
    1943             :        *
    1944             :        * Acceptable formats are typically:
    1945             :        *
    1946             :        *   !name
    1947             :        *   #! name
    1948             :        *   ! *
    1949             :        *
    1950             :        * The latter is clearing the previous setting.
    1951             :        */
    1952          21 :       if (*p == '!' || (*p == '#' && *(p + 1) == '!'))
    1953             :         {
    1954           0 :           if (*++p == '!')
    1955           0 :             ++p;
    1956           0 :           while (isspace (*p))
    1957           0 :             ++p;
    1958           0 :           if (*p == '\0')
    1959           0 :             continue;
    1960             : 
    1961             :           /* Reset previous setting.  */
    1962           0 :           free (selector);
    1963           0 :           selector = NULL;
    1964             : 
    1965           0 :           if (*p != '*')
    1966             :             {
    1967             :               char *sep;
    1968             : 
    1969             :               /* BSD systems allow multiple selectors
    1970             :                * separated by commata.  Strip away any
    1971             :                * additional names since at this time
    1972             :                * we only support a single name.
    1973             :                */
    1974           0 :               sep = strchr (p, ',');
    1975           0 :               if (sep)
    1976           0 :                 *sep = '\0';
    1977             : 
    1978             :               /* Remove trailing whitespace.  */
    1979           0 :               sep = strpbrk (p, " \t\n\r");
    1980           0 :               if (sep)
    1981           0 :                 *sep = '\0';
    1982             : 
    1983           0 :               selector = strdup (p);
    1984             :             }
    1985           0 :           continue;
    1986             :         }
    1987             : 
    1988             :       /* Skip comments and empty line.  */
    1989          21 :       if (*p == '\0' || *p == '#')
    1990           7 :         continue;
    1991             : 
    1992          14 :       memmove (cline, p, strlen (p) + 1);
    1993             : 
    1994             :       /* Cut the trailing spaces.  */
    1995          14 :       for (p = strchr (cline, '\0'); isspace (*--p);)
    1996             :         ;
    1997             : 
    1998             :       /* if '\', indicates continuation on the next line.  */
    1999          14 :       if (*p == '\\')
    2000             :         {
    2001           1 :           *p = '\0';
    2002           1 :           cline = p;
    2003           1 :           cont_line = 1;
    2004           1 :           continue;
    2005             :         }
    2006             : 
    2007          13 :       *++p = '\0';
    2008             : 
    2009             :       /* Send the line for more parsing.
    2010             :        * Then generate the new entry,
    2011             :        * inserting it at the head of
    2012             :        * the already existing table.
    2013             :        */
    2014          13 :       f = (struct filed *) calloc (1, sizeof (*f));
    2015          13 :       cfline (cbuf, f);                 /* Erases *f!  */
    2016          13 :       f->f_next = *nextp;
    2017          13 :       *nextp = f;
    2018             :     }
    2019             : 
    2020             :   /* Close the configuration file.  */
    2021           4 :   fclose (cf);
    2022           4 :   free (cbuf);
    2023             : 
    2024           4 :   return 1;
    2025             : }
    2026             : 
    2027             : /*
    2028             :  * Return zero on error.
    2029             :  */
    2030             : static int
    2031           2 : load_confdir (const char *dirname, struct filed **nextp)
    2032             : {
    2033           2 :   int rc = 0, found = 0;
    2034             :   struct dirent *dent;
    2035             :   DIR *dir;
    2036             : 
    2037           2 :   dir = opendir (dirname);
    2038           2 :   if (dir == NULL)
    2039             :     {
    2040           0 :       dbg_printf ("cannot open %s\n", dirname);
    2041           0 :       return 1;         /* Acceptable deviation.  */
    2042             :     }
    2043             : 
    2044          10 :   while ((dent = readdir (dir)) != NULL)
    2045             :     {
    2046             :       struct stat st;
    2047             :       char *file;
    2048             : 
    2049           6 :       if (asprintf (&file, "%s/%s", dirname, dent->d_name) < 0)
    2050             :         {
    2051           0 :           dbg_printf ("cannot allocate space for configuration filename\n");
    2052           0 :           return 0;
    2053             :         }
    2054             : 
    2055           6 :       if (stat (file, &st) != 0)
    2056             :         {
    2057           0 :           dbg_printf ("cannot stat file configuration file\n");
    2058           0 :           continue;
    2059             :         }
    2060             : 
    2061             : 
    2062           6 :       if (S_ISREG(st.st_mode))
    2063             :         {
    2064           2 :           found++;
    2065           2 :           rc += load_conffile (file, nextp);
    2066             :         }
    2067             : 
    2068           6 :       free (file);
    2069             :     }
    2070             : 
    2071           2 :   closedir (dir);
    2072             : 
    2073             :   /* An empty directory is acceptable.
    2074             :    */
    2075           2 :   return (found ? rc : 1);
    2076             : }
    2077             : 
    2078             : /* INIT -- Initialize syslogd from configuration table.  */
    2079             : void
    2080           2 : init (int signo _GL_UNUSED_PARAMETER)
    2081             : {
    2082             :   int rc, ret;
    2083             :   struct filed *f, *next, **nextp;
    2084             : 
    2085           2 :   dbg_printf ("init\n");
    2086             : 
    2087             :   /* Close all open log files.  */
    2088           2 :   Initialized = 0;
    2089          10 :   for (f = Files; f != NULL; f = next)
    2090             :     {
    2091             :       int j;
    2092             : 
    2093             :       /* Flush any pending output.  */
    2094           8 :       if (f->f_prevcount)
    2095           0 :         fprintlog (f, LocalHostName, 0, (char *) NULL);
    2096             : 
    2097           8 :       switch (f->f_type)
    2098             :         {
    2099             :         case F_FILE:
    2100             :         case F_TTY:
    2101             :         case F_CONSOLE:
    2102             :         case F_PIPE:
    2103           2 :           free (f->f_un.f_fname);
    2104           2 :           close (f->f_file);
    2105           2 :           break;
    2106             :         case F_FORW:
    2107             :         case F_FORW_SUSP:
    2108             :         case F_FORW_UNKN:
    2109           0 :           free (f->f_un.f_forw.f_hname);
    2110           0 :           break;
    2111             :         case F_USERS:
    2112           0 :           for (j = 0; j < f->f_un.f_user.f_nusers; ++j)
    2113           0 :             free (f->f_un.f_user.f_unames[j]);
    2114           0 :           free (f->f_un.f_user.f_unames);
    2115           0 :           break;
    2116             :         }
    2117           8 :       free (f->f_progname);
    2118           8 :       free (f->f_prevhost);
    2119           8 :       next = f->f_next;
    2120           8 :       free (f);
    2121             :     }
    2122             : 
    2123           2 :   Files = NULL;         /* Empty the table.  */
    2124           2 :   nextp = &Files;
    2125           2 :   facilities_seen = 0;
    2126             : 
    2127           2 :   rc = load_conffile (ConfFile, nextp);
    2128             : 
    2129           2 :   ret = load_confdir (ConfDir, nextp);
    2130           2 :   if (!ret)
    2131           0 :     rc = 0;             /* Some allocation errors were found.  */
    2132             : 
    2133           2 :   Initialized = 1;
    2134             : 
    2135           2 :   if (Debug)
    2136             :     {
    2137           0 :       for (f = Files; f; f = f->f_next)
    2138             :         {
    2139             :           int i;
    2140           0 :           for (i = 0; i <= LOG_NFACILITIES; i++)
    2141           0 :             if (f->f_pmask[i] == 0)
    2142           0 :               dbg_printf (" X ");
    2143             :             else
    2144           0 :               dbg_printf ("%2x ", f->f_pmask[i]);
    2145           0 :           dbg_printf ("%s: ", TypeNames[f->f_type]);
    2146           0 :           switch (f->f_type)
    2147             :             {
    2148             :             case F_FILE:
    2149             :             case F_TTY:
    2150             :             case F_CONSOLE:
    2151             :             case F_PIPE:
    2152           0 :               dbg_printf ("%s", f->f_un.f_fname);
    2153           0 :               break;
    2154             : 
    2155             :             case F_FORW:
    2156             :             case F_FORW_SUSP:
    2157             :             case F_FORW_UNKN:
    2158           0 :               dbg_printf ("%s", f->f_un.f_forw.f_hname);
    2159           0 :               break;
    2160             : 
    2161             :             case F_USERS:
    2162           0 :               for (i = 0; i < f->f_un.f_user.f_nusers; i++)
    2163           0 :                 dbg_printf ("%s, ", f->f_un.f_user.f_unames[i]);
    2164           0 :               break;
    2165             :             }
    2166           0 :           dbg_printf ("\n");
    2167             :         }
    2168             :     }
    2169             : 
    2170           2 :   if (AcceptRemote)
    2171           2 :     logmsg (LOG_SYSLOG | LOG_INFO, "syslogd (" PACKAGE_NAME
    2172             :             " " PACKAGE_VERSION "): restart (remote reception)",
    2173             :             LocalHostName, ADDDATE);
    2174             :   else
    2175           0 :     logmsg (LOG_SYSLOG | LOG_INFO, "syslogd (" PACKAGE_NAME
    2176             :             " " PACKAGE_VERSION "): restart", LocalHostName, ADDDATE);
    2177             : 
    2178           2 :   if (!rc)
    2179           0 :     logmsg (LOG_SYSLOG | LOG_ERR, "syslogd: Incomplete configuration.",
    2180             :             LocalHostName, ADDDATE);
    2181             : 
    2182           2 :   dbg_printf ("syslogd: restarted\n");
    2183           2 : }
    2184             : 
    2185             : /* Crack a configuration file line.  */
    2186             : void
    2187          13 : cfline (const char *line, struct filed *f)
    2188             : {
    2189             :   struct addrinfo hints, *rp;
    2190             :   int i, pri, negate_pri, excl_pri, err;
    2191             :   unsigned int pri_set, pri_clear;
    2192             :   char *bp;
    2193             :   const char *p, *q;
    2194             :   char buf[MAXLINE], ebuf[200];
    2195             : 
    2196          26 :   dbg_printf ("cfline(%s)%s%s\n", line,
    2197          13 :               selector ? " tagged " : "",
    2198          13 :               selector ? selector : "");
    2199             : 
    2200          13 :   errno = 0;    /* keep strerror() stuff out of logerror messages */
    2201             : 
    2202             :   /* Clear out file entry.  */
    2203          13 :   memset (f, 0, sizeof (*f));
    2204         338 :   for (i = 0; i <= LOG_NFACILITIES; i++)
    2205             :     {
    2206         325 :       f->f_pmask[i] = 0;
    2207         325 :       f->f_flags = 0;
    2208             :     }
    2209             : 
    2210             :   /* Scan through the list of selectors.  */
    2211          34 :   for (p = line; *p && *p != '\t' && *p != ' ';)
    2212             :     {
    2213             : 
    2214             :       /* Find the end of this facility name list.  */
    2215          61 :       for (q = p; *q && *q != '\t' && *q++ != '.';)
    2216          35 :         continue;
    2217             : 
    2218             :       /* Collect priority name.  */
    2219          65 :       for (bp = buf; *q && !strchr ("\t ,;", *q);)
    2220          39 :         *bp++ = *q++;
    2221          13 :       *bp = '\0';
    2222             : 
    2223             :       /* Skip cruft.  */
    2224          26 :       while (*q && strchr (",;", *q))
    2225           0 :         q++;
    2226             : 
    2227          13 :       bp = buf;
    2228          13 :       negate_pri = excl_pri = 0;
    2229             : 
    2230          30 :       while (*bp == '!' || *bp == '=')
    2231           4 :         switch (*bp++)
    2232             :           {
    2233             :           case '!':
    2234           0 :             negate_pri = 1;
    2235           0 :             break;
    2236             : 
    2237             :           case '=':
    2238           4 :             excl_pri = 1;
    2239           4 :             break;
    2240             :           }
    2241             : 
    2242             :       /* Decode priority name and set up bit masks.  */
    2243          13 :       if (*bp == '*')
    2244             :         {
    2245           3 :           pri_clear = 0;
    2246           3 :           pri_set = LOG_UPTO (LOG_PRIMASK);
    2247             :         }
    2248             :       else
    2249             :         {
    2250          10 :           pri = decode (bp, prioritynames);
    2251          10 :           if (pri < 0 || (pri > LOG_PRIMASK && pri != INTERNAL_NOPRI))
    2252             :             {
    2253           3 :               snprintf (ebuf, sizeof (ebuf),
    2254             :                         "unknown priority name \"%s\"", bp);
    2255           3 :               logerror (ebuf);
    2256           3 :               return;
    2257             :             }
    2258           7 :           if (pri == INTERNAL_NOPRI)
    2259             :             {
    2260           0 :               pri_clear = 255;
    2261           0 :               pri_set = 0;
    2262             :             }
    2263             :           else
    2264             :             {
    2265           7 :               pri_clear = 0;
    2266           7 :               pri_set = excl_pri ? LOG_MASK (pri) : LOG_UPTO (pri);
    2267             :             }
    2268             :         }
    2269          10 :       if (negate_pri)
    2270             :         {
    2271           0 :           unsigned int exchange = pri_set;
    2272           0 :           pri_set = pri_clear;
    2273           0 :           pri_clear = exchange;
    2274             :         }
    2275             : 
    2276             :       /* Scan facilities.  */
    2277          28 :       while (*p && !strchr ("\t .;", *p))
    2278             :         {
    2279          45 :           for (bp = buf; *p && !strchr ("\t ,;.", *p);)
    2280          25 :             *bp++ = *p++;
    2281          10 :           *bp = '\0';
    2282          10 :           if (*buf == '*')
    2283         130 :             for (i = 0; i <= LOG_NFACILITIES; i++)
    2284             :               {
    2285             :                 /* make "**" act as a wildcard only for facilities not
    2286             :                  * specified elsewhere
    2287             :                  */
    2288         125 :                 if (buf[1] == '*' && ((1 << i) & facilities_seen))
    2289           0 :                   continue;
    2290             : 
    2291         125 :                 f->f_pmask[i] &= ~pri_clear;
    2292         125 :                 f->f_pmask[i] |= pri_set;
    2293             :               }
    2294             :           else
    2295             :             {
    2296           5 :               i = decode (buf, facilitynames);
    2297             : 
    2298           5 :               if (i < 0 || i > (LOG_NFACILITIES << 3))
    2299             :                 {
    2300           2 :                   snprintf (ebuf, sizeof (ebuf),
    2301             :                             "unknown facility name \"%s\"", buf);
    2302           2 :                   logerror (ebuf);
    2303           2 :                   return;
    2304             :                 }
    2305             : 
    2306           3 :               f->f_pmask[LOG_FAC (i)] &= ~pri_clear;
    2307           3 :               f->f_pmask[LOG_FAC (i)] |= pri_set;
    2308             : 
    2309           3 :               facilities_seen |= (1 << LOG_FAC (i));
    2310             :             }
    2311          16 :           while (*p == ',' || *p == ' ')
    2312           0 :             p++;
    2313             :         }
    2314           8 :       p = q;
    2315             :     }
    2316             : 
    2317             :   /* Skip to action part.  */
    2318          24 :   while (*p == '\t' || *p == ' ')
    2319           8 :     p++;
    2320             : 
    2321           8 :   if (*p == '-')
    2322             :     {
    2323           0 :       f->f_flags |= OMIT_SYNC;
    2324           0 :       p++;
    2325             :     }
    2326             : 
    2327           8 :   if (!strlen(p))
    2328             :     {
    2329             :       /* Invalidate an entry with empty action field.  */
    2330           1 :       f->f_type = F_UNUSED;
    2331           1 :       logerror ("empty action field");
    2332           1 :       return;
    2333             :     }
    2334             : 
    2335           7 :   switch (*p)
    2336             :     {
    2337             :     case '@':
    2338           0 :       f->f_un.f_forw.f_hname = strdup (++p);
    2339           0 :       memset (&hints, 0, sizeof (hints));
    2340           0 :       hints.ai_family = usefamily;
    2341           0 :       hints.ai_socktype = SOCK_DGRAM;
    2342             : #ifdef AI_ADDRCONFIG
    2343           0 :       if (usefamily == AF_UNSPEC)
    2344           0 :         hints.ai_flags |= AI_ADDRCONFIG;
    2345             : #endif
    2346             : 
    2347           0 :       f->f_un.f_forw.f_addrlen = 0;  /* Invalidate address.  */
    2348           0 :       memset (&f->f_un.f_forw.f_addr, 0, sizeof (f->f_un.f_forw.f_addr));
    2349             : 
    2350           0 :       err = getaddrinfo (p, LogForwardPort, &hints, &rp);
    2351           0 :       if (err)
    2352             :         {
    2353           0 :           switch (err)
    2354             :             {
    2355             :               case EAI_AGAIN:   /* Known kinds of temporary error.  */
    2356             :               case EAI_MEMORY:
    2357           0 :                 f->f_type = F_FORW_UNKN;
    2358           0 :                 f->f_prevcount = INET_RETRY_MAX;
    2359           0 :                 break;
    2360             : 
    2361             :               case EAI_NONAME:  /* The most probable causes for failure.  */
    2362             : #if defined EAI_NODATA && (EAI_NODATA != EAI_NONAME)    /* FreeBSD complains.  */
    2363             :               case EAI_NODATA:
    2364             : #endif
    2365             : #ifdef EAI_ADDRFAMILY
    2366             :               case EAI_ADDRFAMILY:
    2367             : #endif
    2368             :               default:          /* Catch system exceptions.  */
    2369           0 :                 f->f_type = F_UNUSED;
    2370             :             }
    2371             : 
    2372           0 :           f->f_time = time ((time_t *) 0);
    2373             :         }
    2374             :       else
    2375             :         {
    2376           0 :           f->f_type = F_FORW;
    2377           0 :           f->f_un.f_forw.f_addrlen = rp->ai_addrlen;
    2378           0 :           memcpy (&f->f_un.f_forw.f_addr, rp->ai_addr, rp->ai_addrlen);
    2379           0 :           freeaddrinfo (rp);
    2380             :         }
    2381           0 :       break;
    2382             : 
    2383             :     case '|':
    2384           0 :       f->f_un.f_fname = strdup (p);
    2385           0 :       f->f_file = open (++p, O_RDWR | O_NONBLOCK);
    2386           0 :       if (f->f_file < 0)
    2387             :         {
    2388           0 :           f->f_type = F_UNUSED;
    2389           0 :           logerror (p);
    2390           0 :           free (f->f_un.f_fname);
    2391           0 :           f->f_un.f_fname = NULL;
    2392           0 :           break;
    2393             :         }
    2394           0 :       if (strcmp (p, ctty) == 0)
    2395           0 :         f->f_type = F_CONSOLE;
    2396           0 :       else if (isatty (f->f_file))
    2397           0 :         f->f_type = F_TTY;
    2398             :       else
    2399           0 :         f->f_type = F_PIPE;
    2400           0 :       break;
    2401             : 
    2402             :     case '/':
    2403           7 :       f->f_un.f_fname = strdup (p);
    2404           7 :       f->f_file = open (p, O_WRONLY | O_APPEND | O_CREAT, 0644);
    2405           7 :       if (f->f_file < 0)
    2406             :         {
    2407           0 :           f->f_type = F_UNUSED;
    2408           0 :           logerror (p);
    2409           0 :           free (f->f_un.f_fname);
    2410           0 :           f->f_un.f_fname = NULL;
    2411           0 :           break;
    2412             :         }
    2413           7 :       if (strcmp (p, ctty) == 0)
    2414           0 :         f->f_type = F_CONSOLE;
    2415           7 :       else if (isatty (f->f_file))
    2416           0 :         f->f_type = F_TTY;
    2417             :       else
    2418           7 :         f->f_type = F_FILE;
    2419           7 :       break;
    2420             : 
    2421             :     case '*':
    2422           0 :       f->f_type = F_WALL;
    2423           0 :       break;
    2424             : 
    2425             :     default:
    2426           0 :       f->f_un.f_user.f_nusers = 1;
    2427           0 :       for (q = p; *q; q++)
    2428           0 :         if (*q == ',')
    2429           0 :           f->f_un.f_user.f_nusers++;
    2430           0 :       f->f_un.f_user.f_unames =
    2431           0 :         (char **) malloc (f->f_un.f_user.f_nusers * sizeof (char *));
    2432           0 :       for (i = 0; *p; i++)
    2433             :         {
    2434           0 :           for (q = p; *q && *q != ',';)
    2435           0 :             q++;
    2436           0 :           f->f_un.f_user.f_unames[i] = malloc (q - p + 1);
    2437           0 :           if (f->f_un.f_user.f_unames[i])
    2438             :             {
    2439           0 :               strncpy (f->f_un.f_user.f_unames[i], p, q - p);
    2440           0 :               f->f_un.f_user.f_unames[i][q - p] = '\0';
    2441             :             }
    2442           0 :           while (*q == ',' || *q == ' ')
    2443           0 :             q++;
    2444           0 :           p = q;
    2445             :         }
    2446           0 :       f->f_type = F_USERS;
    2447           0 :       break;
    2448             :     }
    2449             : 
    2450             :     /* Set program selector.  */
    2451           7 :     if (selector)
    2452             :       {
    2453           0 :         f->f_progname = strdup (selector);
    2454           0 :         f->f_prognlen = strlen (selector);
    2455             :       }
    2456             :     else
    2457           7 :       f->f_progname = NULL;
    2458             : }
    2459             : 
    2460             : /* Decode a symbolic name to a numeric value.  */
    2461             : int
    2462          15 : decode (const char *name, CODE * codetab)
    2463             : {
    2464             :   CODE *c;
    2465             : 
    2466          15 :   if (isdigit (*name))
    2467           3 :     return atoi (name);
    2468             : 
    2469         132 :   for (c = codetab; c->c_name; c++)
    2470         129 :     if (!strcasecmp (name, c->c_name))
    2471           9 :       return c->c_val;
    2472             : 
    2473           3 :   return -1;
    2474             : }
    2475             : 
    2476             : void
    2477           0 : dbg_toggle (int signo _GL_UNUSED_PARAMETER)
    2478             : {
    2479           0 :   int dbg_save = dbg_output;
    2480             : 
    2481           0 :   dbg_output = 1;
    2482           0 :   dbg_printf ("Switching dbg_output to %s.\n",
    2483             :               dbg_save == 0 ? "true" : "false");
    2484           0 :   dbg_output = (dbg_save == 0) ? 1 : 0;
    2485             : 
    2486             : #ifndef HAVE_SIGACTION
    2487             :   signal (SIGUSR1, dbg_toggle);
    2488             : #endif
    2489           0 : }
    2490             : 
    2491             : /* Ansi2knr will always change ... to va_list va_dcl */
    2492             : static void
    2493         146 : dbg_printf (const char *fmt, ...)
    2494             : {
    2495             :   va_list ap;
    2496             : 
    2497         146 :   if (!(NoDetach && dbg_output))
    2498         292 :     return;
    2499             : 
    2500           0 :   va_start (ap, fmt);
    2501           0 :   vfprintf (stdout, fmt, ap);
    2502           0 :   va_end (ap);
    2503             : 
    2504           0 :   fflush (stdout);
    2505             : }
    2506             : 
    2507             : /* The following function is resposible for handling a SIGHUP signal.
    2508             :    Since we are now doing mallocs/free as part of init we had better
    2509             :    not being doing this during a signal handler.  Instead we simply
    2510             :    set a flag variable which will tell the main loop to go through a
    2511             :    restart.  */
    2512             : void
    2513           1 : trigger_restart (int signo _GL_UNUSED_PARAMETER)
    2514             : {
    2515           1 :   restart = 1;
    2516             : #ifndef HAVE_SIGACTION
    2517             :   signal (SIGHUP, trigger_restart);
    2518             : #endif
    2519           1 : }
    2520             : 
    2521             : /* Override default port with a non-NULL argument.
    2522             :  * Otherwise identify the default syslog/udp with
    2523             :  * proper fallback to avoid resolve issues.  */
    2524             : void
    2525           1 : find_inet_port (const char *port)
    2526             : {
    2527             :   int err;
    2528             :   struct addrinfo hints, *ai;
    2529             : 
    2530             :   /* Fall back to numerical description.  */
    2531             : #ifdef IPPORT_SYSLOG
    2532             :   snprintf (portstr, sizeof (portstr), "%u", IPPORT_SYSLOG);
    2533             :   LogForwardPort = portstr;
    2534             : #else
    2535           1 :   LogForwardPort = "514";
    2536             : #endif
    2537             : 
    2538           1 :   memset (&hints, 0, sizeof (hints));
    2539           1 :   hints.ai_family = AF_UNSPEC;
    2540           1 :   hints.ai_socktype = SOCK_DGRAM;
    2541           1 :   hints.ai_flags = AI_PASSIVE;
    2542             : 
    2543           1 :   err = getaddrinfo (NULL, "syslog", &hints, &ai);
    2544           1 :   if (err == 0)
    2545             :     {
    2546           1 :       LogForwardPort = "syslog";      /* Symbolic name is usable.  */
    2547           1 :       freeaddrinfo (ai);
    2548             :     }
    2549             : 
    2550           1 :   LogPortText = (char *) port;
    2551             : 
    2552           1 :   if (!LogPortText)
    2553             :     {
    2554           0 :       LogPortText = LogForwardPort;
    2555           0 :       return;
    2556             :     }
    2557             : 
    2558             :   /* Is the port specified on command line really usable?  */
    2559           1 :   memset (&hints, 0, sizeof (hints));
    2560           1 :   hints.ai_family = AF_UNSPEC;
    2561           1 :   hints.ai_socktype = SOCK_DGRAM;
    2562           1 :   hints.ai_flags = AI_PASSIVE;
    2563             : 
    2564           1 :   err = getaddrinfo (NULL, LogPortText, &hints, &ai);
    2565           1 :   if (err != 0)
    2566             :     {
    2567             :       /* Not usable, disable listener.
    2568             :        * It is too early to report failure at this time.  */
    2569           0 :       LogPortText = NULL;
    2570             :     }
    2571             :   else
    2572           1 :     freeaddrinfo (ai);
    2573             : 
    2574           1 :   return;
    2575             : }

Generated by: LCOV version 1.11