|
|
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 1024 /* 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: fsync(f->f_file);
724: if (ferror(f->f_file))
725: {
726: char namebuf[40];
727:
728: fclose(f->f_file);
729: f->f_file = NULL;
730: sprintf(namebuf, "write %s", f->f_name);
731: logerror(namebuf);
732: }
733: }
734:
735: /*
736: ** Output alert and subalert priority messages to terminals.
737: **
738: ** We double fork here so that we can continue. Our
739: ** child will fork again and die; we wait for him.
740: ** Then process one inherits our grandchildren, we
741: ** can run off and have a good time. Our grandchild
742: ** actually tries to do the writing (by calling
743: ** wallmsg).
744: **
745: ** Anything go wrong? -- just give up.
746: */
747:
748: if (pri <= LOG_SALERT && pri > 0)
749: {
750: if (fork() == 0)
751: {
752: if (fork() == 0)
753: {
754: wallmsg(pri == LOG_ALERT, buf, p - buf);
755: exit(0);
756: }
757: else
758: exit(0);
759: }
760: else
761: while (wait(&st) >= 0)
762: continue;
763: }
764: }
765: /*
766: ** INIT -- Initialize syslog from configuration table
767: **
768: ** The configuration table consists of a series of lines
769: ** broken into two sections by a blank line. The first
770: ** section gives a list of files to log on. The first
771: ** character is a digit which is the priority mask for
772: ** that file. If the second digit is an asterisk, then
773: ** syslog arranges for something to be printed every fifteen
774: ** minutes (even if only a null line), so that crashes and
775: ** other events can be localized. The rest of the line is
776: ** the pathname of the log file. The second section is
777: ** a list of user names; these people are all notified
778: ** when subalert messages occur (if they are logged on).
779: **
780: ** The configuration table will be reread by this routine
781: ** if a signal 1 occurs; for that reason, it is tricky
782: ** about not re-opening files and closing files it will
783: ** not be using.
784: **
785: ** Parameters:
786: ** none
787: **
788: ** Returns:
789: ** none
790: **
791: ** Side Effects:
792: ** 'Files' and 'Susers' are (re)initialized.
793: */
794:
795: init()
796: {
797: register int i;
798: register FILE *cf;
799: char cline[40];
800: register struct filed *f;
801: register char *p;
802: int mark;
803: int pmask;
804:
805: dprintf("init\n");
806:
807: /* ignore interrupts during this routine */
808: signal(SIGHUP, SIG_IGN);
809: logmsg(LOG_INFO, "reinitializing\n");
810:
811: /* open the configuration file */
812: if ((cf = fopen(ConfFile, "r")) == NULL)
813: {
814: dprintf("cannot open %s\n", ConfFile);
815: return;
816: }
817:
818: /*
819: ** Close all open files.
820: */
821:
822: for (f = Files; f < &Files[NLOGS]; f++)
823: {
824: if (f->f_file != NULL)
825: fclose(f->f_file);
826: f->f_file = NULL;
827: }
828:
829: /*
830: ** Foreach line in the conf table, open that file.
831: */
832:
833: f = Files;
834: while (fgets(cline, sizeof cline, cf) != NULL)
835: {
836: dprintf("F: got line >%s<\n", cline, 0);
837: /* check for end-of-section */
838: if (cline[0] == '\n')
839: break;
840:
841: /* strip off possible newline character */
842: for (p = cline; *p != '\0' && *p != '\n'; p++)
843: continue;
844: *p = '\0';
845:
846: /* extract priority mask and mark flag */
847: p = cline;
848: mark = FALSE;
849: pmask = *p++ - '0';
850: if (*p == '*')
851: {
852: p++;
853: mark = TRUE;
854: }
855:
856: /* insure that it is null-terminated */
857: p[sizeof Files[0].f_name - 1] = '\0';
858:
859: if (f >= &Files[NLOGS])
860: continue;
861:
862: /* mark entry as used and update flags */
863: strcpy(f->f_name, p);
864: f->f_file = fopen(p, "a");
865: f->f_time = 0;
866: f->f_pmask = pmask;
867: f->f_mark = mark;
868: f->f_tty = isatty(fileno(f->f_file));
869: dprintf("File %s pmask %d mark %d tty %d\n", p, pmask, mark, f->f_tty);
870: f++;
871: }
872:
873: /*
874: ** Read the list of users.
875: **
876: ** Anyone in this list is informed directly if s/he
877: ** is logged in when a "subalert" or higher priority
878: ** message comes through.
879: **
880: ** Out with the old order, in with the new.
881: */
882:
883: for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++)
884: {
885: /* strip off newline */
886: for (p = cline; *p != '\0' && *p != '\n'; p++)
887: continue;
888: *p = '\0';
889: cline[8] = '\0';
890: strcpy(Susers[i], cline, 8);
891: }
892:
893: /* zero the rest of the old superusers */
894: for (; i < NSUSERS; i++)
895: Susers[i][0] = '\0';
896:
897: /* close the configuration file */
898: fclose(cf);
899:
900: logmsg(LOG_INFO, "syslog restart\n");
901:
902: /* arrange for signal 1 to reconfigure */
903: signal(SIGHUP, init);
904: }
905: /*
906: ** WALLMSG -- Write a message to the world at large
907: **
908: ** This writes the specified message to either the entire
909: ** world, or at least a list of approved users.
910: **
911: ** It scans the utmp file. For each user logged in, it
912: ** checks to see if the user is on the approved list, or if
913: ** this is an "alert" priority message. In either case,
914: ** it opens a line to that typewriter (unless mesg permission
915: ** is denied) and outputs the message to that terminal.
916: **
917: ** Parameters:
918: ** toall -- if non-zero, writes the message to everyone.
919: ** msg -- the message to write.
920: ** len -- the length of the message.
921: **
922: ** Returns:
923: ** none
924: **
925: ** Side Effects:
926: ** none
927: **
928: ** Requires:
929: ** open(sys)
930: ** read(sys)
931: ** write(sys)
932: ** fstat(sys)
933: ** strcmp(sys)
934: ** fork(sys)
935: ** sleep(sys)
936: ** exit(sys)
937: ** close(sys)
938: **
939: ** Called By:
940: ** logmsg
941: */
942:
943: wallmsg(toall, msg, len)
944: int toall;
945: char *msg;
946: int len;
947: {
948: struct utmp ut;
949: register int i;
950: register char *p;
951: int uf;
952: struct stat statbuf;
953: auto long t;
954: extern char *ctime();
955: char sbuf[1024];
956: #ifdef LOG_IPC
957: extern char *gethostname();
958: char hbuf[32];
959: #endif LOG_IPC
960:
961: /* open the user login file */
962: uf = open("/etc/utmp", 0);
963: if (uf < 0)
964: return;
965:
966: /* scan the user login file */
967: while (read(uf, &ut, sizeof ut) == sizeof ut)
968: {
969: /* is this slot used? */
970: if (ut.ut_name[0] == '\0')
971: continue;
972:
973: /* if not "alert", check if this user is super */
974: if (!toall)
975: {
976: for (i = 0; i < NSUSERS; i++)
977: {
978: if (namecheck(Susers[i], ut.ut_name))
979: break;
980: }
981: if (i >= NSUSERS)
982: {
983: /* nope, just a serf */
984: continue;
985: }
986: }
987:
988: /* fork so that the open can't hang us */
989: if (fork() != 0)
990: continue;
991: sleep(1);
992:
993: /* compute the device name */
994: # ifdef V6
995: p = "/dev/ttyx";
996: p[8] = ut.ut_tty;
997: # else
998: p = "/dev/12345678";
999: strncpy(&p[5], ut.ut_line, sizeof(ut.ut_line));
1000: # endif
1001:
1002: /* open the terminal */
1003: i = open(p, 1);
1004: if (i < 0)
1005: exit(1);
1006:
1007: /* does he have write permission? */
1008: if (fstat(i, &statbuf) < 0 || (statbuf.st_mode & 02) == 0)
1009: {
1010: /* no, just pass him by */
1011: dprintf("Drop user, mode=%o\n", statbuf.st_mode, 0);
1012: close(i);
1013: exit(0);
1014: }
1015:
1016: /* yes, output the message */
1017: time(&t);
1018: strcpy(sbuf, "\r\n\007Broadcast message from ");
1019: #ifdef LOG_IPC
1020: strcat(sbuf, "syslog@");
1021: gethostname(hbuf, sizeof hbuf);
1022: strcat(sbuf, hbuf);
1023: #else LOG_IPC
1024: strcat(sbuf, sysname);
1025: strcat(sbuf, "!syslog");
1026: #endif LOG_IPC
1027: strcat(sbuf, " at ");
1028: strncat(sbuf, ctime(&t), 24);
1029: strcat(sbuf, "...\r\n");
1030: write(i, sbuf, strlen(sbuf));
1031: p = sbuf;
1032: while (len-- > 0)
1033: {
1034: *msg &= 0177;
1035: if (iscntrl(*msg))
1036: {
1037: *p++ = '^';
1038: *p++ = *msg++ ^ 0100;
1039: }
1040: else
1041: *p++ = *msg++;
1042: }
1043: strcpy(p, "\r\n");
1044: write(i, sbuf, strlen(sbuf));
1045:
1046: /* all finished! go away */
1047: exit(0);
1048: }
1049:
1050: /* close the user login file */
1051: close(uf);
1052: }
1053: /*
1054: ** CHECKNAME -- Do an equality comparison on names.
1055: **
1056: ** Does right blank padding.
1057: **
1058: ** Parameters:
1059: ** a, b -- pointers to the names to check.
1060: **
1061: ** Returns:
1062: ** 1 if equal
1063: ** 0 otherwise.
1064: **
1065: ** Side Effects:
1066: ** none
1067: **
1068: ** Requires:
1069: ** none
1070: **
1071: ** Called By:
1072: ** wallmsg
1073: */
1074:
1075: namecheck(a, b)
1076: register char *a, *b;
1077: {
1078: register int i;
1079:
1080: for (i = 0; i < 8; i++)
1081: {
1082: if (*a != *b)
1083: {
1084: if (!((*a == ' ' && *b == '\0') || (*a == '\0' && *b == ' ')))
1085: return (0);
1086: }
1087: if (*a != ' ' && *a != '\0')
1088: a++;
1089: if (*b != ' ' && *b != '\0')
1090: b++;
1091: }
1092: return (1);
1093: }
1094: /*
1095: ** DOMARK -- Make sure every marked file gets output every 15 minutes
1096: **
1097: ** Just calls "logmsg" with a negative priority every time it
1098: ** gets called.
1099: **
1100: ** Algorithm:
1101: ** create timestamp.
1102: ** call logmsg.
1103: **
1104: ** Parameters:
1105: ** none
1106: **
1107: ** Returns:
1108: ** none
1109: **
1110: ** Side Effects:
1111: ** sets the alarm clock to call itself after MarkIntvl
1112: ** minutes.
1113: **
1114: ** Requires:
1115: ** logmsg
1116: **
1117: ** Called By:
1118: ** system alarm clock.
1119: ** init
1120: */
1121:
1122: domark()
1123: {
1124: auto long t;
1125: extern char *ctime();
1126: register char *p;
1127: register char *q;
1128: char buf[40];
1129:
1130: alarm(0);
1131: dprintf("domark\n");
1132: time(&t);
1133: q = buf;
1134: for (p = " --- MARK --- "; (*q++ = *p++) != '\0'; )
1135: continue;
1136: q--;
1137: for (p = ctime(&t); (*q++ = *p++) != '\0'; )
1138: continue;
1139: logmsg(-1, buf);
1140: signal(SIGALRM, domark);
1141: alarm(MarkIntvl*60);
1142: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.