|
|
1.1 ! root 1: /* ! 2: ** SYSLOG -- log system messages ! 3: ** ! 4: ** This program implements a system log, implemented as the ! 5: ** "/dev/log" mpx file on a pre-4.2bsd system or a port on ! 6: ** a post-4.2bsd system. This takes a series of lines. ! 7: ** Each line may have a priority, signified as "<n>" as ! 8: ** the first three characters of the line. If this is ! 9: ** not present, a default priority (DefPri) is used, which ! 10: ** starts out as LOG_ERROR. The default priority can get ! 11: ** changed using "<*>n". ! 12: ** ! 13: ** Timestamps are added if they are not already present. ! 14: ** ! 15: ** To kill syslog, send a signal 15 (terminate). In 30 ! 16: ** seconds, syslog will go down. A signal 1 (hup) will ! 17: ** cause it to reread its configuration file. ! 18: ** ! 19: ** Defined Constants: ! 20: ** MAXLINE -- the maximimum line length that can be ! 21: ** handled. ! 22: ** NLOGS -- the maximum number of simultaneous log ! 23: ** files. ! 24: ** NUSERS -- the maximum number of people that can ! 25: ** be designated as "superusers" on your system. ! 26: ** ! 27: ** Author: ! 28: ** Eric Allman, UCB/INGRES and Britton-Lee. ! 29: */ ! 30: ! 31: # define NLOGS 10 /* max number of log files */ ! 32: # define NSUSERS 10 /* max number of special users */ ! 33: # define MAXLINE 256 /* maximum line length */ ! 34: ! 35: # define LOGHOSTNAME 1 /* log hostid on each line */ ! 36: ! 37: # include <syslog.h> ! 38: # include <errno.h> ! 39: # include <stdio.h> ! 40: # include <utmp.h> ! 41: # include <ctype.h> ! 42: # include <sys/param.h> ! 43: # include <sys/stat.h> ! 44: # include <signal.h> ! 45: # include <sysexits.h> ! 46: # ifdef LOG_IPC ! 47: # include <sys/socket.h> ! 48: #ifndef LOG_OLDIPC ! 49: # include <netinet/in.h> ! 50: # include <netdb.h> ! 51: #else LOG_OLDIPC ! 52: # include <net/in.h> ! 53: #endif LOG_OLDIPC ! 54: # else LOG_IPC ! 55: # include <sys/mx.h> ! 56: # endif LOG_IPC ! 57: ! 58: typedef char bool; ! 59: # define TRUE 1 ! 60: # define FALSE 0 ! 61: ! 62: # ifdef EBUG ! 63: # define dprintf if (Debug) printf ! 64: # else ! 65: # define dprintf if (0) printf ! 66: # endif ! 67: ! 68: static char SccsId[] = "@(#)syslog.c 4.1 7/25/83"; ! 69: ! 70: # define UNAMESZ 8 /* length of a login name */ ! 71: ! 72: /* ! 73: ** This structure represents the files that will have log ! 74: ** copies printed. ! 75: */ ! 76: ! 77: struct filed ! 78: { ! 79: char f_pmask; /* priority mask */ ! 80: bool f_mark; /* if set, output timing marks */ ! 81: bool f_tty; /* if set, this is a tty */ ! 82: FILE *f_file; /* file descriptor; NULL means unallocated */ ! 83: long f_time; /* the last time anything was output to it */ ! 84: char f_name[30]; /* filename */ ! 85: }; ! 86: ! 87: struct filed Files[NLOGS]; ! 88: ! 89: /* list of superusers */ ! 90: char Susers[NSUSERS][UNAMESZ+1]; ! 91: ! 92: int ShutDown; /* set if going down */ ! 93: int DefPri = LOG_ERROR; /* the default priority for untagged msgs */ ! 94: int Debug; /* debug flag */ ! 95: int LogFile; /* log mx file descriptor */ ! 96: int MarkIntvl = 15; /* mark interval in minutes */ ! 97: char *ConfFile; /* configuration file */ ! 98: ! 99: # ifdef LOG_IPC ! 100: #ifndef LOG_OLDIPC ! 101: struct sockaddr_in SyslogAddr; ! 102: #else LOG_OLDIPC ! 103: struct sockaddr_in SyslogAddr = { AF_INET, LOG_PORT }; ! 104: struct sockproto SyslogProto = { PF_INET, IPPROTO_UDP }; ! 105: #endif LOG_OLDIPC ! 106: # endif LOG_IPC ! 107: ! 108: main(argc, argv) ! 109: int argc; ! 110: char **argv; ! 111: { ! 112: register int i; ! 113: register char *p; ! 114: extern shutdown(); ! 115: extern int domark(); ! 116: extern int errno; ! 117: int errct = 0; ! 118: FILE *fp; ! 119: char *logname = "/dev/log"; ! 120: #ifndef LOG_OLDIPC ! 121: #ifdef LOG_IPC ! 122: auto int lenSyslogAddr; ! 123: struct servent *sp; ! 124: struct hostent *hp; ! 125: #endif LOG_IPC ! 126: #endif LOG_OLDIPC ! 127: static char *defconf = "/etc/syslog.conf"; ! 128: static char *defpid = "/etc/syslog.pid"; ! 129: char line[300]; ! 130: ! 131: #ifndef LOG_OLDIPC ! 132: #ifdef LOG_IPC ! 133: /* set up initial port assignment */ ! 134: sp = getservbyname("syslog", "udp"); ! 135: if (sp == NULL) ! 136: { ! 137: perror("Cannot get server"); ! 138: exit(EX_OSFILE); ! 139: } ! 140: SyslogAddr.sin_family = AF_INET; ! 141: SyslogAddr.sin_port = sp->s_port; ! 142: SyslogAddr.sin_addr.s_addr = INADDR_ANY; ! 143: #endif LOG_IPC ! 144: ! 145: #endif LOG_OLDIPC ! 146: while (--argc > 0) ! 147: { ! 148: p = *++argv; ! 149: if (p[0] == '-') ! 150: { ! 151: switch (p[1]) ! 152: { ! 153: case 'm': /* set mark interval */ ! 154: MarkIntvl = atoi(&p[2]); ! 155: if (MarkIntvl <= 0) ! 156: MarkIntvl = 1; ! 157: break; ! 158: ! 159: case 'f': /* configuration file */ ! 160: if (p[2] != '\0') ! 161: ConfFile = &p[2]; ! 162: else ! 163: ConfFile = defconf; ! 164: break; ! 165: ! 166: case 'd': /* debug */ ! 167: Debug++; ! 168: if (ConfFile == NULL) ! 169: ConfFile = "./syslog.conf"; ! 170: break; ! 171: ! 172: # ifdef LOG_IPC ! 173: case 'p': /* port */ ! 174: SyslogAddr.sin_port = htons(atoi(&p[2])); ! 175: break; ! 176: # endif LOG_IPC ! 177: } ! 178: } ! 179: } ! 180: ! 181: if (ConfFile == NULL) ! 182: ConfFile = defconf; ! 183: ! 184: /* try to ignore all signals */ ! 185: if (!Debug) ! 186: { ! 187: for (i = 1; i < NSIG; i++) ! 188: signal(i, SIG_IGN); ! 189: } ! 190: else ! 191: signal(SIGINT, shutdown); ! 192: signal(SIGTERM, shutdown); ! 193: signal(SIGALRM, domark); ! 194: alarm(MarkIntvl*60); ! 195: ! 196: /* close all files */ ! 197: if (!Debug) ! 198: for (i = 0; i < NOFILE; i++) ! 199: close(i); ! 200: ! 201: # ifdef LOG_IPC ! 202: logname = "IPC socket"; ! 203: #ifndef LOG_OLDIPC ! 204: LogFile = socket(AF_INET, SOCK_DGRAM, 0, 0); ! 205: if (LogFile >= 0 && bind(LogFile, &SyslogAddr, sizeof SyslogAddr, 0) < 0) ! 206: { ! 207: close(LogFile); ! 208: LogFile = -1; ! 209: } ! 210: #else LOG_OLDIPC ! 211: LogFile = socket(SOCK_DGRAM, &SyslogProto, &SyslogAddr, 0); ! 212: #endif LOG_OLDIPC ! 213: # else LOG_IPC ! 214: /* create the "/dev/log" device */ ! 215: if (Debug) ! 216: logname = "log"; ! 217: unlink(logname); ! 218: LogFile = mpx(logname, 0222); ! 219: chmod(logname, 0222); ! 220: # endif LOG_IPC ! 221: if (LogFile < 0) ! 222: { ! 223: fp = fopen("/dev/console", "w"); ! 224: fprintf(fp, "\r\nsyslog: cannot create %s (%d)\r\n", logname, errno); ! 225: dprintf("cannot create %s (%d)\n", logname, errno); ! 226: exit(EX_OSFILE); ! 227: } ! 228: ! 229: /* now we can run as daemon safely */ ! 230: setuid(1); ! 231: dprintf("off & running....\n"); ! 232: if (!Debug) ! 233: { ! 234: if (fork() == 0) ! 235: { ! 236: /* tuck my process id away */ ! 237: fp = fopen(defpid, "w"); ! 238: if (fp != NULL) ! 239: { ! 240: fprintf(fp, "%d\n", getpid()); ! 241: fclose(fp); ! 242: } ! 243: } ! 244: else ! 245: exit(0); ! 246: } ! 247: ! 248: init(); ! 249: ! 250: for (;;) ! 251: { ! 252: # ifdef LOG_IPC ! 253: #ifndef LOG_OLDIPC ! 254: lenSyslogAddr = sizeof SyslogAddr; ! 255: i = recvfrom(LogFile, line, sizeof line, 0, &SyslogAddr, &lenSyslogAddr); ! 256: #else LOG_OLDIPC ! 257: i = receive(LogFile, &SyslogAddr, line, sizeof line); ! 258: #endif LOG_OLDIPC ! 259: # else LOG_IPC ! 260: i = read(LogFile, line, sizeof line); ! 261: # endif LOG_IPC ! 262: if (i < 0) ! 263: { ! 264: if (errno == EINTR) ! 265: continue; ! 266: logerror("read"); ! 267: errct++; ! 268: if (errct > 1000) ! 269: { ! 270: logmsg(LOG_SALERT, "syslog: too many errors"); ! 271: die(); ! 272: } ! 273: sleep(15); ! 274: continue; ! 275: } ! 276: # ifdef LOG_IPC ! 277: line[i] = '\0'; ! 278: hp = gethostbyaddr(&SyslogAddr.sin_addr, ! 279: sizeof (SyslogAddr.sin_addr), AF_INET); ! 280: if (hp == 0) ! 281: printline(line, inet_ntoa(SyslogAddr.sin_addr)); ! 282: else ! 283: printline(line, hp->h_name); ! 284: # else LOG_IPC ! 285: crack(line, i); ! 286: # endif LOG_IPC ! 287: } ! 288: } ! 289: /* ! 290: ** LOGERROR -- log an error on the log. ! 291: ** ! 292: ** Parameters: ! 293: ** type -- string to print as error type. ! 294: ** ! 295: ** Returns: ! 296: ** none. ! 297: ** ! 298: ** Side Effects: ! 299: ** outputs the error code in errno to someplace. ! 300: */ ! 301: ! 302: logerror(type) ! 303: char *type; ! 304: { ! 305: char buf[50]; ! 306: extern int errno; ! 307: ! 308: sprintf(buf, "log %s error %d\n", type, errno); ! 309: errno = 0; ! 310: logmsg(LOG_SALERT, buf); ! 311: } ! 312: ! 313: # ifndef LOG_IPC ! 314: ! 315: /* ! 316: ** CRACK -- parse & handle a log line ! 317: ** ! 318: ** Parameters: ! 319: ** rec -- the input record. ! 320: ** bc -- the byte count for rec. ! 321: ** ! 322: ** Returns: ! 323: ** nothing ! 324: ** ! 325: ** Side Effects: ! 326: ** rec is output. ! 327: */ ! 328: ! 329: # define skip(rec, n) ((struct rh *) (((char *) rec) + n)) ! 330: ! 331: crack(rec, bc) ! 332: register struct rh *rec; ! 333: int bc; ! 334: { ! 335: struct rh *endrec; ! 336: ! 337: endrec = skip(rec, bc); ! 338: ! 339: while (rec < endrec) ! 340: { ! 341: if (rec->count == 0) ! 342: { ! 343: /* control record from mpx file */ ! 344: dprintf("%d byte control message\n", rec->ccount); ! 345: control(rec); ! 346: } ! 347: else ! 348: { ! 349: /* data record -- process message */ ! 350: messg(rec); ! 351: } ! 352: rec->count += rec->ccount; ! 353: if (rec->count & 01) ! 354: rec->count++; ! 355: rec = skip(rec, rec->count + sizeof *rec); ! 356: } ! 357: } ! 358: /* ! 359: ** CONTROL -- handle mpx control messages. ! 360: ** ! 361: ** Parameters: ! 362: ** rec -- control message. ! 363: ** ! 364: ** Returns: ! 365: ** none. ! 366: ** ! 367: ** Side Effects: ! 368: ** as necessary for that control message. ! 369: */ ! 370: ! 371: short NoIoctl[] = { M_IOANS }; ! 372: ! 373: control(rec) ! 374: register struct rh *rec; ! 375: { ! 376: register int cmd; ! 377: register short val; ! 378: register short *ap; ! 379: # ifdef MPXDEBUG ! 380: char dbbuf[100]; ! 381: # endif MPXDEBUG ! 382: ! 383: ap = (short *) (((char *) rec) + sizeof *rec); ! 384: cmd = *ap++ & 0377; ! 385: val = *ap++; ! 386: # ifdef MPXDEBUG ! 387: sprintf(dbbuf, "syslog: ctl ch=%x cmd=%d val=%d", rec->index, cmd, val); ! 388: logmsg(LOG_DEBUG, dbbuf); ! 389: # endif MPXDEBUG ! 390: ! 391: switch (cmd) ! 392: { ! 393: case M_WATCH: /* attempted connect; value is uid */ ! 394: dprintf("WATCH, uid=%d\n", val); ! 395: attach(rec->index, LogFile); ! 396: break; ! 397: ! 398: case M_CLOSE: /* close channel; value is unused */ ! 399: dprintf("CLOSE, val=%d\n", val); ! 400: detach(rec->index, LogFile); ! 401: break; ! 402: ! 403: case M_IOCTL: ! 404: dprintf("IOCTL, val=%d\n", val); ! 405: wmpxctl(rec->index, NoIoctl, sizeof NoIoctl); ! 406: break; ! 407: ! 408: default: ! 409: dprintf("unknown cmd %d, val=%d\n", cmd, val); ! 410: break; ! 411: } ! 412: } ! 413: /* ! 414: ** WMPXCTL -- write mpx control message ! 415: ** ! 416: ** Parameters: ! 417: ** index -- index to write to. ! 418: ** buf -- place to write. ! 419: ** len -- length to write. ! 420: ** ! 421: ** Returns: ! 422: ** none. ! 423: ** ! 424: ** Side Effects: ! 425: ** writes to LogFile. ! 426: */ ! 427: ! 428: wmpxctl(index, buf, cnt) ! 429: int index; ! 430: char *buf; ! 431: int cnt; ! 432: { ! 433: struct wh wbuf; ! 434: ! 435: wbuf.index = index; ! 436: wbuf.count = 0; ! 437: wbuf.ccount = cnt; ! 438: wbuf.data = buf; ! 439: write(LogFile, &wbuf, sizeof wbuf); ! 440: } ! 441: /* ! 442: ** MESSG -- log message ! 443: ** ! 444: ** Parameters: ! 445: ** rec -- record of data. ! 446: ** ! 447: ** Returns: ! 448: ** nothing. ! 449: ** ! 450: ** Side Effects: ! 451: ** sends the record to the system log. ! 452: */ ! 453: ! 454: messg(rec) ! 455: register struct rh *rec; ! 456: { ! 457: char endchar; ! 458: char *endptr; ! 459: register char *q; ! 460: ! 461: q = (char *) rec + sizeof *rec; ! 462: endptr = &q[rec->count]; ! 463: endchar = *endptr; ! 464: *endptr = '\0'; ! 465: printline(q, NULL); ! 466: *endptr = endchar; ! 467: } ! 468: ! 469: # endif LOG_IPC ! 470: /* ! 471: ** PRINTLINE -- print one line ! 472: ** ! 473: ** This is really it -- we have one line -- we crack it and ! 474: ** and print it appropriately. ! 475: ** ! 476: ** Parameters: ! 477: ** q -- pointer to the line. ! 478: ** tag -- the name of the host this is from. ! 479: ** ! 480: ** Returns: ! 481: ** none. ! 482: ** ! 483: ** Side Effects: ! 484: ** q is broken up and printed. ! 485: */ ! 486: ! 487: printline(q, tag) ! 488: register char *q; ! 489: { ! 490: register int i; ! 491: static int pri; ! 492: register char *p; ! 493: static char buf[1000]; ! 494: static char *bp = buf; ! 495: ! 496: dprintf("message = ``%s''\n", q); ! 497: while (*q != '\0') ! 498: { ! 499: if (bp == buf) ! 500: { ! 501: # if LOGHOSTNAME > 0 ! 502: if (tag != NULL) ! 503: { ! 504: strcpy(bp, tag); ! 505: strcat(bp, ": "); ! 506: bp += strlen(bp); ! 507: } ! 508: # endif LOGHOSTNAME ! 509: ! 510: /* test for special codes */ ! 511: pri = DefPri; ! 512: if (q[0] == '<' && q[2] == '>') ! 513: { ! 514: switch (q[1]) ! 515: { ! 516: case '*': /* reset default message priority */ ! 517: dprintf("default priority = %c\n", q[3]); ! 518: i = q[3] - '0'; ! 519: if (i > 0 && i <= 9) ! 520: DefPri = i; ! 521: continue; ! 522: ! 523: case '$': /* reconfigure */ ! 524: dprintf("reconfigure\n"); ! 525: init(); ! 526: continue; ! 527: } ! 528: q++; ! 529: pri = *q++ - '0'; ! 530: q++; ! 531: if (pri < 0 || pri > 9) ! 532: pri = DefPri; ! 533: } ! 534: else ! 535: pri = DefPri; ! 536: } ! 537: while (*q != '\0' && *q != '\n') ! 538: { ! 539: if (*q != '\r') ! 540: *bp++ = *q; ! 541: q++; ! 542: } ! 543: if (*q == '\0') ! 544: continue; ! 545: *bp++ = '\0'; ! 546: q++; ! 547: bp = buf; ! 548: ! 549: /* output the line to all files */ ! 550: logmsg(pri, bp); ! 551: bp = buf; ! 552: } ! 553: } ! 554: /* ! 555: ** SHUTDOWN -- shutdown the logger ! 556: ** ! 557: ** This should only be done when the system is going down. ! 558: ** ! 559: ** Parameters: ! 560: ** none ! 561: ** ! 562: ** Returns: ! 563: ** none ! 564: ** ! 565: ** Side Effects: ! 566: ** Starts up an alarm clock, to let other things ! 567: ** happen. Alarm clock will call "die". ! 568: ** ! 569: ** Called By: ! 570: ** main ! 571: ** signal 15 (terminate) ! 572: */ ! 573: ! 574: shutdown() ! 575: { ! 576: extern die(); ! 577: ! 578: logmsg(LOG_CRIT, "syslog: shutdown within 30 seconds\n"); ! 579: ShutDown++; ! 580: signal(SIGALRM, die); ! 581: alarm(30); ! 582: signal(SIGTERM, die); ! 583: if (Debug) ! 584: signal(SIGINT, die); ! 585: } ! 586: /* ! 587: ** DIE -- really die. ! 588: ** ! 589: ** Parameters: ! 590: ** none ! 591: ** ! 592: ** Returns: ! 593: ** never ! 594: ** ! 595: ** Side Effects: ! 596: ** Syslog dies. ! 597: ** ! 598: ** Requires: ! 599: ** exit (sys) ! 600: ** ! 601: ** Called By: ! 602: ** alarm clock (signal 14) ! 603: */ ! 604: ! 605: die() ! 606: { ! 607: alarm(0); ! 608: logmsg(LOG_CRIT, "syslog: down\n"); ! 609: sleep(2); /* wait for output to drain */ ! 610: # ifndef LOG_IPC ! 611: if (!Debug) ! 612: unlink("/dev/log"); ! 613: # endif LOG_IPC ! 614: sync(); ! 615: exit(0); ! 616: } ! 617: /* ! 618: ** STAMPED -- tell if line is already time stamped. ! 619: ** ! 620: ** Accepts time stamps of the form "Sep 13 00:15:17". ! 621: ** Currently just looks for blanks and colons. ! 622: ** ! 623: ** Parameters: ! 624: ** l -- the line to check. ! 625: ** ! 626: ** Returns: ! 627: ** nonzero -- if the line is time stamped. ! 628: ** zero -- otherwise. ! 629: ** ! 630: ** Side Effects: ! 631: ** none. ! 632: */ ! 633: ! 634: stamped(l) ! 635: register char *l; ! 636: { ! 637: register int i; ! 638: ! 639: /* timestamps are at least 15 bytes long */ ! 640: for (i = 0; i < 15; i++) ! 641: if (l[i] == '\0') ! 642: return (0); ! 643: ! 644: /* and they have blanks & colons in well-known places */ ! 645: if (l[3] != ' ' || l[6] != ' ' || l[9] != ':' || l[12] != ':') ! 646: return (0); ! 647: return (1); ! 648: } ! 649: /* ! 650: ** LOGMSG -- log a message to the outputs ! 651: ** ! 652: ** Arranges to get the message to the correct places ! 653: ** based on the priority of the message. A timestamp ! 654: ** is prepended to the message if one does not already ! 655: ** exist. ! 656: ** ! 657: ** Parameters: ! 658: ** pri -- the message priority. ! 659: ** msg -- the message to be logged. ! 660: ** ! 661: ** Returns: ! 662: ** none ! 663: ** ! 664: ** Side Effects: ! 665: ** possibly messages to all users, or just specific ! 666: ** users. ! 667: */ ! 668: ! 669: logmsg(pri, msg) ! 670: int pri; ! 671: char *msg; ! 672: { ! 673: register char *m; ! 674: register char *p; ! 675: register struct filed *f; ! 676: register int l; ! 677: register int i; ! 678: char buf[MAXLINE+2]; ! 679: auto int st; ! 680: auto long now; ! 681: extern char *ctime(); ! 682: extern int errno; ! 683: ! 684: p = buf; ! 685: l = MAXLINE; ! 686: ! 687: /* output a time stamp if one is not already there */ ! 688: time(&now); ! 689: if (!stamped(msg)) ! 690: { ! 691: m = &ctime(&now)[4]; ! 692: for (i = 16; i > 0; i--) ! 693: *p++ = *m++; ! 694: l -= 16; ! 695: } ! 696: ! 697: /* find the end of the message */ ! 698: for (m = msg; *m != '\0' &&l -- >= 0; ) ! 699: *p++ = *m++; ! 700: if (*--m != '\n') ! 701: *p++ = '\n'; ! 702: ! 703: /* log the message to the particular outputs */ ! 704: for (i = 0; i < NLOGS; i++) ! 705: { ! 706: f = &Files[i]; ! 707: if (f->f_file == NULL) ! 708: continue; ! 709: if (pri < 0) ! 710: { ! 711: if (!f->f_mark || f->f_time + MarkIntvl*60 > now) ! 712: continue; ! 713: } ! 714: else if (f->f_pmask < pri) ! 715: continue; ! 716: fseek(f->f_file, 0L, 2); ! 717: errno = 0; ! 718: fwrite(buf, p - buf, 1, f->f_file); ! 719: if (f->f_tty) ! 720: fwrite("\r", 1, 1, f->f_file); ! 721: f->f_time = now; ! 722: fflush(f->f_file); ! 723: if (ferror(f->f_file)) ! 724: { ! 725: char namebuf[40]; ! 726: ! 727: fclose(f->f_file); ! 728: f->f_file = NULL; ! 729: sprintf(namebuf, "write %s", f->f_name); ! 730: logerror(namebuf); ! 731: } ! 732: } ! 733: ! 734: /* let's be paranoid.... */ ! 735: sync(); ! 736: ! 737: /* ! 738: ** Output alert and subalert priority messages to terminals. ! 739: ** ! 740: ** We double fork here so that we can continue. Our ! 741: ** child will fork again and die; we wait for him. ! 742: ** Then process one inherits our grandchildren, we ! 743: ** can run off and have a good time. Our grandchild ! 744: ** actually tries to do the writing (by calling ! 745: ** wallmsg). ! 746: ** ! 747: ** Anything go wrong? -- just give up. ! 748: */ ! 749: ! 750: if (pri <= LOG_SALERT && pri > 0) ! 751: { ! 752: if (fork() == 0) ! 753: { ! 754: if (fork() == 0) ! 755: { ! 756: wallmsg(pri == LOG_ALERT, buf, p - buf); ! 757: exit(0); ! 758: } ! 759: else ! 760: exit(0); ! 761: } ! 762: else ! 763: while (wait(&st) >= 0) ! 764: continue; ! 765: } ! 766: } ! 767: /* ! 768: ** INIT -- Initialize syslog from configuration table ! 769: ** ! 770: ** The configuration table consists of a series of lines ! 771: ** broken into two sections by a blank line. The first ! 772: ** section gives a list of files to log on. The first ! 773: ** character is a digit which is the priority mask for ! 774: ** that file. If the second digit is an asterisk, then ! 775: ** syslog arranges for something to be printed every fifteen ! 776: ** minutes (even if only a null line), so that crashes and ! 777: ** other events can be localized. The rest of the line is ! 778: ** the pathname of the log file. The second section is ! 779: ** a list of user names; these people are all notified ! 780: ** when subalert messages occur (if they are logged on). ! 781: ** ! 782: ** The configuration table will be reread by this routine ! 783: ** if a signal 1 occurs; for that reason, it is tricky ! 784: ** about not re-opening files and closing files it will ! 785: ** not be using. ! 786: ** ! 787: ** Parameters: ! 788: ** none ! 789: ** ! 790: ** Returns: ! 791: ** none ! 792: ** ! 793: ** Side Effects: ! 794: ** 'Files' and 'Susers' are (re)initialized. ! 795: */ ! 796: ! 797: init() ! 798: { ! 799: register int i; ! 800: register FILE *cf; ! 801: char cline[40]; ! 802: register struct filed *f; ! 803: register char *p; ! 804: int mark; ! 805: int pmask; ! 806: ! 807: dprintf("init\n"); ! 808: ! 809: /* ignore interrupts during this routine */ ! 810: signal(SIGHUP, SIG_IGN); ! 811: logmsg(LOG_INFO, "reinitializing\n"); ! 812: ! 813: /* open the configuration file */ ! 814: if ((cf = fopen(ConfFile, "r")) == NULL) ! 815: { ! 816: dprintf("cannot open %s\n", ConfFile); ! 817: return; ! 818: } ! 819: ! 820: /* ! 821: ** Close all open files. ! 822: */ ! 823: ! 824: for (f = Files; f < &Files[NLOGS]; f++) ! 825: { ! 826: if (f->f_file != NULL) ! 827: fclose(f->f_file); ! 828: f->f_file = NULL; ! 829: } ! 830: ! 831: /* ! 832: ** Foreach line in the conf table, open that file. ! 833: */ ! 834: ! 835: f = Files; ! 836: while (fgets(cline, sizeof cline, cf) != NULL) ! 837: { ! 838: dprintf("F: got line >%s<\n", cline, 0); ! 839: /* check for end-of-section */ ! 840: if (cline[0] == '\n') ! 841: break; ! 842: ! 843: /* strip off possible newline character */ ! 844: for (p = cline; *p != '\0' && *p != '\n'; p++) ! 845: continue; ! 846: *p = '\0'; ! 847: ! 848: /* extract priority mask and mark flag */ ! 849: p = cline; ! 850: mark = FALSE; ! 851: pmask = *p++ - '0'; ! 852: if (*p == '*') ! 853: { ! 854: p++; ! 855: mark = TRUE; ! 856: } ! 857: ! 858: /* insure that it is null-terminated */ ! 859: p[sizeof Files[0].f_name - 1] = '\0'; ! 860: ! 861: if (f >= &Files[NLOGS]) ! 862: continue; ! 863: ! 864: /* mark entry as used and update flags */ ! 865: strcpy(f->f_name, p); ! 866: f->f_file = fopen(p, "a"); ! 867: f->f_time = 0; ! 868: f->f_pmask = pmask; ! 869: f->f_mark = mark; ! 870: f->f_tty = isatty(fileno(f->f_file)); ! 871: dprintf("File %s pmask %d mark %d tty %d\n", p, pmask, mark, f->f_tty); ! 872: f++; ! 873: } ! 874: ! 875: /* ! 876: ** Read the list of users. ! 877: ** ! 878: ** Anyone in this list is informed directly if s/he ! 879: ** is logged in when a "subalert" or higher priority ! 880: ** message comes through. ! 881: ** ! 882: ** Out with the old order, in with the new. ! 883: */ ! 884: ! 885: for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) ! 886: { ! 887: /* strip off newline */ ! 888: for (p = cline; *p != '\0' && *p != '\n'; p++) ! 889: continue; ! 890: *p = '\0'; ! 891: cline[8] = '\0'; ! 892: strcpy(Susers[i], cline, 8); ! 893: } ! 894: ! 895: /* zero the rest of the old superusers */ ! 896: for (; i < NSUSERS; i++) ! 897: Susers[i][0] = '\0'; ! 898: ! 899: /* close the configuration file */ ! 900: fclose(cf); ! 901: ! 902: logmsg(LOG_INFO, "syslog restart\n"); ! 903: ! 904: /* arrange for signal 1 to reconfigure */ ! 905: signal(SIGHUP, init); ! 906: } ! 907: /* ! 908: ** WALLMSG -- Write a message to the world at large ! 909: ** ! 910: ** This writes the specified message to either the entire ! 911: ** world, or at least a list of approved users. ! 912: ** ! 913: ** It scans the utmp file. For each user logged in, it ! 914: ** checks to see if the user is on the approved list, or if ! 915: ** this is an "alert" priority message. In either case, ! 916: ** it opens a line to that typewriter (unless mesg permission ! 917: ** is denied) and outputs the message to that terminal. ! 918: ** ! 919: ** Parameters: ! 920: ** toall -- if non-zero, writes the message to everyone. ! 921: ** msg -- the message to write. ! 922: ** len -- the length of the message. ! 923: ** ! 924: ** Returns: ! 925: ** none ! 926: ** ! 927: ** Side Effects: ! 928: ** none ! 929: ** ! 930: ** Requires: ! 931: ** open(sys) ! 932: ** read(sys) ! 933: ** write(sys) ! 934: ** fstat(sys) ! 935: ** strcmp(sys) ! 936: ** fork(sys) ! 937: ** sleep(sys) ! 938: ** exit(sys) ! 939: ** close(sys) ! 940: ** ! 941: ** Called By: ! 942: ** logmsg ! 943: */ ! 944: ! 945: wallmsg(toall, msg, len) ! 946: int toall; ! 947: char *msg; ! 948: int len; ! 949: { ! 950: struct utmp ut; ! 951: register int i; ! 952: register char *p; ! 953: int uf; ! 954: struct stat statbuf; ! 955: auto long t; ! 956: extern char *ctime(); ! 957: char sbuf[1024]; ! 958: #ifdef LOG_IPC ! 959: extern char *gethostname(); ! 960: char hbuf[32]; ! 961: auto int hlen; ! 962: #endif LOG_IPC ! 963: ! 964: /* open the user login file */ ! 965: uf = open("/etc/utmp", 0); ! 966: if (uf < 0) ! 967: return; ! 968: ! 969: /* scan the user login file */ ! 970: while (read(uf, &ut, sizeof ut) == sizeof ut) ! 971: { ! 972: /* is this slot used? */ ! 973: if (ut.ut_name[0] == '\0') ! 974: continue; ! 975: ! 976: /* if not "alert", check if this user is super */ ! 977: if (!toall) ! 978: { ! 979: for (i = 0; i < NSUSERS; i++) ! 980: { ! 981: if (namecheck(Susers[i], ut.ut_name)) ! 982: break; ! 983: } ! 984: if (i >= NSUSERS) ! 985: { ! 986: /* nope, just a serf */ ! 987: continue; ! 988: } ! 989: } ! 990: ! 991: /* fork so that the open can't hang us */ ! 992: if (fork() != 0) ! 993: continue; ! 994: sleep(1); ! 995: ! 996: /* compute the device name */ ! 997: # ifdef V6 ! 998: p = "/dev/ttyx"; ! 999: p[8] = ut.ut_tty; ! 1000: # else ! 1001: p = "/dev/12345678"; ! 1002: strcpyn(&p[5], ut.ut_line, 8); ! 1003: # endif ! 1004: ! 1005: /* open the terminal */ ! 1006: i = open(p, 1); ! 1007: if (i < 0) ! 1008: exit(1); ! 1009: ! 1010: /* does he have write permission? */ ! 1011: if (fstat(i, &statbuf) < 0 || (statbuf.st_mode & 02) == 0) ! 1012: { ! 1013: /* no, just pass him by */ ! 1014: dprintf("Drop user, mode=%o\n", statbuf.st_mode, 0); ! 1015: close(i); ! 1016: exit(0); ! 1017: } ! 1018: ! 1019: /* yes, output the message */ ! 1020: time(&t); ! 1021: strcpy(sbuf, "\r\n\007Broadcast message from "); ! 1022: #ifdef LOG_IPC ! 1023: strcat(sbuf, "syslog@"); ! 1024: hlen = sizeof hbuf; ! 1025: gethostname(hbuf, &hlen); ! 1026: strcat(sbuf, hbuf); ! 1027: #else LOG_IPC ! 1028: strcat(sbuf, sysname); ! 1029: strcat(sbuf, "!syslog"); ! 1030: #endif LOG_IPC ! 1031: strcat(sbuf, " at "); ! 1032: strncat(sbuf, ctime(&t), 24); ! 1033: strcat(sbuf, "...\r\n"); ! 1034: write(i, sbuf, strlen(sbuf)); ! 1035: p = sbuf; ! 1036: while (len-- > 0) ! 1037: { ! 1038: *msg &= 0177; ! 1039: if (iscntrl(*msg)) ! 1040: { ! 1041: *p++ = '^'; ! 1042: *p++ = *msg++ ^ 0100; ! 1043: } ! 1044: else ! 1045: *p++ = *msg++; ! 1046: } ! 1047: strcpy(p, "\r\n"); ! 1048: write(i, sbuf, strlen(sbuf)); ! 1049: ! 1050: /* all finished! go away */ ! 1051: exit(0); ! 1052: } ! 1053: ! 1054: /* close the user login file */ ! 1055: close(uf); ! 1056: } ! 1057: /* ! 1058: ** CHECKNAME -- Do an equality comparison on names. ! 1059: ** ! 1060: ** Does right blank padding. ! 1061: ** ! 1062: ** Parameters: ! 1063: ** a, b -- pointers to the names to check. ! 1064: ** ! 1065: ** Returns: ! 1066: ** 1 if equal ! 1067: ** 0 otherwise. ! 1068: ** ! 1069: ** Side Effects: ! 1070: ** none ! 1071: ** ! 1072: ** Requires: ! 1073: ** none ! 1074: ** ! 1075: ** Called By: ! 1076: ** wallmsg ! 1077: */ ! 1078: ! 1079: namecheck(a, b) ! 1080: register char *a, *b; ! 1081: { ! 1082: register int i; ! 1083: ! 1084: for (i = 0; i < 8; i++) ! 1085: { ! 1086: if (*a != *b) ! 1087: { ! 1088: if (!((*a == ' ' && *b == '\0') || (*a == '\0' && *b == ' '))) ! 1089: return (0); ! 1090: } ! 1091: if (*a != ' ' && *a != '\0') ! 1092: a++; ! 1093: if (*b != ' ' && *b != '\0') ! 1094: b++; ! 1095: } ! 1096: return (1); ! 1097: } ! 1098: /* ! 1099: ** DOMARK -- Make sure every marked file gets output every 15 minutes ! 1100: ** ! 1101: ** Just calls "logmsg" with a negative priority every time it ! 1102: ** gets called. ! 1103: ** ! 1104: ** Algorithm: ! 1105: ** create timestamp. ! 1106: ** call logmsg. ! 1107: ** ! 1108: ** Parameters: ! 1109: ** none ! 1110: ** ! 1111: ** Returns: ! 1112: ** none ! 1113: ** ! 1114: ** Side Effects: ! 1115: ** sets the alarm clock to call itself after MarkIntvl ! 1116: ** minutes. ! 1117: ** ! 1118: ** Requires: ! 1119: ** logmsg ! 1120: ** ! 1121: ** Called By: ! 1122: ** system alarm clock. ! 1123: ** init ! 1124: */ ! 1125: ! 1126: domark() ! 1127: { ! 1128: auto long t; ! 1129: extern char *ctime(); ! 1130: register char *p; ! 1131: register char *q; ! 1132: char buf[40]; ! 1133: ! 1134: alarm(0); ! 1135: dprintf("domark\n"); ! 1136: time(&t); ! 1137: q = buf; ! 1138: for (p = " --- MARK --- "; (*q++ = *p++) != '\0'; ) ! 1139: continue; ! 1140: q--; ! 1141: for (p = ctime(&t); (*q++ = *p++) != '\0'; ) ! 1142: continue; ! 1143: logmsg(-1, buf); ! 1144: signal(SIGALRM, domark); ! 1145: alarm(MarkIntvl*60); ! 1146: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.