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