lots of bug fixes - console bad fileno, repeated messages, reapchild.
[unix-history] / usr / src / usr.sbin / syslogd / syslogd.c
CommitLineData
e677da31 1#ifndef lint
84555b38 2static char sccsid[] = "@(#)syslogd.c 4.9 (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
33#define DEFSPRI LOG_EMERG
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++;
423 return;
424 } else {
425 /* new line, save it */
426 flushmsg();
427 strcpy(prevline, msg);
428 strcpy(prevhost, from);
429 prevdate = prevline + (cp - msg) + 2;
430 prevflags = flags;
431 prevpri = pri;
432 }
433 }
434
ada83039
RC
435 v->iov_base = from;
436 v->iov_len = strlen(v->iov_base);
437 v++;
438 v->iov_base = " ";
439 v->iov_len = 1;
440 v++;
441 v->iov_base = msg;
442 v->iov_len = strlen(v->iov_base);
443 v++;
e677da31
RC
444 /* log the message to the particular outputs */
445 for (f = Files; f < &Files[NLOGS]; f++) {
a49a6aba 446 if (f->f_file < 0)
1386dfed 447 continue;
a49a6aba 448 if (flags & ISMARK) { /* mark message */
1386dfed
RC
449 if (!(f->f_flags & F_MARK))
450 continue;
84555b38
RC
451 if (!(f->f_flags & F_CONS)) {
452 struct stat stb;
453 long now;
454
455 if (fstat(f->f_file, &stb) < 0)
456 continue;
457 time(&now);
458 if (stb.st_mtime > now - MarkIntvl * 60)
459 continue;
460 }
a49a6aba
RC
461 } else if ((f->f_pmask & mask(pri)) == 0 ||
462 (flags & IGN_CONS) && (f->f_flags & F_CONS))
463 continue;
e677da31
RC
464 if (f->f_flags & F_FORW) {
465 sprintf(line, "<%d>%s", pri, msg);
466 l = strlen(line);
467 if (l > MAXLINE)
468 l = MAXLINE;
469 if (sendto(f->f_file, line, l, 0,
8a7154b1
RC
470 &f->f_addr, sizeof f->f_addr) != l) {
471 int e = errno;
472 (void) close(f->f_file);
473 f->f_file = -1;
474 errno = e;
e677da31 475 logerror("sendto");
8a7154b1 476 }
e677da31
RC
477 continue;
478 }
ada83039
RC
479 if (f->f_flags & F_TTY) {
480 v->iov_base = "\r\n";
481 v->iov_len = 2;
482 } else {
483 v->iov_base = "\n";
484 v->iov_len = 1;
e677da31 485 }
ada83039 486 if (writev(f->f_file, iov, 4) < 0) {
8a7154b1 487 int e = errno;
e677da31 488 (void) close(f->f_file);
84555b38
RC
489 /*
490 * Check for EBADF on the console due to vhangup() XXX
491 */
492 if (e == EBADF && (f->f_flags & F_TTY)) {
493 f->f_file = open(f->f_name, O_WRONLY|O_APPEND);
494 if (f->f_file < 0)
495 logerror(f->f_name);
496 } else {
497 f->f_file = -1;
498 errno = e;
499 logerror(f->f_name);
500 }
8a7154b1
RC
501 } else if (flags & SYNC_FILE)
502 (void) fsync(f->f_file);
e677da31
RC
503 }
504
505 /*
506 * Output high priority messages to terminals.
507 */
84555b38 508 if (!(flags & ISMARK) && (mask(pri) & Sumask))
ada83039 509 wallmsg(pri, msg, from);
84555b38
RC
510
511 (void) sigsetmask(omask);
e677da31
RC
512}
513
514/*
a49a6aba 515 * INIT -- Initialize syslogd from configuration table
e677da31 516 *
a49a6aba
RC
517 * The configuration table consists of a series of lines broken
518 * into two sections by a blank line. The first section gives a
519 * list of files to log on. Each line begins with a
520 * comma-separated list of digits or ranges of digits (pairs of
521 * digits separated by a dash); if the priority of a message falls
522 * in the set of digits defined by this list, then the message is
523 * logged in the file corresponding to this line. If the
524 * following character is an asterisk, then syslogd arranges for
525 * something to be printed every fifteen minutes (even if only a
526 * null line), so that crashes and other events can be localized.
527 * The rest of the line is the pathname of the log file. The
528 * second section is a list of user names; these people are all
529 * notified when subalert messages occur (if they are logged on).
530 * These lines may also have associated priority lists.
e677da31 531 *
a49a6aba
RC
532 * The configuration table will be reread by this routine if a
533 * SIGHUP signal occurs; for that reason, it is tricky about not
534 * re-opening files and closing files it will not be using.
e677da31
RC
535 */
536
537init()
538{
539 register int i;
540 register FILE *cf;
541 register struct filed *f;
542 register char *p;
543 char cline[BUFSIZ];
e677da31
RC
544 struct hostent *hp;
545 int pmask, flags;
546 long now;
a49a6aba 547 char *getpmask();
e677da31
RC
548
549 dprintf("init\n");
550
a49a6aba
RC
551 /* flush any pending output */
552 flushmsg();
553
e677da31
RC
554 /*
555 * Close all open log files.
556 */
557 for (f = Files; f < &Files[NLOGS]; f++) {
1386dfed 558 if (f->f_file >= 0)
e677da31
RC
559 (void) close(f->f_file);
560 f->f_file = -1;
561 }
562
563 /* open the configuration file */
564 if ((cf = fopen(ConfFile, "r")) == NULL) {
565 dprintf("cannot open %s\n", ConfFile);
566 f = Files;
567 if ((f->f_file = open(ctty, O_WRONLY)) >= 0) {
568 strncpy(f->f_name, ctty, sizeof(f->f_name)-1);
a49a6aba 569 f->f_pmask = mask(LOG_CRIT);
1386dfed 570 f->f_flags = F_TTY|F_MARK|F_CONS;
a49a6aba 571 untty();
e677da31
RC
572 }
573 return;
574 }
575
576 /*
577 * Foreach line in the conf table, open that file.
578 */
579 f = Files;
e677da31
RC
580 while (fgets(cline, sizeof cline, cf) != NULL) {
581 /* check for end-of-section */
582 if (cline[0] == '\n')
583 break;
584
585 /* strip off newline character */
a24c481a
RC
586 p = index(cline, '\n');
587 if (p)
588 *p = '\0';
e677da31
RC
589
590 dprintf("F: got line '%s'\n", cline);
591
592 /* extract priority mask and mark flag */
593 p = cline;
594 flags = 0;
a49a6aba 595 p = getpmask(p, &pmask);
e677da31
RC
596 if (*p == '*') {
597 p++;
598 flags |= F_MARK;
599 }
600
601 if (f >= &Files[NLOGS])
602 continue;
603
604 /* mark entry as used and update flags */
605 if (*p == '@') {
ada83039
RC
606 if (!inet)
607 continue;
e677da31 608 hp = gethostbyname(++p);
ada83039
RC
609 if (hp == NULL) {
610 char buf[100];
611
612 sprintf(buf, "unknown host %s", p);
613 errno = 0;
614 logerror(buf);
615 continue;
616 }
617 bzero(&f->f_addr, sizeof f->f_addr);
618 f->f_addr.sin_family = AF_INET;
619 f->f_addr.sin_port = port;
620 bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length);
621 f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
622 if (f->f_file < 0) {
623 logerror("socket");
624 continue;
e677da31
RC
625 }
626 flags |= F_FORW;
627 f->f_pmask = pmask;
628 f->f_flags = flags;
a49a6aba 629 dprintf("Host %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
630 f++;
631 continue;
632 }
633 strncpy(f->f_name, p, sizeof(f->f_name)-1);
84555b38 634 if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
e677da31
RC
635 logerror(p);
636 continue;
637 }
a49a6aba 638 if (isatty(f->f_file)) {
e677da31 639 flags |= F_TTY;
a49a6aba
RC
640 untty();
641 }
1386dfed
RC
642 if (strcmp(p, ctty) == 0)
643 flags |= F_CONS;
e677da31
RC
644 f->f_pmask = pmask;
645 f->f_flags = flags;
a49a6aba 646 dprintf("File %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
647 f++;
648 }
649
650 /*
651 * Read the list of users.
652 *
653 * Anyone in this list is informed directly if s/he
654 * is logged in when a high priority message comes through.
655 */
84555b38 656 Sumask = mask(LOG_ALERT);
e677da31
RC
657 for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) {
658 /* strip off newline */
a24c481a
RC
659 p = index(cline, '\n');
660 if (p)
661 *p = '\0';
e677da31
RC
662 dprintf("U: got line '%s'\n", cline);
663 p = cline;
84555b38 664 if (isdigit(*p))
a49a6aba 665 p = getpmask(p, &pmask);
84555b38
RC
666 else
667 pmask = mask(LOG_SALERT);
668 Susers[i].s_pmask = pmask;
669 Sumask |= pmask;
e677da31 670 strncpy(Susers[i].s_name, p, UNAMESZ);
a49a6aba 671 dprintf("Suser %s pmask %#x\n", p, pmask);
e677da31
RC
672 }
673
674 /* zero the rest of the old superusers */
675 while (i < NSUSERS)
676 Susers[i++].s_name[0] = '\0';
677
678 /* close the configuration file */
679 (void) fclose(cf);
680
ada83039 681 dprintf("syslogd: restarted\n");
e677da31
RC
682}
683
684/*
685 * WALLMSG -- Write a message to the world at large
686 *
687 * Write the specified message to either the entire
688 * world, or a list of approved users.
689 */
690
ada83039 691wallmsg(pri, msg, from)
e677da31 692 int pri;
ada83039 693 char *msg, *from;
e677da31
RC
694{
695 register char *p;
696 register int i;
ada83039
RC
697 int f, flags, len, e;
698 FILE *uf;
e677da31
RC
699 struct utmp ut;
700 long now;
701 char line[MAXLINE + 100];
e677da31
RC
702
703 /* open the user login file */
ada83039 704 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
84555b38
RC
705 i = Sumask;
706 Sumask = 0;
ada83039 707 logerror("/etc/utmp");
84555b38 708 Sumask = i;
e677da31 709 return;
ada83039 710 }
e677da31
RC
711
712 time(&now);
e677da31 713 sprintf(line,
ada83039
RC
714 "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n",
715 from, ctime(&now), msg);
e677da31
RC
716 len = strlen(line);
717
718 /* scan the user login file */
ada83039 719 while (fread(&ut, sizeof ut, 1, uf) == 1) {
e677da31
RC
720 /* is this slot used? */
721 if (ut.ut_name[0] == '\0')
722 continue;
723
724 /* should we send the message to this user? */
725 if (pri != LOG_ALERT) {
726 for (i = 0; i < NSUSERS; i++) {
a49a6aba 727 if ((mask(pri) & Susers[i].s_pmask) == 0)
e677da31
RC
728 continue;
729 if (strncmp(Susers[i].s_name, ut.ut_name,
84555b38 730 UNAMESZ) == 0)
e677da31
RC
731 goto prmsg;
732 }
733 continue;
734 }
1386dfed 735 prmsg:
e677da31
RC
736
737 /* compute the device name */
738 p = "/dev/12345678";
739 strcpyn(&p[5], ut.ut_line, UNAMESZ);
740
84555b38
RC
741 /*
742 * Might as well fork instead of using nonblocking I/O
743 * and doing notty().
744 */
e677da31 745 if (fork() == 0) {
84555b38
RC
746 signal(SIGALRM, SIG_DFL);
747 alarm(30);
748 /* open the terminal */
749 f = open(p, O_WRONLY);
750 if (f >= 0)
751 (void) write(f, line, len);
e677da31
RC
752 exit(0);
753 }
e677da31 754 }
e677da31 755 /* close the user login file */
84555b38
RC
756 (void) fclose(uf);
757}
758
759reapchild()
760{
761 union wait status;
762
763 while (wait3(&status, WNOHANG, 0) > 0)
764 ;
e677da31
RC
765}
766
767/*
768 * Make sure every marked file gets written to periodically.
769 * Reset the alarm clock to call itself after MarkIntvl minutes.
770 */
771domark()
772{
84555b38 773 char buf[50];
e677da31
RC
774 long now;
775
776 dprintf("domark\n");
777
778 time(&now);
1386dfed 779 sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now));
a49a6aba
RC
780 flushmsg();
781 logmsg(0, buf, host, NOCOPY|ISMARK);
e677da31
RC
782 alarm(MarkIntvl * 60);
783}
784
785/*
786 * Check to see if we should log this message.
787 */
788chkhost(f)
789 struct sockaddr_in *f;
790{
791 struct hostent *hp;
792 extern char *inet_ntoa();
793
794 dprintf("chkhost\n");
795
796 if (f->sin_family != AF_INET) {
797 dprintf("Malformed from address\n");
798 return (0);
799 }
800 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
801 if (hp == 0) {
802 dprintf("Host name for your address (%s) unknown\n",
803 inet_ntoa(f->sin_addr));
804 return (0);
805 }
806 strncpy(rhost, hp->h_name, sizeof rhost);
807 return (1);
808}
809
a49a6aba
RC
810flushmsg()
811{
812 if (count == 0)
813 return;
814 if (count > 1)
815 sprintf(prevdate+18, "last message repeated %d times", count);
84555b38 816 count = 0;
a49a6aba
RC
817 logmsg(prevpri, prevline, prevhost, prevflags|NOCOPY);
818 prevline[0] = '\0';
a49a6aba
RC
819}
820
e677da31
RC
821/*
822 * Print syslogd errors some place.
823 */
824logerror(type)
825 char *type;
826{
827 char buf[100];
ada83039 828 long now;
e677da31 829
ada83039 830 time(&now);
e677da31 831 if (errno == 0)
ada83039 832 sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type);
e677da31 833 else if ((unsigned) errno > sys_nerr)
ada83039
RC
834 sprintf(buf, "syslogd: %.24s-- %s: error %d",
835 ctime(&now), type, errno);
e677da31 836 else
ada83039
RC
837 sprintf(buf, "syslogd: %.24s-- %s: %s",
838 ctime(&now), type, sys_errlist[errno]);
e677da31 839 errno = 0;
ada83039 840 dprintf("%s\n", buf);
1386dfed 841 logmsg(LOG_ERR, buf, host, 0);
e677da31
RC
842}
843
844die()
845{
ada83039 846
a49a6aba 847 flushmsg();
ada83039 848 dprintf("syslogd: going down\n");
e677da31
RC
849 (void) unlink(logname);
850 exit(0);
851}
a49a6aba
RC
852
853/*
854 * getpmask() parses a string cp looking for a set of numbers like
855 * '1-5,8,16' and returns in *ppmask the set of bits represented by
856 * these numbers. A notation '1-5' is interpreted to mean 'turn on
857 * bits 1 through 5 inclusive'. getpmask() returns the address of
858 * first byte after the number set.
859 */
860char *
861getpmask(cp, ppmask)
862 register char *cp;
863 unsigned *ppmask;
864{
865 int count1, count2;
866 register int i;
867
868 *ppmask = 0;
869 while (isdigit(*cp)) {
870 count1 = count2 = 0;
871 do {
872 count1 = 10 * count1 + (*cp++ - '0');
873 } while (isdigit(*cp));
874 switch (*cp) {
875 case ',':
876 ++cp;
877 /* FALL THRU */
878 default:
879 *ppmask |= mask(count1);
880 continue;
881
882 case '-':
883 while (isdigit(*++cp))
884 count2 = 10 * count2 + (*cp - '0');
885 for (i = count1; i <= count2; ++i)
886 *ppmask |= mask(i);
887 if (*cp == ',')
888 ++cp;
889 continue;
890 }
891 }
892
893 return (cp);
894}