man macros distributed with 4.3BSD beta
[unix-history] / usr / src / usr.sbin / syslogd / syslogd.c
CommitLineData
e677da31 1#ifndef lint
dec31094 2static char sccsid[] = "@(#)syslogd.c 4.12 (Berkeley) %G%";
e677da31
RC
3#endif
4
5/*
6 * syslogd -- log system messages
7 *
8 * This program implements a system log. It takes a series of lines.
9 * Each line may have a priority, signified as "<n>" as
a49a6aba
RC
10 * the first characters of the line. If this is
11 * not present, a default priority is used.
e677da31
RC
12 *
13 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
14 * cause it to reread its configuration file.
15 *
16 * Defined Constants:
17 *
e677da31 18 * MAXLINE -- the maximimum line length that can be handled.
a49a6aba
RC
19 * NLOGS -- the maximum number of simultaneous log files.
20 * NUSERS -- the maximum number of people that can
21 * be designated as "superusers" on your system.
22 * DEFUPRI -- the default priority for user messages
23 * DEFSPRI -- the default priority for kernel messages
ada83039
RC
24 *
25 * Author: Eric Allman
a49a6aba 26 * extensive changes by Ralph Campbell
e677da31
RC
27 */
28
a49a6aba
RC
29#define NLOGS 10 /* max number of log files */
30#define NSUSERS 10 /* max number of special users */
31#define MAXLINE 1024 /* maximum line length */
32#define DEFUPRI LOG_NOTICE
dec31094 33#define DEFSPRI KERN_ERR
e677da31
RC
34
35#include <syslog.h>
36#include <errno.h>
37#include <stdio.h>
38#include <utmp.h>
39#include <ctype.h>
a24c481a
RC
40#include <signal.h>
41#include <sysexits.h>
42#include <strings.h>
43
e677da31
RC
44#include <sys/types.h>
45#include <sys/ioctl.h>
46#include <sys/stat.h>
84555b38 47#include <sys/wait.h>
e677da31
RC
48#include <sys/socket.h>
49#include <sys/file.h>
63cb489e 50#include <sys/msgbuf.h>
ada83039 51#include <sys/uio.h>
e677da31 52#include <sys/un.h>
a24c481a 53
e677da31
RC
54#include <netinet/in.h>
55#include <netdb.h>
56
57char logname[] = "/dev/log";
58char defconf[] = "/etc/syslog.conf";
59char defpid[] = "/etc/syslog.pid";
60char ctty[] = "/dev/console";
61
e677da31
RC
62#define dprintf if (Debug) printf
63
64#define UNAMESZ 8 /* length of a login name */
65
a49a6aba
RC
66#define mask(x) (1 << (x))
67
8a7154b1
RC
68/*
69 * Flags to logmsg().
70 */
71#define IGN_CONS 0x1
72#define SYNC_FILE 0x2
a49a6aba
RC
73#define NOCOPY 0x4
74#define ISMARK 0x10
8a7154b1 75
e677da31
RC
76/*
77 * This structure represents the files that will have log
78 * copies printed.
79 */
80
81struct filed {
82 int f_file; /* file descriptor */
a49a6aba
RC
83 u_int f_pmask; /* priority mask */
84 u_int f_flags; /* see #defines below */
e677da31
RC
85 struct sockaddr_in f_addr; /* forwarding address */
86 char f_name[248]; /* filename */
87};
88
1386dfed
RC
89#define F_TTY 001 /* file is a tty */
90#define F_MARK 002 /* write to the file periodically */
91#define F_FORW 004 /* forward message to another host */
92#define F_CONS 010 /* file is the console */
e677da31
RC
93
94struct filed Files[NLOGS];
95
96/* list of superusers */
97struct susers {
a49a6aba 98 u_int s_pmask; /* priority mask */
e677da31
RC
99 char s_name[UNAMESZ+1];
100};
101
102struct susers Susers[NSUSERS];
103
104int Debug; /* debug flag */
105int LogFile; /* log file descriptor */
a49a6aba 106u_int Sumask; /* priorities written to super-users */
e677da31
RC
107int MarkIntvl = 15; /* mark interval in minutes */
108char *ConfFile = defconf; /* configuration file */
ada83039 109char host[32]; /* our hostname */
e677da31 110char rhost[32]; /* hostname of sender (forwarded messages) */
ada83039
RC
111int inet = 0; /* non-zero if INET sockets are being used */
112int port; /* port number for INET connections */
a49a6aba
RC
113u_int Copymask = 0xffffffff; /* priorities to supress multiple copies */
114char prevline[MAXLINE + 1]; /* copy of last line to supress repeats */
115char *prevdate; /* pointer to the date in prevline */
116char prevhost[32]; /* previous host */
117int prevflags;
118int prevpri;
119int count = 0; /* number of times seen */
e677da31
RC
120
121extern int errno, sys_nerr;
122extern char *sys_errlist[];
a49a6aba 123extern char *ctime(), *index();
e677da31
RC
124
125main(argc, argv)
126 int argc;
127 char **argv;
128{
129 register int i;
130 register char *p;
84555b38 131 int funix, finet, inetm, fklog, klogm, len;
e677da31
RC
132 struct sockaddr_un sun, fromunix;
133 struct sockaddr_in sin, frominet;
134 FILE *fp;
63cb489e 135 char line[MSG_BSIZE + 1];
84555b38 136 extern int die(), domark(), reapchild();
e677da31
RC
137
138 sun.sun_family = AF_UNIX;
139 strncpy(sun.sun_path, logname, sizeof sun.sun_path);
ada83039 140 gethostname(host, sizeof host);
e677da31
RC
141
142 while (--argc > 0) {
143 p = *++argv;
a49a6aba
RC
144 if (p[0] != '-')
145 usage();
146 switch (p[1]) {
147 case 'm': /* set mark interval */
148 MarkIntvl = atoi(&p[2]);
149 if (MarkIntvl <= 0)
150 MarkIntvl = 1;
151 break;
152
153 case 'f': /* configuration file */
154 if (p[2] != '\0')
155 ConfFile = &p[2];
156 break;
157
158 case 'd': /* debug */
159 Debug++;
160 break;
161
162 case 'p': /* path */
163 if (p[2] != '\0')
164 strncpy(sun.sun_path, &p[2],
165 sizeof sun.sun_path);
166 break;
167
168 default:
169 usage();
e677da31
RC
170 }
171 }
172
173 if (!Debug) {
174 if (fork())
175 exit(0);
176 for (i = 0; i < 10; i++)
177 (void) close(i);
178 (void) open("/", 0);
179 (void) dup2(0, 1);
180 (void) dup2(0, 2);
a49a6aba 181 untty();
84555b38
RC
182 } else
183 setlinebuf(stdout);
184
e677da31 185 signal(SIGTERM, die);
a49a6aba 186 signal(SIGINT, die);
84555b38 187 signal(SIGCHLD, reapchild);
e677da31 188 funix = socket(AF_UNIX, SOCK_DGRAM, 0);
84555b38
RC
189 if (funix < 0 || bind(funix, &sun,
190 sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0 ||
191 chmod(sun.sun_path, 0666) < 0) {
e677da31 192 fp = fopen(ctty, "w");
a49a6aba 193 fprintf(fp, "\r\nsyslogd: cannot create %s (%d)\r\n", logname, errno);
e677da31
RC
194 dprintf("cannot create %s (%d)\n", logname, errno);
195 exit(1);
196 }
e677da31
RC
197 finet = socket(AF_INET, SOCK_DGRAM, 0);
198 if (finet >= 0) {
199 struct servent *sp;
200
201 sp = getservbyname("syslog", "udp");
202 if (sp == NULL) {
203 errno = 0;
204 logerror("syslog/udp: unknown service");
205 die();
206 }
207 sin.sin_family = AF_INET;
ada83039 208 sin.sin_port = port = sp->s_port;
e677da31
RC
209 if (bind(finet, &sin, sizeof(sin), 0) < 0) {
210 logerror("bind");
211 die();
212 }
84555b38 213 inetm = mask(finet);
ada83039 214 inet = 1;
e677da31 215 }
84555b38
RC
216 if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
217 klogm = mask(fklog);
218 else {
63cb489e 219 dprintf("can't open /dev/klog (%d)\n", errno);
a49a6aba
RC
220 klogm = 0;
221 }
e677da31
RC
222
223 /* tuck my process id away */
224 fp = fopen(defpid, "w");
225 if (fp != NULL) {
226 fprintf(fp, "%d\n", getpid());
227 fclose(fp);
228 }
229
230 dprintf("off & running....\n");
231
232 for (i = 0; i < NLOGS; i++)
233 Files[i].f_file = -1;
234 init();
84555b38 235 signal(SIGHUP, init);
454c883a
RC
236 signal(SIGALRM, domark);
237 alarm(MarkIntvl * 60);
238
e677da31 239 for (;;) {
84555b38 240 int nfds, readfds = mask(funix) | inetm | klogm;
e677da31 241
84555b38 242 dprintf("readfds = %#x\n", readfds, funix, finet, fklog);
e677da31 243 nfds = select(20, &readfds, 0, 0, 0);
a49a6aba 244 dprintf("got a message (%d, %#x)\n", nfds, readfds);
e677da31
RC
245 if (nfds == 0)
246 continue;
247 if (nfds < 0) {
248 if (errno == EINTR)
249 continue;
250 logerror("select");
251 continue;
252 }
a49a6aba 253 if (readfds & klogm) {
84555b38 254 i = read(fklog, line, sizeof(line) - 1);
8a7154b1
RC
255 if (i > 0) {
256 line[i] = '\0';
257 printsys(line);
a49a6aba 258 } else if (i < 0 && errno != EINTR) {
84555b38
RC
259 logerror("klog");
260 fklog = -1;
a49a6aba
RC
261 klogm = 0;
262 }
8a7154b1 263 }
a49a6aba 264 if (readfds & mask(funix)) {
e677da31
RC
265 len = sizeof fromunix;
266 i = recvfrom(funix, line, MAXLINE, 0, &fromunix, &len);
a24c481a
RC
267 if (i > 0) {
268 line[i] = '\0';
269 printline(1, line);
270 } else if (i < 0 && errno != EINTR)
271 logerror("recvfrom");
272 }
84555b38 273 if (readfds & inetm) {
e677da31
RC
274 len = sizeof frominet;
275 i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len);
a24c481a
RC
276 if (i > 0 && chkhost(&frominet)) {
277 line[i] = '\0';
278 printline(0, line);
279 } else if (i < 0 && errno != EINTR)
280 logerror("recvfrom");
281 }
e677da31
RC
282 }
283}
284
a49a6aba
RC
285usage()
286{
287 fprintf(stderr, "usage: syslogd [-m#] [-d] [-ppath] [-fconffile]\n");
288 exit(1);
289}
290
291untty()
292{
293 int i;
294
295 if (!Debug) {
296 i = open("/dev/tty", O_RDWR);
297 if (i >= 0) {
298 ioctl(i, TIOCNOTTY, (char *)0);
299 (void) close(i);
300 }
301 }
302}
303
e677da31
RC
304/*
305 * Take a raw input line, decode the message, and print the message
306 * on the appropriate log files.
307 */
308
309printline(local, msg)
310 int local;
311 char *msg;
312{
313 register char *p, *q;
314 register int c;
63cb489e 315 char line[MAXLINE + 1];
e677da31
RC
316 int pri;
317
318 /* test for special codes */
a49a6aba 319 pri = DEFUPRI;
e677da31 320 p = msg;
a49a6aba
RC
321 if (*p == '<') {
322 pri = 0;
323 while (isdigit(*++p))
324 pri = 10 * pri + (*p - '0');
325 if (*p == '>')
326 ++p;
327 if (pri <= 0 || pri >= 32)
328 pri = DEFUPRI;
e677da31
RC
329 }
330
331 q = line;
e677da31 332 while ((c = *p++ & 0177) != '\0' && c != '\n' &&
63cb489e 333 q < &line[sizeof(line) - 1]) {
e677da31
RC
334 if (iscntrl(c)) {
335 *q++ = '^';
336 *q++ = c ^ 0100;
337 } else
338 *q++ = c;
339 }
e677da31
RC
340 *q = '\0';
341
1386dfed 342 logmsg(pri, line, local ? host : rhost, 0);
e677da31
RC
343}
344
63cb489e
RC
345/*
346 * Take a raw input line from /dev/klog, split and format similar to syslog().
347 */
348
349printsys(msg)
350 char *msg;
351{
352 register char *p, *q;
353 register int c;
354 char line[MAXLINE + 1];
8a7154b1 355 int pri, flags;
a49a6aba 356 char *lp;
63cb489e
RC
357 long now;
358
359 time(&now);
a49a6aba
RC
360 sprintf(line, "vmunix: %.15s-- ", ctime(&now) + 4);
361 lp = line + strlen(line);
63cb489e 362 for (p = msg; *p != '\0'; ) {
8a7154b1 363 flags = SYNC_FILE; /* fsync file after write */
a49a6aba
RC
364 pri = DEFSPRI;
365 if (*p == '<') {
366 pri = 0;
367 while (isdigit(*++p))
368 pri = 10 * pri + (*p - '0');
369 if (*p == '>')
370 ++p;
371 if (pri <= 0 || pri >= 32)
372 pri = DEFSPRI;
8a7154b1
RC
373 } else {
374 /* kernel printf's come out on console */
375 flags |= IGN_CONS;
376 }
a49a6aba
RC
377 q = lp;
378 while (*p != '\0' && (c = *p++) != '\n' &&
379 q < &line[MAXLINE])
63cb489e
RC
380 *q++ = c;
381 *q = '\0';
8a7154b1 382 logmsg(pri, line, host, flags);
63cb489e
RC
383 }
384}
385
e677da31
RC
386/*
387 * Log a message to the appropriate log files, users, etc. based on
388 * the priority.
389 */
390
8a7154b1 391logmsg(pri, msg, from, flags)
e677da31 392 int pri;
ada83039 393 char *msg, *from;
8a7154b1 394 int flags;
e677da31
RC
395{
396 char line[MAXLINE + 1];
397 register struct filed *f;
398 register int l;
ada83039
RC
399 struct iovec iov[4];
400 register struct iovec *v = iov;
84555b38
RC
401 int omask;
402
403 omask = sigblock(sigmask(SIGALRM)|sigmask(SIGHUP));
ada83039 404
a49a6aba
RC
405 if ((flags & NOCOPY) == 0) {
406 register char *cp;
407
408 /*
409 * Check to see if copies should be supressed or
410 * msg looks non-standard (e.g., 'prog: Feb 16 13:23:56-- ').
411 */
412 if ((Copymask & mask(pri)) == 0 ||
413 (cp = index(msg, ':')) == NULL || strlen(cp) < 20 ||
414 cp[5] != ' ' || cp[8] != ' ' || cp[11] != ':' ||
415 cp[14] != ':' || cp[17] != '-' || cp[18] != '-' ||
416 cp[19] != ' ')
417 flushmsg();
418 else if (!strncmp(msg, prevline, cp-msg) &&
419 !strcmp(cp+20, prevdate+18)) {
420 /* we found a match, update the time */
421 strncpy(prevdate, cp+2, 15);
422 count++;
2af4dea2 423 (void) sigsetmask(omask);
a49a6aba
RC
424 return;
425 } else {
426 /* new line, save it */
427 flushmsg();
428 strcpy(prevline, msg);
429 strcpy(prevhost, from);
430 prevdate = prevline + (cp - msg) + 2;
431 prevflags = flags;
432 prevpri = pri;
433 }
434 }
435
ada83039
RC
436 v->iov_base = from;
437 v->iov_len = strlen(v->iov_base);
438 v++;
439 v->iov_base = " ";
440 v->iov_len = 1;
441 v++;
442 v->iov_base = msg;
443 v->iov_len = strlen(v->iov_base);
444 v++;
e677da31
RC
445 /* log the message to the particular outputs */
446 for (f = Files; f < &Files[NLOGS]; f++) {
a49a6aba 447 if (f->f_file < 0)
1386dfed 448 continue;
a49a6aba 449 if (flags & ISMARK) { /* mark message */
1386dfed
RC
450 if (!(f->f_flags & F_MARK))
451 continue;
84555b38
RC
452 if (!(f->f_flags & F_CONS)) {
453 struct stat stb;
454 long now;
455
456 if (fstat(f->f_file, &stb) < 0)
457 continue;
458 time(&now);
459 if (stb.st_mtime > now - MarkIntvl * 60)
460 continue;
461 }
a49a6aba
RC
462 } else if ((f->f_pmask & mask(pri)) == 0 ||
463 (flags & IGN_CONS) && (f->f_flags & F_CONS))
464 continue;
e677da31
RC
465 if (f->f_flags & F_FORW) {
466 sprintf(line, "<%d>%s", pri, msg);
467 l = strlen(line);
468 if (l > MAXLINE)
469 l = MAXLINE;
470 if (sendto(f->f_file, line, l, 0,
8a7154b1
RC
471 &f->f_addr, sizeof f->f_addr) != l) {
472 int e = errno;
473 (void) close(f->f_file);
474 f->f_file = -1;
475 errno = e;
e677da31 476 logerror("sendto");
8a7154b1 477 }
e677da31
RC
478 continue;
479 }
ada83039
RC
480 if (f->f_flags & F_TTY) {
481 v->iov_base = "\r\n";
482 v->iov_len = 2;
483 } else {
484 v->iov_base = "\n";
485 v->iov_len = 1;
e677da31 486 }
ada83039 487 if (writev(f->f_file, iov, 4) < 0) {
8a7154b1 488 int e = errno;
e677da31 489 (void) close(f->f_file);
84555b38
RC
490 /*
491 * Check for EBADF on the console due to vhangup() XXX
492 */
493 if (e == EBADF && (f->f_flags & F_TTY)) {
494 f->f_file = open(f->f_name, O_WRONLY|O_APPEND);
495 if (f->f_file < 0)
496 logerror(f->f_name);
497 } else {
498 f->f_file = -1;
499 errno = e;
500 logerror(f->f_name);
501 }
8a7154b1
RC
502 } else if (flags & SYNC_FILE)
503 (void) fsync(f->f_file);
e677da31
RC
504 }
505
506 /*
507 * Output high priority messages to terminals.
508 */
84555b38 509 if (!(flags & ISMARK) && (mask(pri) & Sumask))
ada83039 510 wallmsg(pri, msg, from);
84555b38
RC
511
512 (void) sigsetmask(omask);
e677da31
RC
513}
514
515/*
a49a6aba 516 * INIT -- Initialize syslogd from configuration table
e677da31 517 *
a49a6aba
RC
518 * The configuration table consists of a series of lines broken
519 * into two sections by a blank line. The first section gives a
520 * list of files to log on. Each line begins with a
521 * comma-separated list of digits or ranges of digits (pairs of
522 * digits separated by a dash); if the priority of a message falls
523 * in the set of digits defined by this list, then the message is
524 * logged in the file corresponding to this line. If the
525 * following character is an asterisk, then syslogd arranges for
526 * something to be printed every fifteen minutes (even if only a
527 * null line), so that crashes and other events can be localized.
528 * The rest of the line is the pathname of the log file. The
529 * second section is a list of user names; these people are all
530 * notified when subalert messages occur (if they are logged on).
531 * These lines may also have associated priority lists.
e677da31 532 *
a49a6aba
RC
533 * The configuration table will be reread by this routine if a
534 * SIGHUP signal occurs; for that reason, it is tricky about not
535 * re-opening files and closing files it will not be using.
e677da31
RC
536 */
537
538init()
539{
540 register int i;
541 register FILE *cf;
542 register struct filed *f;
543 register char *p;
544 char cline[BUFSIZ];
e677da31
RC
545 struct hostent *hp;
546 int pmask, flags;
547 long now;
a49a6aba 548 char *getpmask();
e677da31
RC
549
550 dprintf("init\n");
551
a49a6aba
RC
552 /* flush any pending output */
553 flushmsg();
554
e677da31
RC
555 /*
556 * Close all open log files.
557 */
558 for (f = Files; f < &Files[NLOGS]; f++) {
1386dfed 559 if (f->f_file >= 0)
e677da31
RC
560 (void) close(f->f_file);
561 f->f_file = -1;
562 }
563
564 /* open the configuration file */
565 if ((cf = fopen(ConfFile, "r")) == NULL) {
566 dprintf("cannot open %s\n", ConfFile);
567 f = Files;
568 if ((f->f_file = open(ctty, O_WRONLY)) >= 0) {
569 strncpy(f->f_name, ctty, sizeof(f->f_name)-1);
a49a6aba 570 f->f_pmask = mask(LOG_CRIT);
1386dfed 571 f->f_flags = F_TTY|F_MARK|F_CONS;
a49a6aba 572 untty();
e677da31
RC
573 }
574 return;
575 }
576
577 /*
578 * Foreach line in the conf table, open that file.
579 */
580 f = Files;
e677da31
RC
581 while (fgets(cline, sizeof cline, cf) != NULL) {
582 /* check for end-of-section */
583 if (cline[0] == '\n')
584 break;
585
586 /* strip off newline character */
a24c481a
RC
587 p = index(cline, '\n');
588 if (p)
589 *p = '\0';
e677da31
RC
590
591 dprintf("F: got line '%s'\n", cline);
592
593 /* extract priority mask and mark flag */
594 p = cline;
595 flags = 0;
a49a6aba 596 p = getpmask(p, &pmask);
e677da31
RC
597 if (*p == '*') {
598 p++;
599 flags |= F_MARK;
600 }
601
602 if (f >= &Files[NLOGS])
603 continue;
604
605 /* mark entry as used and update flags */
606 if (*p == '@') {
ada83039
RC
607 if (!inet)
608 continue;
e677da31 609 hp = gethostbyname(++p);
ada83039
RC
610 if (hp == NULL) {
611 char buf[100];
612
613 sprintf(buf, "unknown host %s", p);
614 errno = 0;
615 logerror(buf);
616 continue;
617 }
618 bzero(&f->f_addr, sizeof f->f_addr);
619 f->f_addr.sin_family = AF_INET;
620 f->f_addr.sin_port = port;
621 bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length);
622 f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
623 if (f->f_file < 0) {
624 logerror("socket");
625 continue;
e677da31
RC
626 }
627 flags |= F_FORW;
628 f->f_pmask = pmask;
629 f->f_flags = flags;
a49a6aba 630 dprintf("Host %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
631 f++;
632 continue;
633 }
634 strncpy(f->f_name, p, sizeof(f->f_name)-1);
84555b38 635 if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
e677da31
RC
636 logerror(p);
637 continue;
638 }
a49a6aba 639 if (isatty(f->f_file)) {
e677da31 640 flags |= F_TTY;
a49a6aba
RC
641 untty();
642 }
1386dfed
RC
643 if (strcmp(p, ctty) == 0)
644 flags |= F_CONS;
e677da31
RC
645 f->f_pmask = pmask;
646 f->f_flags = flags;
a49a6aba 647 dprintf("File %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
648 f++;
649 }
650
651 /*
652 * Read the list of users.
653 *
654 * Anyone in this list is informed directly if s/he
655 * is logged in when a high priority message comes through.
656 */
4bbbecf7 657 Sumask = mask(KERN_EMERG)|mask(LOG_EMERG);
e677da31
RC
658 for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) {
659 /* strip off newline */
a24c481a
RC
660 p = index(cline, '\n');
661 if (p)
662 *p = '\0';
e677da31
RC
663 dprintf("U: got line '%s'\n", cline);
664 p = cline;
84555b38 665 if (isdigit(*p))
a49a6aba 666 p = getpmask(p, &pmask);
84555b38
RC
667 else
668 pmask = mask(LOG_SALERT);
669 Susers[i].s_pmask = pmask;
670 Sumask |= pmask;
e677da31 671 strncpy(Susers[i].s_name, p, UNAMESZ);
a49a6aba 672 dprintf("Suser %s pmask %#x\n", p, pmask);
e677da31
RC
673 }
674
675 /* zero the rest of the old superusers */
676 while (i < NSUSERS)
677 Susers[i++].s_name[0] = '\0';
678
679 /* close the configuration file */
680 (void) fclose(cf);
681
ada83039 682 dprintf("syslogd: restarted\n");
e677da31
RC
683}
684
685/*
686 * WALLMSG -- Write a message to the world at large
687 *
688 * Write the specified message to either the entire
689 * world, or a list of approved users.
690 */
691
ada83039 692wallmsg(pri, msg, from)
e677da31 693 int pri;
ada83039 694 char *msg, *from;
e677da31
RC
695{
696 register char *p;
697 register int i;
ada83039
RC
698 int f, flags, len, e;
699 FILE *uf;
e677da31
RC
700 struct utmp ut;
701 long now;
702 char line[MAXLINE + 100];
e677da31
RC
703
704 /* open the user login file */
ada83039 705 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
84555b38
RC
706 i = Sumask;
707 Sumask = 0;
ada83039 708 logerror("/etc/utmp");
84555b38 709 Sumask = i;
e677da31 710 return;
ada83039 711 }
e677da31
RC
712
713 time(&now);
e677da31 714 sprintf(line,
ada83039
RC
715 "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n",
716 from, ctime(&now), msg);
e677da31
RC
717 len = strlen(line);
718
719 /* scan the user login file */
ada83039 720 while (fread(&ut, sizeof ut, 1, uf) == 1) {
e677da31
RC
721 /* is this slot used? */
722 if (ut.ut_name[0] == '\0')
723 continue;
724
725 /* should we send the message to this user? */
726 if (pri != LOG_ALERT) {
727 for (i = 0; i < NSUSERS; i++) {
a49a6aba 728 if ((mask(pri) & Susers[i].s_pmask) == 0)
e677da31
RC
729 continue;
730 if (strncmp(Susers[i].s_name, ut.ut_name,
84555b38 731 UNAMESZ) == 0)
e677da31
RC
732 goto prmsg;
733 }
734 continue;
735 }
1386dfed 736 prmsg:
e677da31
RC
737
738 /* compute the device name */
739 p = "/dev/12345678";
740 strcpyn(&p[5], ut.ut_line, UNAMESZ);
741
84555b38
RC
742 /*
743 * Might as well fork instead of using nonblocking I/O
744 * and doing notty().
745 */
e677da31 746 if (fork() == 0) {
84555b38
RC
747 signal(SIGALRM, SIG_DFL);
748 alarm(30);
749 /* open the terminal */
750 f = open(p, O_WRONLY);
751 if (f >= 0)
752 (void) write(f, line, len);
e677da31
RC
753 exit(0);
754 }
e677da31 755 }
e677da31 756 /* close the user login file */
84555b38
RC
757 (void) fclose(uf);
758}
759
760reapchild()
761{
762 union wait status;
763
764 while (wait3(&status, WNOHANG, 0) > 0)
765 ;
e677da31
RC
766}
767
768/*
769 * Make sure every marked file gets written to periodically.
770 * Reset the alarm clock to call itself after MarkIntvl minutes.
771 */
772domark()
773{
84555b38 774 char buf[50];
e677da31
RC
775 long now;
776
777 dprintf("domark\n");
778
779 time(&now);
1386dfed 780 sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now));
a49a6aba
RC
781 flushmsg();
782 logmsg(0, buf, host, NOCOPY|ISMARK);
e677da31
RC
783 alarm(MarkIntvl * 60);
784}
785
786/*
787 * Check to see if we should log this message.
788 */
789chkhost(f)
790 struct sockaddr_in *f;
791{
792 struct hostent *hp;
793 extern char *inet_ntoa();
794
795 dprintf("chkhost\n");
796
797 if (f->sin_family != AF_INET) {
798 dprintf("Malformed from address\n");
799 return (0);
800 }
801 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
802 if (hp == 0) {
803 dprintf("Host name for your address (%s) unknown\n",
804 inet_ntoa(f->sin_addr));
805 return (0);
806 }
807 strncpy(rhost, hp->h_name, sizeof rhost);
808 return (1);
809}
810
a49a6aba
RC
811flushmsg()
812{
813 if (count == 0)
814 return;
815 if (count > 1)
816 sprintf(prevdate+18, "last message repeated %d times", count);
84555b38 817 count = 0;
a49a6aba
RC
818 logmsg(prevpri, prevline, prevhost, prevflags|NOCOPY);
819 prevline[0] = '\0';
a49a6aba
RC
820}
821
e677da31
RC
822/*
823 * Print syslogd errors some place.
824 */
825logerror(type)
826 char *type;
827{
828 char buf[100];
ada83039 829 long now;
e677da31 830
ada83039 831 time(&now);
e677da31 832 if (errno == 0)
ada83039 833 sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type);
e677da31 834 else if ((unsigned) errno > sys_nerr)
ada83039
RC
835 sprintf(buf, "syslogd: %.24s-- %s: error %d",
836 ctime(&now), type, errno);
e677da31 837 else
ada83039
RC
838 sprintf(buf, "syslogd: %.24s-- %s: %s",
839 ctime(&now), type, sys_errlist[errno]);
e677da31 840 errno = 0;
ada83039 841 dprintf("%s\n", buf);
1386dfed 842 logmsg(LOG_ERR, buf, host, 0);
e677da31
RC
843}
844
845die()
846{
ada83039 847
a49a6aba 848 flushmsg();
ada83039 849 dprintf("syslogd: going down\n");
e677da31
RC
850 (void) unlink(logname);
851 exit(0);
852}
a49a6aba
RC
853
854/*
855 * getpmask() parses a string cp looking for a set of numbers like
856 * '1-5,8,16' and returns in *ppmask the set of bits represented by
857 * these numbers. A notation '1-5' is interpreted to mean 'turn on
858 * bits 1 through 5 inclusive'. getpmask() returns the address of
859 * first byte after the number set.
860 */
861char *
862getpmask(cp, ppmask)
863 register char *cp;
864 unsigned *ppmask;
865{
866 int count1, count2;
867 register int i;
868
869 *ppmask = 0;
870 while (isdigit(*cp)) {
871 count1 = count2 = 0;
872 do {
873 count1 = 10 * count1 + (*cp++ - '0');
874 } while (isdigit(*cp));
875 switch (*cp) {
876 case ',':
877 ++cp;
878 /* FALL THRU */
879 default:
880 *ppmask |= mask(count1);
881 continue;
882
883 case '-':
884 while (isdigit(*++cp))
885 count2 = 10 * count2 + (*cp - '0');
886 for (i = count1; i <= count2; ++i)
887 *ppmask |= mask(i);
888 if (*cp == ',')
889 ++cp;
890 continue;
891 }
892 }
893
894 return (cp);
895}