1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #if defined(DOSCCS) && !defined(lint)
   8: char copyright[] =
   9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: 
  12: static char sccsid[] = "@(#)syslogd.c	5.13.6 (2.11BSD) 1999/6/18";
  13: #endif
  14: 
  15: /*
  16:  *  syslogd -- log system messages
  17:  *
  18:  * This program implements a system log. It takes a series of lines.
  19:  * Each line may have a priority, signified as "<n>" as
  20:  * the first characters of the line.  If this is
  21:  * not present, a default priority is used.
  22:  *
  23:  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  24:  * cause it to reread its configuration file.
  25:  *
  26:  * Defined Constants:
  27:  *
  28:  * MAXLINE -- the maximimum line length that can be handled.
  29:  * NLOGS   -- the maximum number of simultaneous log files.
  30:  * DEFUPRI -- the default priority for user messages
  31:  * DEFSPRI -- the default priority for kernel messages
  32:  *
  33:  * Author: Eric Allman
  34:  * extensive changes by Ralph Campbell
  35:  */
  36: 
  37: #define NLOGS       20      /* max number of log files */
  38: #define MAXLINE     1024        /* maximum line length */
  39: #define DEFUPRI     (LOG_USER|LOG_NOTICE)
  40: #define DEFSPRI     (LOG_KERN|LOG_CRIT)
  41: #define MARKCOUNT   10      /* ratio of minor to major marks */
  42: 
  43: #include <errno.h>
  44: #include <stdio.h>
  45: #include <utmp.h>
  46: #include <ctype.h>
  47: #include <signal.h>
  48: #include <sysexits.h>
  49: #include <string.h>
  50: 
  51: #include <sys/syslog.h>
  52: #include <sys/types.h>
  53: #include <sys/param.h>
  54: #include <sys/ioctl.h>
  55: #include <sys/stat.h>
  56: #include <sys/wait.h>
  57: #include <sys/socket.h>
  58: #include <sys/file.h>
  59: #include <sys/msgbuf.h>
  60: #include <sys/uio.h>
  61: #include <sys/un.h>
  62: #include <sys/time.h>
  63: #include <sys/resource.h>
  64: 
  65: #include <netinet/in.h>
  66: #include <netdb.h>
  67: 
  68: char    *LogName = "/dev/log";
  69: char    *ConfFile = "/etc/syslog.conf";
  70: char    *PidFile = "/var/run/syslog.pid";
  71: char    ctty[] = "/dev/console";
  72: 
  73: #define FDMASK(fd)  (1 << (fd))
  74: 
  75: #define dprintf     if (Debug) printf
  76: 
  77: #define UNAMESZ     14  /* length of a login name */
  78: #define MAXUNAMES   20  /* maximum number of user names */
  79: #define MAXFNAME    200 /* max file pathname length */
  80: 
  81: #define NOPRI       0x10    /* the "no priority" priority */
  82: #define LOG_MARK    (LOG_NFACILITIES << 3)  /* mark "facility" */
  83: 
  84: /*
  85:  * Flags to logmsg().
  86:  */
  87: 
  88: #define IGN_CONS    0x001   /* don't print on console */
  89: #define SYNC_FILE   0x002   /* do fsync on file after printing */
  90: #define NOCOPY      0x004   /* don't suppress duplicate messages */
  91: #define ADDDATE     0x008   /* add a date to the message */
  92: #define MARK        0x010   /* this message is a mark */
  93: 
  94: /*
  95:  * This structure represents the files that will have log
  96:  * copies printed.
  97:  */
  98: 
  99: struct filed {
 100:     short   f_type;         /* entry type, see below */
 101:     short   f_file;         /* file descriptor */
 102:     time_t  f_time;         /* time this was last written */
 103:     u_char  f_pmask[LOG_NFACILITIES+1]; /* priority mask */
 104:     union {
 105:         char    f_uname[MAXUNAMES][UNAMESZ+1];
 106:         struct {
 107:             char    f_hname[MAXHOSTNAMELEN+1];
 108:             struct sockaddr_in  f_addr;
 109:         } f_forw;       /* forwarding address */
 110:         char    f_fname[MAXFNAME];
 111:     } f_un;
 112: };
 113: 
 114: /* values for f_type */
 115: #define F_UNUSED    0       /* unused entry */
 116: #define F_FILE      1       /* regular file */
 117: #define F_TTY       2       /* terminal */
 118: #define F_CONSOLE   3       /* console terminal */
 119: #define F_FORW      4       /* remote machine */
 120: #define F_USERS     5       /* list of users */
 121: #define F_WALL      6       /* everyone logged on */
 122: 
 123: char    *TypeNames[7] = {
 124:     "UNUSED",   "FILE",     "TTY",      "CONSOLE",
 125:     "FORW",     "USERS",    "WALL"
 126: };
 127: 
 128: struct filed    Files[NLOGS];
 129: 
 130: int Debug;          /* debug flag */
 131: char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
 132: char    *LocalDomain;       /* our local domain name */
 133: int InetInuse = 0;      /* non-zero if INET sockets are being used */
 134: int LogPort;        /* port number for INET connections */
 135: char    PrevLine[MAXLINE + 1];  /* copy of last line to supress repeats */
 136: char    PrevHost[MAXHOSTNAMELEN+1];     /* previous host */
 137: int PrevFlags;
 138: int PrevPri;
 139: int PrevCount = 0;      /* number of times seen */
 140: int Initialized = 0;    /* set when we have initialized ourselves */
 141: int MarkInterval = 20;  /* interval between marks in minutes */
 142: int MarkSeq = 0;        /* mark sequence number */
 143: static  sigset_t block_set; /* Signals to block while logging */
 144: 
 145: main(argc, argv)
 146:     int argc;
 147:     char **argv;
 148: {
 149:     register int i;
 150:     register char *p;
 151:     int funix, finet, fklog, len;
 152:     u_long inetm, klogm;
 153:     struct sockaddr_un sun, fromunix;
 154:     struct sockaddr_in sin, frominet;
 155:     FILE *fp;
 156:     struct itimerval itv;
 157:     sigset_t oset;
 158:     struct sigaction sigact;
 159:     char line[MSG_BSIZE + 1];
 160:     extern int die(), domark(), reapchild(), init();
 161: 
 162:     while (--argc > 0) {
 163:         p = *++argv;
 164:         if (p[0] != '-')
 165:             usage();
 166:         switch (p[1]) {
 167:         case 'f':       /* configuration file */
 168:             if (p[2] != '\0')
 169:                 ConfFile = &p[2];
 170:             break;
 171: 
 172:         case 'd':       /* debug */
 173:             Debug++;
 174:             break;
 175: 
 176:         case 'p':       /* path */
 177:             if (p[2] != '\0')
 178:                 LogName = &p[2];
 179:             break;
 180: 
 181:         case 'm':       /* mark interval */
 182:             if (p[2] != '\0')
 183:                 MarkInterval = atoi(&p[2]);
 184:             break;
 185: 
 186:         default:
 187:             usage();
 188:         }
 189:     }
 190: 
 191:     /* Init signal block set and block signals */
 192:     (void)sigemptyset(&block_set);
 193:     (void)sigaddset(&block_set, SIGHUP);
 194:     (void)sigaddset(&block_set, SIGALRM);
 195:     sigprocmask(SIG_BLOCK, &block_set, &oset);
 196: 
 197:     /* Setup signals */
 198:     sigact.sa_mask = block_set;
 199:     sigact.sa_flags = SA_NOCLDSTOP;
 200:     sigact.sa_handler = reapchild;
 201:     sigaction(SIGCHLD, &sigact, NULL);
 202: 
 203:     sigact.sa_flags = 0;
 204:     sigact.sa_handler = die;
 205:     sigaction(SIGTERM, &sigact, NULL);
 206: 
 207:     if  (!Debug)
 208:         sigact.sa_handler = SIG_IGN;
 209:     sigaction(SIGINT, &sigact, NULL);
 210:     sigaction(SIGQUIT, &sigact, NULL);
 211: 
 212:     sigact.sa_handler = init;
 213:     sigaction(SIGHUP, &sigact, NULL);
 214: 
 215:     sigact.sa_handler = domark;
 216:     sigaction(SIGALRM, &sigact, NULL);
 217: 
 218:     if  (!Debug)
 219:         daemon(0, 0);
 220:     else
 221:         setlinebuf(stdout);
 222: 
 223:     /* Initialize timer */
 224:     itv.it_interval.tv_sec = MarkInterval * 60 / MARKCOUNT;
 225:     itv.it_interval.tv_usec = 0;
 226:     itv.it_value.tv_sec = MarkInterval * 60 / MARKCOUNT;
 227:     itv.it_value.tv_usec = 0;
 228:     setitimer(ITIMER_REAL, &itv, NULL);
 229: 
 230:     (void) gethostname(LocalHostName, sizeof LocalHostName);
 231:     if (p = index(LocalHostName, '.')) {
 232:         *p++ = '\0';
 233:         LocalDomain = p;
 234:     }
 235:     else
 236:         LocalDomain = "";
 237: 
 238:     (void) unlink(LogName);
 239: 
 240:     sun.sun_family = AF_UNIX;
 241:     (void) strncpy(sun.sun_path, LogName, sizeof sun.sun_path);
 242:     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
 243:     if (funix < 0 || bind(funix, (struct sockaddr *) &sun,
 244:         sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0 ||
 245:         chmod(LogName, 0666) < 0) {
 246:         (void) sprintf(line, "cannot create %s", LogName);
 247:         logerror(line);
 248:         dprintf("cannot create %s (%d)\n", LogName, errno);
 249:         die(0);
 250:     }
 251:     finet = socket(AF_INET, SOCK_DGRAM, 0);
 252:     if (finet >= 0) {
 253:         struct servent *sp;
 254: 
 255:         sp = getservbyname("syslog", "udp");
 256:         if (sp == NULL) {
 257:             errno = 0;
 258:             logerror("syslog/udp: unknown service");
 259:             die(0);
 260:         }
 261:         sin.sin_family = AF_INET;
 262:         sin.sin_port = LogPort = sp->s_port;
 263:         if (bind(finet, &sin, sizeof(sin)) < 0) {
 264:             logerror("bind");
 265:             if (!Debug)
 266:                 die(0);
 267:         } else {
 268:             inetm = FDMASK(finet);
 269:             InetInuse = 1;
 270:         }
 271:     }
 272:     if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
 273:         klogm = FDMASK(fklog);
 274:     else {
 275:         dprintf("can't open /dev/klog (%d)\n", errno);
 276:         klogm = 0;
 277:     }
 278: 
 279:     /* tuck my process id away */
 280:     fp = fopen(PidFile, "w");
 281:     if (fp != NULL) {
 282:         fprintf(fp, "%d\n", getpid());
 283:         (void) fclose(fp);
 284:     }
 285: 
 286:     dprintf("off & running....\n");
 287: 
 288:     init(0);
 289: 
 290:     /* Unblock signals now */
 291:     (void)sigprocmask(SIG_SETMASK, &oset, NULL);
 292: 
 293:     for (;;) {
 294:         int nfds;
 295:         u_long readfds = FDMASK(funix) | inetm | klogm;
 296: 
 297:         errno = 0;
 298:         dprintf("readfds = %#x\n", readfds, funix, finet, fklog);
 299:         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
 300:                   (fd_set *) NULL, (struct timeval *) NULL);
 301:         dprintf("got a message (%d, %#x)\n", nfds, readfds);
 302:         if (nfds == 0)
 303:             continue;
 304:         if (nfds < 0) {
 305:             if (errno != EINTR)
 306:                 logerror("select");
 307:             continue;
 308:         }
 309:         if (readfds & klogm) {
 310:             i = read(fklog, line, sizeof(line) - 1);
 311:             if (i > 0) {
 312:                 line[i] = '\0';
 313:                 printsys(line);
 314:             } else if (i < 0 && errno != EINTR) {
 315:                 logerror("klog");
 316:                 fklog = -1;
 317:                 klogm = 0;
 318:             }
 319:         }
 320:         if (readfds & FDMASK(funix)) {
 321:             len = sizeof fromunix;
 322:             i = recvfrom(funix, line, MAXLINE, 0,
 323:                      (struct sockaddr *) &fromunix, &len);
 324:             if (i > 0) {
 325:                 line[i] = '\0';
 326:                 printline(LocalHostName, line);
 327:             } else if (i < 0 && errno != EINTR)
 328:                 logerror("recvfrom unix");
 329:         }
 330:         if (readfds & inetm) {
 331:             len = sizeof frominet;
 332:             i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len);
 333:             if (i > 0) {
 334:                 extern char *cvthname();
 335: 
 336:                 line[i] = '\0';
 337:                 printline(cvthname(&frominet), line);
 338:             } else if (i < 0 && errno != EINTR)
 339:                 logerror("recvfrom inet");
 340:         }
 341:     }
 342: }
 343: 
 344: usage()
 345: {
 346:     fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
 347:     exit(1);
 348: }
 349: 
 350: untty()
 351: {
 352:     int i;
 353: 
 354:     if (!Debug) {
 355:         i = open("/dev/tty", O_RDWR);
 356:         if (i >= 0) {
 357:             (void) ioctl(i, TIOCNOTTY, (char *)0);
 358:             (void) close(i);
 359:         }
 360:     }
 361: }
 362: 
 363: /*
 364:  * Take a raw input line, decode the message, and print the message
 365:  * on the appropriate log files.
 366:  */
 367: 
 368: printline(hname, msg)
 369:     char *hname;
 370:     char *msg;
 371: {
 372:     register char *p, *q;
 373:     register int c;
 374:     char line[MAXLINE + 1];
 375:     int pri;
 376: 
 377:     /* test for special codes */
 378:     pri = DEFUPRI;
 379:     p = msg;
 380:     if (*p == '<') {
 381:         pri = 0;
 382:         while (isdigit(*++p))
 383:             pri = 10 * pri + (*p - '0');
 384:         if (*p == '>')
 385:             ++p;
 386:         if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
 387:             pri = DEFUPRI;
 388:     }
 389: 
 390:     /* don't allow users to log kernel messages */
 391:     if ((pri & LOG_PRIMASK) == LOG_KERN)
 392:         pri |= LOG_USER;
 393: 
 394:     q = line;
 395: 
 396:     while ((c = *p++ & 0177) != '\0' && c != '\n' &&
 397:         q < &line[sizeof(line) - 1]) {
 398:         if (iscntrl(c)) {
 399:             *q++ = '^';
 400:             *q++ = c ^ 0100;
 401:         } else
 402:             *q++ = c;
 403:     }
 404:     *q = '\0';
 405: 
 406:     logmsg(pri, line, hname, 0);
 407: }
 408: 
 409: /*
 410:  * Take a raw input line from /dev/klog, split and format similar to syslog().
 411:  */
 412: 
 413: printsys(msg)
 414:     char *msg;
 415: {
 416:     register char *p, *q;
 417:     register int c;
 418:     char line[MAXLINE + 1];
 419:     int pri, flags;
 420:     char *lp;
 421:     time_t now;
 422: 
 423:     (void) time(&now);
 424:     (void) sprintf(line, "%.15s vmunix: ", ctime(&now) + 4);
 425:     lp = line + strlen(line);
 426:     for (p = msg; *p != '\0'; ) {
 427:         flags = SYNC_FILE;  /* fsync file after write */
 428:         pri = DEFSPRI;
 429:         if (*p == '<') {
 430:             pri = 0;
 431:             while (isdigit(*++p))
 432:                 pri = 10 * pri + (*p - '0');
 433:             if (*p == '>')
 434:                 ++p;
 435:             if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
 436:                 pri = DEFSPRI;
 437:         } else {
 438:             /* kernel printf's come out on console */
 439:             flags |= IGN_CONS;
 440:         }
 441:         q = lp;
 442:         while (*p != '\0' && (c = *p++) != '\n' &&
 443:             q < &line[MAXLINE])
 444:             *q++ = c;
 445:         *q = '\0';
 446:         logmsg(pri, line, LocalHostName, flags);
 447:     }
 448: }
 449: 
 450: /*
 451:  * Log a message to the appropriate log files, users, etc. based on
 452:  * the priority.
 453:  */
 454: 
 455: logmsg(pri, msg, from, flags)
 456:     int pri;
 457:     char *msg, *from;
 458:     int flags;
 459: {
 460:     register struct filed *f;
 461:     register int l;
 462:     int fac, prilev;
 463:     time_t now;
 464:     sigset_t oset;
 465:     struct iovec iov[6];
 466:     register struct iovec *v = iov;
 467:     char line[MAXLINE + 1];
 468: 
 469:     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);
 470: 
 471:     (void)sigprocmask(SIG_BLOCK, &block_set, &oset);
 472: 
 473:     /*
 474: 	 * Check to see if msg looks non-standard.
 475: 	 */
 476:     if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
 477:         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
 478:         flags |= ADDDATE;
 479: 
 480:     if (!(flags & NOCOPY)) {
 481:         if (flags & (ADDDATE|MARK))
 482:             flushmsg();
 483:         else if (!strcmp(msg + 16, PrevLine + 16)) {
 484:             /* we found a match, update the time */
 485:             (void) strncpy(PrevLine, msg, 15);
 486:             PrevCount++;
 487:             goto out;
 488:         } else {
 489:             /* new line, save it */
 490:             flushmsg();
 491:             (void) strcpy(PrevLine, msg);
 492:             (void) strcpy(PrevHost, from);
 493:             PrevFlags = flags;
 494:             PrevPri = pri;
 495:         }
 496:     }
 497: 
 498:     (void) time(&now);
 499:     if (flags & ADDDATE)
 500:         v->iov_base = ctime(&now) + 4;
 501:     else
 502:         v->iov_base = msg;
 503:     v->iov_len = 15;
 504:     v++;
 505:     v->iov_base = " ";
 506:     v->iov_len = 1;
 507:     v++;
 508:     v->iov_base = from;
 509:     v->iov_len = strlen(v->iov_base);
 510:     v++;
 511:     v->iov_base = " ";
 512:     v->iov_len = 1;
 513:     v++;
 514:     if (flags & ADDDATE)
 515:         v->iov_base = msg;
 516:     else
 517:         v->iov_base = msg + 16;
 518:     v->iov_len = strlen(v->iov_base);
 519:     v++;
 520: 
 521:     /* extract facility and priority level */
 522:     fac = (pri & LOG_FACMASK) >> 3;
 523:     if (flags & MARK)
 524:         fac = LOG_NFACILITIES;
 525:     prilev = pri & LOG_PRIMASK;
 526: 
 527:     /* log the message to the particular outputs */
 528:     if (!Initialized) {
 529:         int cfd = open(ctty, O_WRONLY);
 530: 
 531:         if (cfd >= 0) {
 532:             v->iov_base = "\r\n";
 533:             v->iov_len = 2;
 534:             (void) writev(cfd, iov, 6);
 535:             (void) close(cfd);
 536:         }
 537:         untty();
 538:         goto out;
 539:     }
 540:     for (f = Files; f < &Files[NLOGS]; f++) {
 541:         /* skip messages that are incorrect priority */
 542:         if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
 543:             continue;
 544: 
 545:         /* don't output marks to recently written files */
 546:         if ((flags & MARK) && (now - f->f_time) < (MarkInterval * 60 / 2))
 547:             continue;
 548: 
 549:         dprintf("Logging to %s", TypeNames[f->f_type]);
 550:         f->f_time = now;
 551:         switch (f->f_type) {
 552:         case F_UNUSED:
 553:             dprintf("\n");
 554:             break;
 555: 
 556:         case F_FORW:
 557:             dprintf(" %s\n", f->f_un.f_forw.f_hname);
 558:             (void) sprintf(line, "<%d>%.15s %s", pri,
 559:                 iov[0].iov_base, iov[4].iov_base);
 560:             l = strlen(line);
 561:             if (l > MAXLINE)
 562:                 l = MAXLINE;
 563:             if (sendto(f->f_file, line, l, 0,
 564:                 &f->f_un.f_forw.f_addr,
 565:                 sizeof f->f_un.f_forw.f_addr) != l) {
 566:                 int e = errno;
 567:                 (void) close(f->f_file);
 568:                 f->f_type = F_UNUSED;
 569:                 errno = e;
 570:                 logerror("sendto");
 571:             }
 572:             break;
 573: 
 574:         case F_CONSOLE:
 575:             if (flags & IGN_CONS) {
 576:                 dprintf(" (ignored)\n");
 577:                 break;
 578:             }
 579: 
 580:         case F_TTY:
 581:         case F_FILE:
 582:             dprintf(" %s\n", f->f_un.f_fname);
 583:             if (f->f_type != F_FILE) {
 584:                 v->iov_base = "\r\n";
 585:                 v->iov_len = 2;
 586:             } else {
 587:                 v->iov_base = "\n";
 588:                 v->iov_len = 1;
 589:             }
 590:             if (writev(f->f_file, iov, 6) < 0) {
 591:                 int e = errno;
 592:                 (void) close(f->f_file);
 593:                 /*
 594: 				 * Check for EBADF on TTY's due to vhangup() XXX
 595: 				 */
 596:                 if (e == EBADF && f->f_type != F_FILE) {
 597:                     f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
 598:                     if (f->f_file < 0) {
 599:                         f->f_type = F_UNUSED;
 600:                         logerror(f->f_un.f_fname);
 601:                     }
 602:                 } else {
 603:                     f->f_type = F_UNUSED;
 604:                     errno = e;
 605:                     logerror(f->f_un.f_fname);
 606:                 }
 607:             } else if (flags & SYNC_FILE)
 608:                 (void) fsync(f->f_file);
 609:             break;
 610: 
 611:         case F_USERS:
 612:         case F_WALL:
 613:             dprintf("\n");
 614:             v->iov_base = "\r\n";
 615:             v->iov_len = 2;
 616:             wallmsg(f, iov);
 617:             break;
 618:         }
 619:     }
 620: out:
 621:     (void)sigprocmask(SIG_SETMASK, &oset, NULL);
 622: }
 623: 
 624: 
 625: /*
 626:  *  WALLMSG -- Write a message to the world at large
 627:  *
 628:  *	Write the specified message to either the entire
 629:  *	world, or a list of approved users.
 630:  */
 631: 
 632: wallmsg(f, iov)
 633:     register struct filed *f;
 634:     struct iovec *iov;
 635: {
 636:     register char *p;
 637:     register int i;
 638:     int ttyf, len;
 639:     FILE *uf;
 640:     static int reenter = 0;
 641:     struct utmp ut;
 642:     time_t now;
 643:     char greetings[200];
 644: 
 645:     if (reenter++)
 646:         return;
 647: 
 648:     /* open the user login file */
 649:     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
 650:         logerror(_PATH_UTMP);
 651:         reenter = 0;
 652:         return;
 653:     }
 654: 
 655:     (void) time(&now);
 656:     (void) sprintf(greetings,
 657:         "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
 658:         iov[2].iov_base, ctime(&now));
 659:     len = strlen(greetings);
 660: 
 661:     /* scan the user login file */
 662:     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
 663:         /* is this slot used? */
 664:         if (ut.ut_name[0] == '\0')
 665:             continue;
 666: 
 667:         /* should we send the message to this user? */
 668:         if (f->f_type == F_USERS) {
 669:             for (i = 0; i < MAXUNAMES; i++) {
 670:                 if (!f->f_un.f_uname[i][0]) {
 671:                     i = MAXUNAMES;
 672:                     break;
 673:                 }
 674:                 if (strncmp(f->f_un.f_uname[i], ut.ut_name,
 675:                     UNAMESZ) == 0)
 676:                     break;
 677:             }
 678:             if (i >= MAXUNAMES)
 679:                 continue;
 680:         }
 681: 
 682:         /*
 683: 		 * Might as well fork instead of using nonblocking I/O
 684: 		 * and doing notty().
 685: 		 */
 686:         if (fork() == 0) {
 687: 
 688:             /* compute the device name */
 689:             p = (char *)calloc(1, sizeof ("/dev/") + UNAMESZ + 2);
 690:             strcpy(p, "/dev/");
 691:             strncat(p+5, ut.ut_line, UNAMESZ);
 692: 
 693:             if (f->f_type == F_WALL) {
 694:                 iov[0].iov_base = greetings;
 695:                 iov[0].iov_len = len;
 696:                 iov[1].iov_len = 0;
 697:             }
 698:             (void) signal(SIGALRM, SIG_DFL);
 699:             (void) alarm(30);
 700:             /* open the terminal */
 701:             ttyf = open(p, O_WRONLY);
 702:             if (ttyf >= 0)
 703:                 (void) writev(ttyf, iov, 6);
 704:             exit(0);
 705:         }
 706:     }
 707:     /* close the user login file */
 708:     (void) fclose(uf);
 709:     reenter = 0;
 710: }
 711: 
 712: reapchild()
 713: {
 714:     union wait status;
 715: 
 716:     while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
 717:         ;
 718: }
 719: 
 720: /*
 721:  * Return a printable representation of a host address.
 722:  */
 723: char *
 724: cvthname(f)
 725:     struct sockaddr_in *f;
 726: {
 727:     struct hostent *hp;
 728:     register char *p;
 729:     extern char *inet_ntoa();
 730: 
 731:     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
 732: 
 733:     if (f->sin_family != AF_INET) {
 734:         dprintf("Malformed from address\n");
 735:         return ("???");
 736:     }
 737:     hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
 738:     if (hp == 0) {
 739:         dprintf("Host name for your address (%s) unknown\n",
 740:             inet_ntoa(f->sin_addr));
 741:         return (inet_ntoa(f->sin_addr));
 742:     }
 743:     if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
 744:         *p = '\0';
 745:     return (hp->h_name);
 746: }
 747: 
 748: domark()
 749: {
 750: 
 751:     if ((++MarkSeq % MARKCOUNT) == 0)
 752:         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
 753:     else
 754:         flushmsg();
 755: }
 756: 
 757: flushmsg()
 758: {
 759:     if (PrevCount == 0)
 760:         return;
 761:     if (PrevCount > 1)
 762:         (void) sprintf(PrevLine+16, "last message repeated %d times", PrevCount);
 763:     PrevCount = 0;
 764:     logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY);
 765:     PrevLine[0] = '\0';
 766: }
 767: 
 768: /*
 769:  * Print syslogd errors some place.
 770:  */
 771: logerror(type)
 772:     char *type;
 773: {
 774:     char buf[100];
 775: 
 776:     if (errno == 0)
 777:         (void) sprintf(buf, "syslogd: %s", type);
 778:     else
 779:         (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
 780:     errno = 0;
 781:     dprintf("%s\n", buf);
 782:     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
 783: }
 784: 
 785: die(sig)
 786: {
 787:     char buf[100];
 788: 
 789:     if (sig) {
 790:         dprintf("syslogd: going down on signal %d\n", sig);
 791:         flushmsg();
 792:         (void) sprintf(buf, "going down on signal %d", sig);
 793:         logerror(buf);
 794:     }
 795:     (void) unlink(LogName);
 796:     exit(0);
 797: }
 798: 
 799: /*
 800:  *  INIT -- Initialize syslogd from configuration table
 801:  */
 802: 
 803: /* ARGSUSED */
 804: init(sig)
 805:     int sig;        /* signal number */
 806: {
 807:     register int i;
 808:     register FILE *cf;
 809:     register struct filed *f;
 810:     register char *p;
 811:     char cline[BUFSIZ];
 812: 
 813:     dprintf("init\n");
 814: 
 815:     /* flush any pending output */
 816:     flushmsg();
 817: 
 818:     /*
 819: 	 *  Close all open log files.
 820: 	 */
 821:     for (f = Files; f < &Files[NLOGS]; f++) {
 822:         switch (f->f_type) {
 823:           case F_FILE:
 824:           case F_TTY:
 825:           case F_FORW:
 826:           case F_CONSOLE:
 827:             (void) close(f->f_file);
 828:             break;
 829:         }
 830:         f->f_type = F_UNUSED;
 831:     }
 832: 
 833:     /* open the configuration file */
 834:     if ((cf = fopen(ConfFile, "r")) == NULL) {
 835:         dprintf("cannot open %s\n", ConfFile);
 836:         cfline("*.ERR\t/dev/console", &Files[0]);
 837:         cfline("*.PANIC\t*", &Files[1]);
 838:         return;
 839:     }
 840: 
 841:     /*
 842: 	 *  Foreach line in the conf table, open that file.
 843: 	 */
 844:     f = Files;
 845:     while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) {
 846:         /* check for end-of-section */
 847:         if (cline[0] == '\n' || cline[0] == '#')
 848:             continue;
 849: 
 850:         /* strip off newline character */
 851:         p = index(cline, '\n');
 852:         if (p)
 853:             *p = '\0';
 854: 
 855:         cfline(cline, f++);
 856:     }
 857: 
 858:     /* close the configuration file */
 859:     (void) fclose(cf);
 860: 
 861:     Initialized = 1;
 862: 
 863:     if (Debug) {
 864:         for (f = Files; f < &Files[NLOGS]; f++) {
 865:             for (i = 0; i <= LOG_NFACILITIES; i++)
 866:                 if (f->f_pmask[i] == NOPRI)
 867:                     printf("X ");
 868:                 else
 869:                     printf("%d ", f->f_pmask[i]);
 870:             printf("%s: ", TypeNames[f->f_type]);
 871:             switch (f->f_type) {
 872:             case F_FILE:
 873:             case F_TTY:
 874:             case F_CONSOLE:
 875:                 printf("%s", f->f_un.f_fname);
 876:                 break;
 877: 
 878:             case F_FORW:
 879:                 printf("%s", f->f_un.f_forw.f_hname);
 880:                 break;
 881: 
 882:             case F_USERS:
 883:                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
 884:                     printf("%s, ", f->f_un.f_uname[i]);
 885:                 break;
 886:             }
 887:             printf("\n");
 888:         }
 889:     }
 890: 
 891:     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
 892:     dprintf("syslogd: restarted\n");
 893: }
 894: 
 895: /*
 896:  * Crack a configuration file line
 897:  */
 898: 
 899: struct code {
 900:     char    *c_name;
 901:     int c_val;
 902: };
 903: 
 904: struct code PriNames[] = {
 905:     "emerg",    LOG_EMERG,
 906:     "alert",    LOG_ALERT,
 907:     "crit",     LOG_CRIT,
 908:     "err",      LOG_ERR,
 909:     "warn",     LOG_WARNING,
 910:     "notice",   LOG_NOTICE,
 911:     "info",     LOG_INFO,
 912:     "debug",    LOG_DEBUG,
 913:     "none",     NOPRI,
 914:     NULL,       -1
 915: };
 916: 
 917: struct code FacNames[] = {
 918:     "kern",     LOG_KERN,
 919:     "user",     LOG_USER,
 920:     "mail",     LOG_MAIL,
 921:     "daemon",   LOG_DAEMON,
 922:     "auth",     LOG_AUTH,
 923:     "mark",     LOG_MARK,
 924:     "syslog",   LOG_SYSLOG,
 925:     "lpr",      LOG_LPR,
 926:     "cron",     LOG_CRON,
 927:     "local0",   LOG_LOCAL0,
 928:     "local1",   LOG_LOCAL1,
 929:     "local2",   LOG_LOCAL2,
 930:     "local3",   LOG_LOCAL3,
 931:     "local4",   LOG_LOCAL4,
 932:     "local5",   LOG_LOCAL5,
 933:     "local6",   LOG_LOCAL6,
 934:     "local7",   LOG_LOCAL7,
 935:     NULL,       -1
 936: };
 937: 
 938: cfline(line, f)
 939:     char *line;
 940:     register struct filed *f;
 941: {
 942:     register char *p;
 943:     register char *q;
 944:     register int i;
 945:     char *bp;
 946:     int pri;
 947:     struct hostent *hp;
 948:     char buf[MAXLINE];
 949: 
 950:     dprintf("cfline(%s)\n", line);
 951: 
 952:     /* clear out file entry */
 953:     bzero((char *) f, sizeof *f);
 954:     for (i = 0; i <= LOG_NFACILITIES; i++)
 955:         f->f_pmask[i] = NOPRI;
 956: 
 957:     /* scan through the list of selectors */
 958:     for (p = line; *p && *p != '\t';) {
 959: 
 960:         /* find the end of this facility name list */
 961:         for (q = p; *q && *q != '\t' && *q++ != '.'; )
 962:             continue;
 963: 
 964:         /* collect priority name */
 965:         for (bp = buf; *q && !index("\t,;", *q); )
 966:             *bp++ = *q++;
 967:         *bp = '\0';
 968: 
 969:         /* skip cruft */
 970:         while (index(", ;", *q))
 971:             q++;
 972: 
 973:         /* decode priority name */
 974:         pri = decode(buf, PriNames);
 975:         if (pri < 0) {
 976:             char xbuf[200];
 977: 
 978:             (void) sprintf(xbuf, "unknown priority name \"%s\"", buf);
 979:             logerror(xbuf);
 980:             return;
 981:         }
 982: 
 983:         /* scan facilities */
 984:         while (*p && !index("\t.;", *p)) {
 985:             for (bp = buf; *p && !index("\t,;.", *p); )
 986:                 *bp++ = *p++;
 987:             *bp = '\0';
 988:             if (*buf == '*')
 989:                 for (i = 0; i < LOG_NFACILITIES; i++)
 990:                     f->f_pmask[i] = pri;
 991:             else {
 992:                 i = decode(buf, FacNames);
 993:                 if (i < 0) {
 994:                     char xbuf[200];
 995: 
 996:                     (void) sprintf(xbuf, "unknown facility name \"%s\"", buf);
 997:                     logerror(xbuf);
 998:                     return;
 999:                 }
1000:                 f->f_pmask[i >> 3] = pri;
1001:             }
1002:             while (*p == ',' || *p == ' ')
1003:                 p++;
1004:         }
1005: 
1006:         p = q;
1007:     }
1008: 
1009:     /* skip to action part */
1010:     while (*p == '\t')
1011:         p++;
1012: 
1013:     switch (*p)
1014:     {
1015:     case '@':
1016:         if (!InetInuse)
1017:             break;
1018:         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1019:         hp = gethostbyname(p);
1020:         if (hp == NULL) {
1021:             (void) sprintf(buf, "unknown host %s", p);
1022:             errno = 0;
1023:             logerror(buf);
1024:             break;
1025:         }
1026:         bzero((char *) &f->f_un.f_forw.f_addr,
1027:              sizeof f->f_un.f_forw.f_addr);
1028:         f->f_un.f_forw.f_addr.sin_family = AF_INET;
1029:         f->f_un.f_forw.f_addr.sin_port = LogPort;
1030:         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
1031:         f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
1032:         if (f->f_file < 0) {
1033:             logerror("socket");
1034:             break;
1035:         }
1036:         f->f_type = F_FORW;
1037:         break;
1038: 
1039:     case '/':
1040:         (void) strcpy(f->f_un.f_fname, p);
1041:         if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
1042:             logerror(p);
1043:             break;
1044:         }
1045:         if (isatty(f->f_file)) {
1046:             f->f_type = F_TTY;
1047:             untty();
1048:         }
1049:         else
1050:             f->f_type = F_FILE;
1051:         if (strcmp(p, ctty) == 0)
1052:             f->f_type = F_CONSOLE;
1053:         break;
1054: 
1055:     case '*':
1056:         f->f_type = F_WALL;
1057:         break;
1058: 
1059:     default:
1060:         for (i = 0; i < MAXUNAMES && *p; i++) {
1061:             for (q = p; *q && *q != ','; )
1062:                 q++;
1063:             (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
1064:             if ((q - p) > UNAMESZ)
1065:                 f->f_un.f_uname[i][UNAMESZ] = '\0';
1066:             else
1067:                 f->f_un.f_uname[i][q - p] = '\0';
1068:             while (*q == ',' || *q == ' ')
1069:                 q++;
1070:             p = q;
1071:         }
1072:         f->f_type = F_USERS;
1073:         break;
1074:     }
1075: }
1076: 
1077: 
1078: /*
1079:  *  Decode a symbolic name to a numeric value
1080:  */
1081: 
1082: decode(name, codetab)
1083:     char *name;
1084:     struct code *codetab;
1085: {
1086:     register struct code *c;
1087:     register char *p;
1088:     char buf[40];
1089: 
1090:     if (isdigit(*name))
1091:         return (atoi(name));
1092: 
1093:     (void) strcpy(buf, name);
1094:     for (p = buf; *p; p++)
1095:         if (isupper(*p))
1096:             *p = tolower(*p);
1097:     for (c = codetab; c->c_name; c++)
1098:         if (!strcmp(buf, c->c_name))
1099:             return (c->c_val);
1100: 
1101:     return (-1);
1102: }

Defined functions

cfline defined in line 938; used 3 times
cvthname defined in line 723; used 2 times
decode defined in line 1082; used 2 times
die defined in line 785; used 5 times
domark defined in line 748; used 2 times
flushmsg defined in line 757; used 5 times
init defined in line 804; used 3 times
logerror defined in line 771; used 17 times
logmsg defined in line 455; used 6 times
main defined in line 145; never used
printline defined in line 368; used 2 times
printsys defined in line 413; used 1 times
reapchild defined in line 712; used 2 times
untty defined in line 350; used 2 times
usage defined in line 344; used 2 times
wallmsg defined in line 632; used 1 times

Defined variables

ConfFile defined in line 69; used 3 times
Debug defined in line 130; used 7 times
FacNames defined in line 917; used 1 times
Files defined in line 128; used 10 times
InetInuse defined in line 133; used 2 times
Initialized defined in line 140; used 2 times
LocalDomain defined in line 132; used 3 times
LocalHostName defined in line 131; used 8 times
LogName defined in line 68; used 7 times
LogPort defined in line 134; used 2 times
MarkInterval defined in line 141; used 4 times
MarkSeq defined in line 142; used 1 times
PidFile defined in line 70; used 1 times
PrevCount defined in line 139; used 5 times
PrevFlags defined in line 137; used 2 times
PrevHost defined in line 136; used 2 times
PrevLine defined in line 135; used 6 times
PrevPri defined in line 138; used 2 times
PriNames defined in line 904; used 1 times
TypeNames defined in line 123; used 2 times
block_set defined in line 143; used 6 times
copyright defined in line 8; never used
ctty defined in line 71; used 2 times
sccsid defined in line 12; never used

Defined struct's

code defined in line 899; used 8 times
filed defined in line 99; used 10 times

Defined macros

ADDDATE defined in line 91; used 7 times
DEFSPRI defined in line 40; used 2 times
DEFUPRI defined in line 39; used 2 times
FDMASK defined in line 73; used 4 times
F_CONSOLE defined in line 118; used 1 times
F_FILE defined in line 116; used 3 times
F_FORW defined in line 119; used 1 times
F_TTY defined in line 117; used 1 times
F_UNUSED defined in line 115; used 4 times
F_USERS defined in line 120; used 2 times
F_WALL defined in line 121; used 2 times
IGN_CONS defined in line 88; used 2 times
LOG_MARK defined in line 82; used 1 times
MARK defined in line 92; used 4 times
MARKCOUNT defined in line 41; used 3 times
MAXFNAME defined in line 79; used 1 times
MAXLINE defined in line 38; used 10 times
MAXUNAMES defined in line 78; used 6 times
NLOGS defined in line 37; used 5 times
NOCOPY defined in line 90; used 2 times
NOPRI defined in line 81; used 4 times
SYNC_FILE defined in line 89; used 2 times
UNAMESZ defined in line 77; used 7 times
dprintf defined in line 75; used 21 times
Last modified: 1999-06-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7886
Valid CSS Valid XHTML 1.0 Strict