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: }