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

Defined functions

cfline defined in line 913; used 3 times
cvthname defined in line 699; used 2 times
decode defined in line 1061; used 2 times
die defined in line 765; used 7 times
domark defined in line 724; used 2 times
flushmsg defined in line 735; used 5 times
init defined in line 783; used 2 times
logerror defined in line 749; used 17 times
logmsg defined in line 431; used 6 times
main defined in line 150; never used
printline defined in line 344; used 2 times
printsys defined in line 389; used 1 times
reapchild defined in line 688; used 2 times
untty defined in line 326; used 3 times
usage defined in line 320; used 2 times
wallmsg defined in line 610; used 1 times

Defined variables

ConfFile defined in line 71; used 3 times
Debug defined in line 132; used 8 times
FacNames defined in line 892; used 1 times
Files defined in line 130; used 10 times
InetInuse defined in line 135; used 2 times
Initialized defined in line 142; used 2 times
LocalDomain defined in line 134; used 3 times
LocalHostName defined in line 133; used 8 times
LogName defined in line 70; used 7 times
LogPort defined in line 136; used 2 times
MarkInterval defined in line 143; used 4 times
MarkSeq defined in line 144; used 1 times
PidFile defined in line 72; used 1 times
PrevCount defined in line 141; used 5 times
PrevFlags defined in line 139; used 2 times
PrevHost defined in line 138; used 2 times
PrevLine defined in line 137; used 6 times
PrevPri defined in line 140; used 2 times
PriNames defined in line 876; used 1 times
TypeNames defined in line 125; used 2 times
copyright defined in line 8; never used
ctty defined in line 73; used 2 times
sccsid defined in line 14; never used

Defined struct's

code defined in line 871; used 8 times
filed defined in line 101; used 10 times

Defined macros

ADDDATE defined in line 93; used 7 times
DEFSPRI defined in line 42; used 2 times
DEFUPRI defined in line 41; used 2 times
FDMASK defined in line 75; used 4 times
F_CONSOLE defined in line 120; used 1 times
F_FILE defined in line 118; used 4 times
F_FORW defined in line 121; used 1 times
F_TTY defined in line 119; used 2 times
F_UNUSED defined in line 117; used 4 times
F_USERS defined in line 122; used 2 times
F_WALL defined in line 123; used 2 times
IGN_CONS defined in line 90; used 2 times
LOG_MARK defined in line 84; used 1 times
MARK defined in line 94; used 4 times
MARKCOUNT defined in line 43; used 3 times
MAXFNAME defined in line 81; used 1 times
MAXLINE defined in line 40; used 10 times
MAXUNAMES defined in line 80; used 6 times
NLOGS defined in line 39; used 5 times
NOCOPY defined in line 92; used 2 times
NOPRI defined in line 83; used 4 times
SYNC_FILE defined in line 91; used 2 times
UNAMESZ defined in line 79; used 6 times
dprintf defined in line 77; used 21 times
Last modified: 1986-05-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4127
Valid CSS Valid XHTML 1.0 Strict