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: #endif LOG_IPC 962: 963: /* open the user login file */ 964: uf = open("/etc/utmp", 0); 965: if (uf < 0) 966: return; 967: 968: /* scan the user login file */ 969: while (read(uf, &ut, sizeof ut) == sizeof ut) 970: { 971: /* is this slot used? */ 972: if (ut.ut_name[0] == '\0') 973: continue; 974: 975: /* if not "alert", check if this user is super */ 976: if (!toall) 977: { 978: for (i = 0; i < NSUSERS; i++) 979: { 980: if (namecheck(Susers[i], ut.ut_name)) 981: break; 982: } 983: if (i >= NSUSERS) 984: { 985: /* nope, just a serf */ 986: continue; 987: } 988: } 989: 990: /* fork so that the open can't hang us */ 991: if (fork() != 0) 992: continue; 993: sleep(1); 994: 995: /* compute the device name */ 996: # ifdef V6 997: p = "/dev/ttyx"; 998: p[8] = ut.ut_tty; 999: # else 1000: p = "/dev/12345678"; 1001: strcpyn(&p[5], ut.ut_line, 8); 1002: # endif 1003: 1004: /* open the terminal */ 1005: i = open(p, 1); 1006: if (i < 0) 1007: exit(1); 1008: 1009: /* does he have write permission? */ 1010: if (fstat(i, &statbuf) < 0 || (statbuf.st_mode & 02) == 0) 1011: { 1012: /* no, just pass him by */ 1013: dprintf("Drop user, mode=%o\n", statbuf.st_mode, 0); 1014: close(i); 1015: exit(0); 1016: } 1017: 1018: /* yes, output the message */ 1019: time(&t); 1020: strcpy(sbuf, "\r\n\007Broadcast message from "); 1021: #ifdef LOG_IPC 1022: strcat(sbuf, "syslog@"); 1023: gethostname(hbuf, sizeof hbuf); 1024: strcat(sbuf, hbuf); 1025: #else LOG_IPC 1026: strcat(sbuf, sysname); 1027: strcat(sbuf, "!syslog"); 1028: #endif LOG_IPC 1029: strcat(sbuf, " at "); 1030: strncat(sbuf, ctime(&t), 24); 1031: strcat(sbuf, "...\r\n"); 1032: write(i, sbuf, strlen(sbuf)); 1033: p = sbuf; 1034: while (len-- > 0) 1035: { 1036: *msg &= 0177; 1037: if (iscntrl(*msg)) 1038: { 1039: *p++ = '^'; 1040: *p++ = *msg++ ^ 0100; 1041: } 1042: else 1043: *p++ = *msg++; 1044: } 1045: strcpy(p, "\r\n"); 1046: write(i, sbuf, strlen(sbuf)); 1047: 1048: /* all finished! go away */ 1049: exit(0); 1050: } 1051: 1052: /* close the user login file */ 1053: close(uf); 1054: } 1055: /* 1056: ** CHECKNAME -- Do an equality comparison on names. 1057: ** 1058: ** Does right blank padding. 1059: ** 1060: ** Parameters: 1061: ** a, b -- pointers to the names to check. 1062: ** 1063: ** Returns: 1064: ** 1 if equal 1065: ** 0 otherwise. 1066: ** 1067: ** Side Effects: 1068: ** none 1069: ** 1070: ** Requires: 1071: ** none 1072: ** 1073: ** Called By: 1074: ** wallmsg 1075: */ 1076: 1077: namecheck(a, b) 1078: register char *a, *b; 1079: { 1080: register int i; 1081: 1082: for (i = 0; i < 8; i++) 1083: { 1084: if (*a != *b) 1085: { 1086: if (!((*a == ' ' && *b == '\0') || (*a == '\0' && *b == ' '))) 1087: return (0); 1088: } 1089: if (*a != ' ' && *a != '\0') 1090: a++; 1091: if (*b != ' ' && *b != '\0') 1092: b++; 1093: } 1094: return (1); 1095: } 1096: /* 1097: ** DOMARK -- Make sure every marked file gets output every 15 minutes 1098: ** 1099: ** Just calls "logmsg" with a negative priority every time it 1100: ** gets called. 1101: ** 1102: ** Algorithm: 1103: ** create timestamp. 1104: ** call logmsg. 1105: ** 1106: ** Parameters: 1107: ** none 1108: ** 1109: ** Returns: 1110: ** none 1111: ** 1112: ** Side Effects: 1113: ** sets the alarm clock to call itself after MarkIntvl 1114: ** minutes. 1115: ** 1116: ** Requires: 1117: ** logmsg 1118: ** 1119: ** Called By: 1120: ** system alarm clock. 1121: ** init 1122: */ 1123: 1124: domark() 1125: { 1126: auto long t; 1127: extern char *ctime(); 1128: register char *p; 1129: register char *q; 1130: char buf[40]; 1131: 1132: alarm(0); 1133: dprintf("domark\n"); 1134: time(&t); 1135: q = buf; 1136: for (p = " --- MARK --- "; (*q++ = *p++) != '\0'; ) 1137: continue; 1138: q--; 1139: for (p = ctime(&t); (*q++ = *p++) != '\0'; ) 1140: continue; 1141: logmsg(-1, buf); 1142: signal(SIGALRM, domark); 1143: alarm(MarkIntvl*60); 1144: }