syslogd.c

Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 1983, 1988
00003 **  The Regents of the University of California.  All rights reserved.
00004 **
00005 **  Redistribution and use in source and binary forms, with or without
00006 **  modification, are permitted provided that the following conditions
00007 **  are met:
00008 **  1. Redistributions of source code must retain the above copyright
00009 **     notice, this list of conditions and the following disclaimer.
00010 **  2. Redistributions in binary form must reproduce the above copyright
00011 **     notice, this list of conditions and the following disclaimer in the
00012 **     documentation and/or other materials provided with the distribution.
00013 **  3. All advertising materials mentioning features or use of this software
00014 **     must display the following acknowledgement:
00015 **       This product includes software developed by the University of
00016 **       California, Berkeley and its contributors.
00017 **  4. Neither the name of the University nor the names of its contributors
00018 **     may be used to endorse or promote products derived from this software
00019 **     without specific prior written permission.
00020 **
00021 **  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00022 **  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 **  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 **  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025 **  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026 **  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027 **  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028 **  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 **  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030 **  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031 **  SUCH DAMAGE.
00032 **
00033 **  #ifndef lint
00034 **  char copyright2[] =
00035 **  "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
00036 **   All rights reserved.\n";
00037 **  #endif
00038 **
00039 **  #ifndef lint
00040 **  static char sccsid[] = "@(#)syslogd.c       5.27 (Berkeley) 10/10/88";
00041 **  #endif
00042 **
00043 **  -----------------------------------------------------------------------
00044 **
00045 **  SYSLOGD -- log system messages
00046 **      This program implements a system log.
00047 **      It takes a series of lines and outputs them according to the setup
00048 **      defined in the configuration file.
00049 **      Each line may have a priority, signified as "<n>" as
00050 **      the first characters of the line.  If this is
00051 **      not present, a default priority is used.
00052 **
00053 **      To kill syslogd, send a signal 15 (terminate).
00054 **      A signal 1 (hup) will cause it to reread its configuration file.
00055 **
00056 **  Defined Constants:
00057 **      MAXLINE   -- the maximimum line length that can be handled.
00058 **      MAXSVLINE -- the length of saved messages (for filtering)
00059 **      DEFUPRI   -- the default priority for user messages
00060 **      DEFSPRI   -- the default priority for kernel messages
00061 **
00062 **  Author: Eric Allman
00063 **  extensive changes by Ralph Campbell
00064 **  more extensive changes by Eric Allman (again)
00065 **  changes by Steve Lord
00066 **
00067 **  Extensive rewriting by G. Falzoni <gfalzoni@inwind.it> for porting to Minix
00068 ** 
00069 **  $Log: syslogd.c,v $
00070 **  Revision 1.3  2006/04/04 14:22:40  beng
00071 **  Fix
00072 **
00073 **  Revision 1.2  2006/04/04 14:18:16  beng
00074 **  Make syslogd work, even if it can only open klog and not udp or vice versa
00075 **  (but not neither)
00076 **
00077 **  Revision 1.1  2006/04/03 13:07:42  beng
00078 **  Kick out usyslogd in favour of syslogd Giovanni's syslogd port
00079 **
00080 **  Revision 1.3  2005/09/16 10:10:12  lsodgf0
00081 **  Rework for Minix 3.  Adds kernel logs from /dev/klogd
00082 **
00083 **  $Id: syslogd.c,v 1.3 2006/04/04 14:22:40 beng Exp $
00084 */
00085 
00086 #include <sys/types.h>
00087 #include <stdio.h>
00088 #include <ctype.h>
00089 #include <string.h>
00090 #include <unistd.h>
00091 #include <stdlib.h>
00092 #include <signal.h>
00093 #include <errno.h>
00094 #include <fcntl.h>
00095 #include <limits.h>
00096 #include <time.h>
00097 #include <sys/ioctl.h>
00098 #include <sys/select.h>
00099 #include <sys/wait.h>
00100 #include <net/netlib.h>
00101 #include <net/hton.h>
00102 #include <net/gen/in.h>
00103 #include <net/gen/udp.h>
00104 #include <net/gen/udp_io.h>
00105 #include <net/gen/netdb.h>
00106 
00107 #define SYSLOG_NAMES
00108 #include <syslog.h>
00109 #define KLOGD 1
00110 
00111 #define MAXLINE         512     /* maximum line length */
00112 #define MAXSVLINE       256     /* maximum saved line length */
00113 
00114 #define DEFUPRI         (LOG_USER|LOG_NOTICE)
00115 #define DEFSPRI         (LOG_KERN|LOG_CRIT)
00116 
00117 /* Flags to logmsg() */
00118 #define IGN_CONS        0x001   /* don't print on console */
00119 #define SYNC_FILE       0x002   /* do fsync on file after printing */
00120 #define ADDDATE         0x004   /* add a date to the message */
00121 #define MARK            0x008   /* this message is a mark */
00122 
00123 #define CTTY            "/dev/log"      /* Minix log device (console) */
00124 
00125 #define dprintf if(DbgOpt!=0)printf
00126 #if debug == 0
00127 #define DEBUG(statement)
00128 #else
00129 #define DEBUG(statement) statement
00130 #endif
00131 #if !defined PIDFILE
00132 #define PIDFILE "/var/run/syslogd.pid"
00133 #endif
00134 
00135 #define UNAMESZ         8       /* length of a login name */
00136 #define MAXUNAMES       20      /* maximum number of user names */
00137 #define MAXFNAME        200     /* max file pathname length */
00138 #define MAXHOSTNAMELEN  64      /* max length of FQDN host name */
00139 
00140 /* Intervals at which we flush out "message repeated" messages,
00141  * in seconds after previous message is logged.  After each flush,
00142  * we move to the next interval until we reach the largest.  */
00143 #define TIMERINTVL      30      /* interval for checking flush, mark */
00144 #define INTERVAL1       30
00145 #define INTERVAL2       60
00146 #define MAXREPEAT ((sizeof(repeatinterval)/sizeof(repeatinterval[0]))-1)
00147 #define REPEATTIME(f) ((f)->f_time+repeatinterval[(f)->f_repeatcount])
00148 #define BACKOFF(f) {if(++(f)->f_repeatcount>MAXREPEAT)(f)->f_repeatcount=MAXREPEAT;}
00149 
00150 /* Values for f_type */
00151 #define F_UNUSED        0       /* unused entry */
00152 #define F_FILE          1       /* regular file */
00153 #define F_TTY           2       /* terminal */
00154 #define F_CONSOLE       3       /* console terminal */
00155 #define F_FORW          4       /* remote machine */
00156 #define F_USERS         5       /* list of users */
00157 #define F_WALL          6       /* everyone logged on */
00158 
00159 #define max(a,b) ((a)>=(b)?(a):(b))
00160 
00161 /* This structure represents the files that will have log copies printed */
00162 struct filed {
00163   struct filed *f_next;         /* next in linked list */
00164   short f_type;                 /* entry type, see below */
00165   short f_file;                 /* file descriptor */
00166   time_t f_time;                /* time this was last written */
00167   char f_pmask[LOG_NFACILITIES + 1];    /* priority mask */
00168   union {
00169         char f_uname[MAXUNAMES][UNAMESZ + 1];
00170         char f_fname[MAXFNAME];
00171   } f_un;
00172   char f_prevline[MAXSVLINE];   /* last message logged */
00173   char f_lasttime[16];          /* time of last occurrence */
00174   char f_prevhost[MAXHOSTNAMELEN + 1];  /* host from which recd. */
00175   int f_prevpri;                /* pri of f_prevline */
00176   int f_prevlen;                /* length of f_prevline */
00177   int f_prevcount;              /* repetition cnt of prevline */
00178   int f_repeatcount;            /* number of "repeated" msgs */
00179   int f_flags;                  /* store some additional flags */
00180 };
00181 
00182 static const char *const TypeNames[] =
00183 {
00184  "UNUSED", "FILE", "TTY", "CONSOLE", "FORW", "USERS", "WALL", NULL,
00185 };
00186 
00187 static struct filed *Files = NULL;
00188 static struct filed consfile;
00189 static int DbgOpt = 0;          /* debug flag */
00190 static char LocalHostName[MAXHOSTNAMELEN + 1];  /* our hostname */
00191 static int Initialized = 0;     /* set when we have initialized ourselves */
00192 static int MarkInterval = 20 * 60;      /* interval between marks in seconds */
00193 static int MarkSeq = 0;         /* mark sequence number */
00194 static time_t now;
00195 
00196 static const char *ConfFile = "/etc/syslog.conf";
00197 static const char *PidFile = PIDFILE;   /* "/var/run/syslogd.pid" */
00198 static const char ctty[] = CTTY;
00199 
00200 static const char ProgName[] = "syslogd:";
00201 static const char version[] = "1.3 (Minix)";
00202 static const char usage[] =
00203  /* */ "usage:\tsyslogd [-d] [-m markinterval] [-f conf-file]\n"
00204        "\t\t[-p listeningport] [-v] [-?]\n" ;
00205 static const int repeatinterval[] =
00206  /* */ {INTERVAL1, INTERVAL2,}; /* # of secs before flush */
00207 
00208 /*
00209 **  Name:       void wallmsg(struct filed *fLog, char *message);
00210 **  Function:   Write the specified message to either the entire
00211 **              world, or a list of approved users.
00212 */
00213 void wallmsg(struct filed * fLog, char *message)
00214 {
00215 
00216   return;
00217 }
00218 
00219 /*
00220 **  Name:       void fprintlog(struct filed *fLog, int flags, char *message);
00221 **  Function:
00222 */
00223 void fprintlog(struct filed * fLog, int flags, char *message)
00224 {
00225   int len;
00226   char line[MAXLINE + 1];
00227   char repbuf[80];
00228 
00229   if (message == NULL) {
00230         if (fLog->f_prevcount > 1) {
00231                 sprintf(repbuf, "last message repeated %d times", fLog->f_prevcount);
00232                 message = repbuf;
00233         } else
00234                 message = fLog->f_prevline;
00235   }
00236   sprintf(line, "%s %s %s", fLog->f_lasttime, fLog->f_prevhost, message);
00237   DEBUG(dprintf("Logging to %s", TypeNames[fLog->f_type]);)
00238   fLog->f_time = now;
00239   switch (fLog->f_type) {
00240       case F_UNUSED:            /* */
00241         DEBUG(dprintf("\n");)
00242         break;
00243       case F_CONSOLE:
00244         if (flags & IGN_CONS) {
00245       case F_FORW:              /* */
00246                 DEBUG(dprintf(" (ignored)\n");)
00247                 break;
00248         }                       /* else Fall Through */
00249       case F_TTY:
00250       case F_FILE:
00251         DEBUG(dprintf(" %s\n", fLog->f_un.f_fname);)
00252         strcat(line, fLog->f_type != F_FILE ? "\r\n" : "\n");
00253         len = strlen(line);
00254         if (write(fLog->f_file, line, len) != len) {
00255                  /* Handle errors */ ;
00256         } else if (flags & SYNC_FILE)
00257                 sync();
00258         break;
00259       case F_USERS:
00260       case F_WALL:
00261         DEBUG(dprintf("\n");)
00262         strcat(line, "\r\n");
00263         wallmsg(fLog, line);
00264         break;
00265   }
00266   fLog->f_prevcount = 0;
00267   return;
00268 }
00269 
00270 /*
00271 **  Name:       void logmsg(int pri, char *msg, char *from, int flags);
00272 **  Function:   Log a message to the appropriate log files, users, etc.
00273 **              based on the priority.
00274 */
00275 void logmsg(int pri, char *msg, char *from, int flags)
00276 {
00277   struct filed *f;
00278   int fac, prilev;
00279   int omask, msglen;
00280   char *timestamp;
00281 
00282   DEBUG(dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);)
00283 /*
00284   omask = sigblock(__sigmask(SIGHUP) | __sigmask(SIGALRM));
00285 */
00286   /* Check to see if msg looks non-standard. */
00287   msglen = strlen(msg);
00288   if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
00289       msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
00290         flags |= ADDDATE;
00291 
00292   time(&now);
00293   if (flags & ADDDATE)
00294         timestamp = ctime(&now) + 4;
00295   else {
00296         timestamp = msg;
00297         msg += 16;
00298         msglen -= 16;
00299   }
00300 
00301   /* Extract facility and priority level */
00302   fac = (flags & MARK) ? LOG_NFACILITIES : LOG_FAC(pri);
00303   prilev = LOG_PRI(pri);
00304 
00305   /* Log the message to the particular outputs */
00306   if (!Initialized) {
00307         /* Not yet initialized. Every message goes to console */
00308         f = &consfile;
00309         f->f_file = open(ctty, O_WRONLY | O_NOCTTY);
00310         if (f->f_file >= 0) {
00311                 if (!DbgOpt) setsid();
00312                 fprintlog(f, flags, msg);
00313                 close(f->f_file);
00314         }
00315   } else {
00316         for (f = Files; f; f = f->f_next) {
00317 
00318                 /* Skip messages that are incorrect priority */
00319                 if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == INTERNAL_NOPRI)
00320                         continue;
00321 
00322                 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) continue;
00323 
00324                 /* Don't output marks to recently written files */
00325                 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
00326                         continue;
00327 
00328                 /* Suppress duplicate lines to this file */
00329                 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
00330                     !strcmp(msg, f->f_prevline) &&
00331                     !strcmp(from, f->f_prevhost)) {
00332                         strncpy(f->f_lasttime, timestamp, 15);
00333                         f->f_prevcount += 1;
00334                         DEBUG(dprintf("msg repeated %d times, %ld sec of %d\n",
00335                                 f->f_prevcount, now - f->f_time,
00336                                 repeatinterval[f->f_repeatcount]);)
00337                         /* If domark would have logged this by now,
00338                          * flush it now (so we don't hold isolated
00339                          * messages), but back off so we'll flush
00340                          * less often in the future. */
00341                         if (now > REPEATTIME(f)) {
00342                                 fprintlog(f, flags, (char *) NULL);
00343                                 BACKOFF(f);
00344                         }
00345                 } else {
00346                         /* New line, save it */
00347                         if (f->f_prevcount) fprintlog(f, 0, (char *) NULL);
00348                         f->f_repeatcount = 0;
00349                         strncpy(f->f_lasttime, timestamp, 15);
00350                         strncpy(f->f_prevhost, from, sizeof(f->f_prevhost));
00351                         if (msglen < MAXSVLINE) {
00352                                 f->f_prevlen = msglen;
00353                                 f->f_prevpri = pri;
00354                                 strcpy(f->f_prevline, msg);
00355                                 fprintlog(f, flags, (char *) NULL);
00356                         } else {
00357                                 f->f_prevline[0] = 0;
00358                                 f->f_prevlen = 0;
00359                                 fprintlog(f, flags, msg);
00360                         }
00361                 }
00362         }
00363   }
00364 
00365 /*
00366   sigsetmask(omask);
00367 */
00368   return;
00369 }
00370 
00371 /*
00372 **  Name:       void logerror(char *type);
00373 **  Function:   Prints syslogd errors in some place.
00374 */
00375 void logerror(char *type)
00376 {
00377   char buf[100];
00378 
00379   if (errno == 0) sprintf(buf, "%s %s", ProgName, type);
00380 
00381   else if (errno >= _NERROR)
00382         sprintf(buf, "%s %s - error %d", ProgName, type, errno);
00383 
00384   else
00385         sprintf(buf, "%s %s - %s", ProgName, type, strerror(errno));
00386 
00387   errno = 0;
00388   dprintf("%s\n", buf);
00389   logmsg(LOG_SYSLOG | LOG_ERR, buf, LocalHostName, ADDDATE);
00390   return;
00391 }
00392 
00393 /*
00394 **  Name:       void die(int sig);
00395 **  Function:   Signal handler for kill signals.
00396 */
00397 void die(int sig)
00398 {
00399   struct filed *f;
00400   char buf[100];
00401 
00402   for (f = Files; f != NULL; f = f->f_next) {
00403         /* Flush any pending output */
00404         if (f->f_prevcount) fprintlog(f, 0, NULL);
00405   }
00406   if (sig >= 0) {
00407         DEBUG(dprintf("%s exiting on signal %d\n", ProgName, sig);)
00408         sprintf(buf, "exiting on signal %d", sig);
00409         errno = 0;
00410         logerror(buf);
00411   }
00412   unlink(PidFile);
00413   exit(sig == (-1) ? EXIT_FAILURE : EXIT_SUCCESS);
00414 }
00415 
00416 /*
00417 **  Name:       void domark(int sig);
00418 **  Function:   Signal handler for alarm.
00419 **              Used for messages filtering and mark facility.
00420 */
00421 void domark(int sig)
00422 {
00423   struct filed *f;
00424 
00425   now = time(NULL);
00426   MarkSeq += TIMERINTVL;
00427   if (MarkSeq >= MarkInterval) {
00428         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE | MARK);
00429         MarkSeq = 0;
00430   }
00431   for (f = Files; f; f = f->f_next) {
00432         if (f->f_prevcount && now >= REPEATTIME(f)) {
00433                 DEBUG(dprintf("flush %s: repeated %d times, %d sec.\n",
00434                         TypeNames[f->f_type], f->f_prevcount,
00435                         repeatinterval[f->f_repeatcount]);)
00436                 fprintlog(f, 0, NULL);
00437                 BACKOFF(f);
00438         }
00439   }
00440   signal(SIGALRM, domark);
00441   alarm(TIMERINTVL);
00442   return;
00443 }
00444 
00445 /*
00446 **  Name:       int decode(char *name, struct _code *codetab);
00447 **  Function:   Decode a symbolic name to a numeric value
00448 */
00449 int decode(char *name, const struct _code *codetab)
00450 {
00451   const struct _code *c;
00452   char *p;
00453   char buf[40];
00454 
00455   DEBUG(dprintf("symbolic name: %s", name);)
00456   if (isdigit(*name)) return (atoi(name));
00457 
00458   strcpy(buf, name);
00459   for (p = buf; *p; p += 1) {
00460         if (isupper(*p)) *p = tolower(*p);
00461   }
00462   for (c = codetab; c->c_name; c += 1) {
00463         if (!strcmp(buf, c->c_name)) {
00464                 DEBUG(dprintf(" ==> %d\n", c->c_val);)
00465                 return (c->c_val);
00466         }
00467   }
00468   return (-1);
00469 }
00470 
00471 /*
00472 **  Name:       void cfline(char *line, struct filed *f);
00473 **  Function:   Parse a configuration file line
00474 */
00475 void cfline(char *line, struct filed * fLog)
00476 {
00477   char *p, *q, *bp;
00478   int ix, pri;
00479   char buf[MAXLINE];
00480   char xbuf[200];
00481 
00482   DEBUG(dprintf("cfline(%s)\n", line);)
00483 
00484   /* Keep sys_errlist stuff out of logerror messages */
00485   errno = 0;
00486 
00487   /* Clear out file entry */
00488   memset(fLog, 0, sizeof(*fLog));
00489   for (ix = 0; ix <= LOG_NFACILITIES; ix += 1)  /* */
00490         fLog->f_pmask[ix] = INTERNAL_NOPRI;
00491 
00492   /* Scan through the list of selectors */
00493   for (p = line; *p && *p != '\t';) {
00494 
00495         /* Find the end of this facility name list */
00496         for (q = p; *q && *q != '\t' && *q++ != '.';) continue;
00497 
00498         /* Collect priority name */
00499         for (bp = buf; *q && !strchr("\t,;", *q);) *bp++ = *q++;
00500         *bp = '\0';
00501 
00502         /* Skip cruft */
00503         while (strchr(", ;", *q)) q++;
00504 
00505         /* Decode priority name */
00506         pri = decode(buf, PriNames);
00507         if (pri < 0) {
00508                 sprintf(xbuf, "unknown priority name \"%s\"", buf);
00509                 logerror(xbuf);
00510                 return;
00511         }
00512 
00513         /* Scan facilities */
00514         while (*p && !strchr("\t.;", *p)) {
00515                 for (bp = buf; *p && !strchr("\t,;.", *p);) *bp++ = *p++;
00516                 *bp = '\0';
00517                 if (*buf == '*') {
00518                         for (ix = 0; ix <= LOG_NFACILITIES; ix += 1)
00519                                 if ((fLog->f_pmask[ix] < pri) ||
00520                                     (fLog->f_pmask[ix] == INTERNAL_NOPRI)) {
00521                                         fLog->f_pmask[ix] = pri;
00522                                 }
00523                 } else {
00524                         ix = decode(buf, FacNames);
00525                         if (ix < 0) {
00526                                 sprintf(xbuf, "unknown facility name \"%s\"", buf);
00527                                 logerror(xbuf);
00528                                 return;
00529                         }
00530                         if ((fLog->f_pmask[ix >> 3] < pri) ||
00531                         (fLog->f_pmask[ix >> 3] == INTERNAL_NOPRI)) {
00532                                 fLog->f_pmask[ix >> 3] = pri;
00533                         }
00534                 }
00535                 while (*p == ',' || *p == ' ') p++;
00536         }
00537         p = q;
00538   }
00539 
00540   /* Skip to action part */
00541   while (*p == '\t' || *p == ' ') p++;
00542 
00543   DEBUG(dprintf("leading char in action: %c\n", *p);)
00544   switch (*p) {
00545       case '@':                 /* Logging to a remote host */
00546         break;                  /* NOT IMPLEMENTED */
00547 
00548       case '/':                 /* Logging to a local file/device */
00549         strcpy(fLog->f_un.f_fname, p);
00550         DEBUG(dprintf("filename: %s\n", p);     /* ASP */)
00551         if ((fLog->f_file = open(p, O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0644)) < 0) {
00552                 fLog->f_file = F_UNUSED;
00553                 sprintf(xbuf, "unknown file/device (%s)", p);
00554                 logerror(xbuf);
00555                 break;
00556         }
00557         if (isatty(fLog->f_file)) {
00558                 if (!DbgOpt) setsid();
00559                 fLog->f_type = F_TTY;
00560         } else
00561                 fLog->f_type = F_FILE;
00562         if (strcmp(p, ctty) == 0) fLog->f_type = F_CONSOLE;
00563         break;
00564 
00565       case '*':                 /* Logging to all users */
00566         DEBUG(dprintf("write-all\n");)
00567         fLog->f_type = F_WALL;
00568         break;
00569 
00570       default:                  /* Logging to selected users */
00571         DEBUG(dprintf("users: %s\n", p);        /* ASP */)
00572         for (ix = 0; ix < MAXUNAMES && *p; ix += 1) {
00573                 for (q = p; *q && *q != ',';) q += 1;
00574                 strncpy(fLog->f_un.f_uname[ix], p, UNAMESZ);
00575                 if ((q - p) > UNAMESZ)
00576                         fLog->f_un.f_uname[ix][UNAMESZ] = '\0';
00577                 else
00578                         fLog->f_un.f_uname[ix][q - p] = '\0';
00579                 while (*q == ',' || *q == ' ') q++;
00580                 p = q;
00581         }
00582         fLog->f_type = F_USERS;
00583         break;
00584   }
00585 }
00586 
00587 /*
00588 **  Name:       void printline(char *hname, char *msg);
00589 **  Function:   Takes a raw input line, decodes the message and
00590 **              prints the message on the appropriate log files.
00591 */
00592 void printline(char *hname, char *msg)
00593 {
00594   char line[MAXLINE + 1];
00595   char *p = msg, *q = line;
00596   int ch, pri = DEFUPRI;
00597 
00598   /* Test for special codes */
00599   if (*p == '<') {
00600         pri = 0;
00601         while (isdigit(*++p)) {
00602                 if ((*p - '0') < 8) {
00603                         /* Only 3 bits allocated for pri -- ASP */
00604                         pri = 10 * pri + (*p - '0');
00605                 } else
00606                         pri = 10 * pri + 7;
00607         }
00608         if (*p == '>') ++p;
00609   }
00610   if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) pri = DEFUPRI;
00611 
00612   /* Does not allow users to log kernel messages */
00613   if (LOG_FAC(pri) == LOG_KERN) pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
00614 
00615   /* Copies message to local buffer, translating control characters */
00616   while ((ch = *p++ & 0177) != '\0' && q < &line[sizeof(line) - 1]) {
00617         if (ch == '\n')         /* Removes newlines */
00618                 *q++ = ' ';
00619         else if (iscntrl(ch)) { /* Translates control characters */
00620                 *q++ = '^';
00621                 *q++ = ch ^ 0100;
00622         } else
00623                 *q++ = ch;
00624   }
00625   *q = '\0';
00626 
00627   logmsg(pri, line, hname, 0);
00628   return;
00629 }
00630 
00631 /*
00632 **  Name:       void printkline(char *hname, char *msg);
00633 **  Function:   Takes a raw input line from kernel and 
00634 **              prints the message on the appropriate log files.
00635 */
00636 void printkline(char *hname, char *msg)
00637 {
00638   char line[MAXLINE + 1];
00639   char *p = msg, *q = line;
00640   int ch, pri = DEFUPRI;
00641 
00642   /* Copies message to local buffer, adding source program tag */
00643   sprintf(line, "kernel: %s", msg);
00644 
00645   logmsg(LOG_KERN | LOG_INFO, line, hname, ADDDATE);
00646   return;
00647 }
00648 
00649 /*
00650 **  Name:       void init(int sig);
00651 **  Function:   Initialize syslogd from configuration file.
00652 **              Used at startup or after a SIGHUP signal.
00653 */
00654 void init(int sig)
00655 {
00656   int i;
00657   FILE *cf;
00658   struct filed *fLog, *next, **nextp;
00659   char *p;
00660   char cline[BUFSIZ];
00661 
00662   DEBUG(dprintf("init\n");)
00663 
00664   /* Close all open log files. */
00665   Initialized = 0;
00666   for (fLog = Files; fLog != NULL; fLog = next) {
00667 
00668         /* Flush any pending output */
00669         if (fLog->f_prevcount) fprintlog(fLog, 0, NULL);
00670 
00671         switch (fLog->f_type) {
00672             case F_FILE:
00673             case F_TTY:
00674             case F_CONSOLE:     close(fLog->f_file);    break;
00675         }
00676         next = fLog->f_next;
00677         free((char *) fLog);
00678   }
00679   Files = NULL;
00680   nextp = &Files;
00681 
00682   /* Open the configuration file */
00683   if ((cf = fopen(ConfFile, "r")) != NULL) {
00684         /* Foreach line in the configuration table, open that file. */
00685         fLog = NULL;
00686         while (fgets(cline, sizeof(cline), cf) != NULL) {
00687                 /* Check for end-of-section, comments, strip off
00688                  * trailing spaces and newline character. */
00689                 for (p = cline; isspace(*p); p += 1);
00690                 if (*p == '\0' || *p == '#') continue;
00691                 for (p = strchr(cline, '\0'); isspace(*--p););
00692                 *++p = '\0';
00693                 fLog = (struct filed *) calloc(1, sizeof(*fLog));
00694                 *nextp = fLog;
00695                 nextp = &fLog->f_next;
00696                 cfline(cline, fLog);
00697         }
00698 
00699         /* Close the configuration file */
00700         fclose(cf);
00701         Initialized = 1;
00702 DEBUG (
00703         if (DbgOpt) {
00704                 for (fLog = Files; fLog; fLog = fLog->f_next) {
00705                         for (i = 0; i <= LOG_NFACILITIES; i += 1)
00706                                 if (fLog->f_pmask[i] == INTERNAL_NOPRI)
00707                                         printf("X ");
00708                                 else
00709                                         printf("%d ", fLog->f_pmask[i]);
00710                         printf("%s: ", TypeNames[fLog->f_type]);
00711                         switch (fLog->f_type) {
00712                             case F_FILE:
00713                             case F_TTY:
00714                             case F_CONSOLE:
00715                                 printf("%s", fLog->f_un.f_fname);
00716                                 break;
00717                             case F_FORW:
00718                                 break;
00719                             case F_USERS:
00720                                 for (i = 0; i < MAXUNAMES && *fLog->f_un.f_uname[i]; i += 1)
00721                                         printf("%s, ", fLog->f_un.f_uname[i]);
00722                                 break;
00723                         }
00724                         printf("\n");
00725                 }
00726         }
00727   )
00728         logmsg(LOG_SYSLOG | LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
00729         signal(SIGHUP, init);
00730         DEBUG(dprintf("%s restarted\n", ProgName);)
00731   } else {
00732         DEBUG(dprintf("cannot open %s\n", ConfFile);)
00733         *nextp = (struct filed *) calloc(1, sizeof(*fLog));
00734         cfline("*.ERR\t" CTTY, *nextp);
00735         (*nextp)->f_next = (struct filed *) calloc(1, sizeof(*fLog));
00736         cfline("*.PANIC\t*", (*nextp)->f_next);
00737         Initialized = 1;
00738   }
00739   return;
00740 }
00741 
00742 /*
00743 **  Name:       void daemonize(char *line);
00744 **  Function:   Clone itself and becomes a daemon releasing unnecessay resources.
00745 */
00746 void daemonize(char *line)
00747 {
00748   int lfd, len, pid;
00749 
00750   if ((lfd = open(PidFile, O_CREAT | O_RDWR, 0600)) > 0) {
00751         len = read(lfd, line, 10);
00752         line[len] = '\0';
00753         close(lfd);
00754         if ((kill(len = atoi(line), 0) < 0 && errno == ESRCH) || len == 0) {
00755                 if (!DbgOpt) {
00756                         /* Parent ends and child becomes a daemon */
00757                         if ((pid = fork()) > 0) {
00758                                 /* Write process id. in pid file */
00759                                 lfd = open(PidFile, O_TRUNC | O_WRONLY);
00760                                 len = sprintf(line, "%5d", pid);
00761                                 write(lfd, line, len);
00762                                 close(lfd);
00763 
00764                                 /* Wait for initialization to complete */
00765                                 exit(EXIT_SUCCESS);
00766                         }
00767                         sleep(1);
00768                         setsid();       /* Set as session leader */
00769                         chdir("/");     /* Change to the root directory */
00770                         /* Get rid of all open files */
00771                         for (lfd = STDERR_FILENO + 1; lfd < OPEN_MAX; lfd += 1)
00772                                 close(lfd);
00773                 }
00774         } else {
00775                 fprintf(stderr, "\n%s already running\n", ProgName);
00776                 exit(EXIT_FAILURE);
00777         }
00778   } else {
00779         fprintf(stderr, "\n%s can't open %s (%s)\n", ProgName, PidFile, strerror(errno));
00780         exit(EXIT_FAILURE);
00781   }
00782   return;
00783 }
00784 
00785 /*
00786 **  Name:       int main(int argc, char **argv);
00787 **  Function:   Syslog daemon entry point
00788 */
00789 int main(int argc, char **argv)
00790 {
00791   char *p, *udpdev, *eol;
00792   int nfd, kfd, len, fdmax;
00793   int ch, port = 0;
00794   fd_set fdset;
00795   struct nwio_udpopt udpopt;
00796   struct servent *sp;
00797   char line[MAXLINE + 1];
00798 
00799   while ((ch = getopt(argc, argv, "df:m:p:v?")) != EOF) {
00800         switch ((char) ch) {
00801             case 'd':           /* Debug */
00802                 DbgOpt += 1;
00803                 break;
00804             case 'f':           /* Set configuration file */
00805                 ConfFile = optarg;
00806                 break;
00807             case 'm':           /* Set mark interval */
00808                 MarkInterval = atoi(optarg) * 60;
00809                 break;
00810             case 'p':           /* Set listening port */
00811                 port = atoi(optarg);
00812                 break;
00813             case 'v':           /* Print version */
00814                 fprintf(stderr, "%s version %s\n", ProgName, version);
00815                 return EXIT_FAILURE;
00816             case '?':           /* Help */
00817             default:
00818                 fprintf(stderr, usage);
00819                 return EXIT_FAILURE;
00820         }
00821   }
00822   if (argc -= optind) {
00823         fprintf(stderr, usage);
00824         return EXIT_FAILURE;
00825   }
00826 
00827   daemonize(line);
00828 
00829   /* Get the official name of local host. */
00830   gethostname(LocalHostName, sizeof(LocalHostName) - 1);
00831   if ((p = strchr(LocalHostName, '.'))) *p = '\0';
00832 
00833   udpdev = (p = getenv("UDP_DEVICE")) ? p : UDP_DEVICE;
00834   sp = getservbyname("syslog", "udp");
00835 
00836   signal(SIGTERM, die);
00837   signal(SIGINT, DbgOpt ? die : SIG_IGN);
00838   signal(SIGQUIT, DbgOpt ? die : SIG_IGN);
00839   signal(SIGALRM, domark);
00840 
00841   alarm(TIMERINTVL);
00842 
00843   /* Open UDP device */
00844   nfd = open(udpdev, O_NONBLOCK | O_RDONLY);
00845 
00846   /* Configures the UDP device */
00847   udpopt.nwuo_flags = NWUO_SHARED | NWUO_LP_SET | NWUO_EN_LOC |
00848         NWUO_DI_BROAD | NWUO_RP_SET | NWUO_RA_SET |
00849         NWUO_RWDATONLY | NWUO_DI_IPOPT;
00850   udpopt.nwuo_locport = udpopt.nwuo_remport =
00851                         port == 0 ? sp->s_port : htons(port);
00852   udpopt.nwuo_remaddr = udpopt.nwuo_locaddr = htonl(0x7F000001L);
00853   
00854  if(nfd >= 0) {
00855   while (ioctl(nfd, NWIOSUDPOPT, &udpopt) < 0 ||
00856       ioctl(nfd, NWIOGUDPOPT, &udpopt) < 0) {
00857         if (errno == EAGAIN) {
00858                 sleep(1);
00859                 continue;
00860         }
00861         logerror("Set/Get UDP options failed");
00862         return EXIT_FAILURE;
00863   }
00864  }
00865 
00866   /* Open kernel log device */
00867   kfd = open("/dev/klog", O_NONBLOCK | O_RDONLY);
00868 
00869   if(kfd < 0 && nfd < 0) {
00870         logerror("open /dev/klog and udp device failed - can't log anything");
00871         return EXIT_FAILURE;
00872   }
00873 
00874   fdmax = max(nfd, kfd) + 1;
00875 
00876   DEBUG(dprintf("off & running....\n");)
00877   
00878   init(-1);                     /* Initilizes log data structures */
00879 
00880   for (;;) {                    /* Main loop */
00881 
00882         FD_ZERO(&fdset);        /* Setup descriptors for select */
00883         if(nfd >= 0) FD_SET(nfd, &fdset);
00884         if(kfd >= 0) FD_SET(kfd, &fdset);
00885 
00886         if (select(fdmax, &fdset, NULL, NULL, NULL) <= 0) {
00887                 sleep(1);
00888                 continue;
00889 
00890         }
00891         if (nfd >= 0 && FD_ISSET(nfd, &fdset)) {
00892 
00893                 /* Read a message from application programs */
00894                 len = read(nfd, line, MAXLINE);
00895                 if (len > 0) {          /* Got a message */
00896                         line[len] = '\0';
00897                         dprintf("got a message (%d, %#x)\n", nfd, len);
00898                         printline(LocalHostName, line);
00899 
00900                 } else if (len < 0) {   /* Got an error or signal while reading */
00901                         if (errno != EINTR)     /* */
00902                                 logerror("Receive error from UDP channel");
00903 
00904                 } else {        /* (len == 0) Channel has been closed */
00905                         logerror("UDP channel has closed");
00906                         close(nfd);
00907                         die(-1);
00908                 }
00909         }
00910         if (kfd >= 0 && FD_ISSET(kfd, &fdset)) {
00911                 static char linebuf[5*1024];
00912 
00913                 /* Read a message from kernel (klog) */
00914                 len = read(kfd, linebuf, sizeof(linebuf)-2);
00915                 dprintf("got a message (%d, %#x)\n", kfd, len);
00916                 for (ch = 0; ch < len; ch += 1)
00917                         if (linebuf[ch] == '\0') linebuf[ch] = ' ';
00918                 if (linebuf[len - 1] == '\n') len -= 1;
00919                 linebuf[len] = '\n';
00920                 linebuf[len + 1] = '\0';
00921                 p = linebuf;
00922                 while(eol = strchr(p, '\n')) {
00923                         *eol = '\0';
00924                         printkline(LocalHostName, p);
00925                         p = eol+1;
00926                 }
00927         }
00928   }
00929   /* Control never gets here */
00930 }
00931 

Generated on Fri Apr 14 22:57:13 2006 for minix by  doxygen 1.4.6