|
|
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.