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

Defined functions

control defined in line 373; used 1 times
crack defined in line 331; used 1 times
die defined in line 605; used 5 times
domark defined in line 1124; used 3 times
init defined in line 797; used 3 times
logerror defined in line 302; used 2 times
logmsg defined in line 669; used 11 times
main defined in line 108; never used
messg defined in line 454; used 1 times
namecheck defined in line 1077; used 1 times
printline defined in line 487; used 3 times
shutdown defined in line 574; used 3 times
stamped defined in line 634; used 1 times
wallmsg defined in line 945; used 1 times
wmpxctl defined in line 428; used 1 times

Defined variables

ConfFile defined in line 97; used 8 times
Debug defined in line 94; used 8 times
DefPri defined in line 93; used 4 times
Files defined in line 87; used 6 times
LogFile defined in line 95; used 14 times
MarkIntvl defined in line 96; used 6 times
NoIoctl defined in line 371; used 2 times
  • in line 405(2)
SccsId defined in line 68; never used
ShutDown defined in line 92; used 1 times
Susers defined in line 90; used 3 times
SyslogAddr defined in line 103; used 13 times
SyslogProto defined in line 104; used 1 times

Defined struct's

filed defined in line 77; used 6 times

Defined typedef's

bool defined in line 58; used 2 times

Defined macros

FALSE defined in line 60; used 1 times
LOGHOSTNAME defined in line 35; used 1 times
MAXLINE defined in line 33; used 2 times
NLOGS defined in line 31; used 4 times
NSUSERS defined in line 32; used 5 times
TRUE defined in line 59; used 1 times
UNAMESZ defined in line 70; used 1 times
  • in line 90
dprintf defined in line 65; used 16 times
skip defined in line 329; used 2 times
Last modified: 1984-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2158
Valid CSS Valid XHTML 1.0 Strict