reasonable error message
[unix-history] / usr / src / usr.sbin / syslogd / syslogd.c
CommitLineData
e677da31 1#ifndef lint
a49a6aba 2static char sccsid[] = "@(#)syslogd.c 4.8 (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>
e677da31
RC
47#include <sys/socket.h>
48#include <sys/file.h>
63cb489e 49#include <sys/msgbuf.h>
ada83039 50#include <sys/uio.h>
e677da31 51#include <sys/un.h>
a24c481a 52
e677da31
RC
53#include <netinet/in.h>
54#include <netdb.h>
55
56char logname[] = "/dev/log";
57char defconf[] = "/etc/syslog.conf";
58char defpid[] = "/etc/syslog.pid";
59char ctty[] = "/dev/console";
60
e677da31
RC
61#define dprintf if (Debug) printf
62
63#define UNAMESZ 8 /* length of a login name */
64
a49a6aba
RC
65#define mask(x) (1 << (x))
66
8a7154b1
RC
67/*
68 * Flags to logmsg().
69 */
70#define IGN_CONS 0x1
71#define SYNC_FILE 0x2
a49a6aba
RC
72#define NOCOPY 0x4
73#define ISMARK 0x10
8a7154b1 74
e677da31
RC
75/*
76 * This structure represents the files that will have log
77 * copies printed.
78 */
79
80struct filed {
81 int f_file; /* file descriptor */
a49a6aba
RC
82 u_int f_pmask; /* priority mask */
83 u_int f_flags; /* see #defines below */
e677da31
RC
84 struct sockaddr_in f_addr; /* forwarding address */
85 char f_name[248]; /* filename */
86};
87
1386dfed
RC
88#define F_TTY 001 /* file is a tty */
89#define F_MARK 002 /* write to the file periodically */
90#define F_FORW 004 /* forward message to another host */
91#define F_CONS 010 /* file is the console */
e677da31
RC
92
93struct filed Files[NLOGS];
94
95/* list of superusers */
96struct susers {
a49a6aba 97 u_int s_pmask; /* priority mask */
e677da31
RC
98 char s_name[UNAMESZ+1];
99};
100
101struct susers Susers[NSUSERS];
102
103int Debug; /* debug flag */
104int LogFile; /* log file descriptor */
a49a6aba 105u_int Sumask; /* priorities written to super-users */
e677da31
RC
106int MarkIntvl = 15; /* mark interval in minutes */
107char *ConfFile = defconf; /* configuration file */
ada83039 108char host[32]; /* our hostname */
e677da31 109char rhost[32]; /* hostname of sender (forwarded messages) */
ada83039
RC
110int inet = 0; /* non-zero if INET sockets are being used */
111int port; /* port number for INET connections */
a49a6aba
RC
112u_int Copymask = 0xffffffff; /* priorities to supress multiple copies */
113char prevline[MAXLINE + 1]; /* copy of last line to supress repeats */
114char *prevdate; /* pointer to the date in prevline */
115char prevhost[32]; /* previous host */
116int prevflags;
117int prevpri;
118int count = 0; /* number of times seen */
e677da31
RC
119
120extern int errno, sys_nerr;
121extern char *sys_errlist[];
a49a6aba 122extern char *ctime(), *index();
e677da31
RC
123
124main(argc, argv)
125 int argc;
126 char **argv;
127{
128 register int i;
129 register char *p;
a49a6aba 130 int klog, funix, finet, defreadfds, klogm, len;
e677da31
RC
131 struct sockaddr_un sun, fromunix;
132 struct sockaddr_in sin, frominet;
133 FILE *fp;
63cb489e 134 char line[MSG_BSIZE + 1];
ada83039 135 extern int die(), domark();
e677da31
RC
136
137 sun.sun_family = AF_UNIX;
138 strncpy(sun.sun_path, logname, sizeof sun.sun_path);
ada83039 139 gethostname(host, sizeof host);
e677da31
RC
140
141 while (--argc > 0) {
142 p = *++argv;
a49a6aba
RC
143 if (p[0] != '-')
144 usage();
145 switch (p[1]) {
146 case 'm': /* set mark interval */
147 MarkIntvl = atoi(&p[2]);
148 if (MarkIntvl <= 0)
149 MarkIntvl = 1;
150 break;
151
152 case 'f': /* configuration file */
153 if (p[2] != '\0')
154 ConfFile = &p[2];
155 break;
156
157 case 'd': /* debug */
158 Debug++;
159 break;
160
161 case 'p': /* path */
162 if (p[2] != '\0')
163 strncpy(sun.sun_path, &p[2],
164 sizeof sun.sun_path);
165 break;
166
167 default:
168 usage();
e677da31
RC
169 }
170 }
171
172 if (!Debug) {
173 if (fork())
174 exit(0);
175 for (i = 0; i < 10; i++)
176 (void) close(i);
177 (void) open("/", 0);
178 (void) dup2(0, 1);
179 (void) dup2(0, 2);
a49a6aba 180 untty();
e677da31
RC
181 }
182 signal(SIGTERM, die);
a49a6aba 183 signal(SIGINT, die);
e677da31
RC
184 funix = socket(AF_UNIX, SOCK_DGRAM, 0);
185 if (funix >= 0 && bind(funix, &sun,
186 sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0) {
187 close(funix);
188 funix = -1;
189 }
190 if (funix < 0) {
191 fp = fopen(ctty, "w");
a49a6aba 192 fprintf(fp, "\r\nsyslogd: cannot create %s (%d)\r\n", logname, errno);
e677da31
RC
193 dprintf("cannot create %s (%d)\n", logname, errno);
194 exit(1);
195 }
a49a6aba 196 defreadfds = mask(funix);
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 }
a49a6aba 213 defreadfds |= mask(finet);
ada83039 214 inet = 1;
e677da31 215 }
a49a6aba
RC
216 if ((klog = open("/dev/klog", O_RDONLY)) >= 0) {
217 klogm = mask(klog);
218 defreadfds |= klogm;
219 } else {
63cb489e 220 dprintf("can't open /dev/klog (%d)\n", errno);
a49a6aba
RC
221 klogm = 0;
222 }
e677da31
RC
223
224 /* tuck my process id away */
225 fp = fopen(defpid, "w");
226 if (fp != NULL) {
227 fprintf(fp, "%d\n", getpid());
228 fclose(fp);
229 }
230
231 dprintf("off & running....\n");
232
233 for (i = 0; i < NLOGS; i++)
234 Files[i].f_file = -1;
235 init();
454c883a
RC
236 signal(SIGALRM, domark);
237 alarm(MarkIntvl * 60);
238
e677da31 239 for (;;) {
a24c481a 240 int nfds, readfds = defreadfds;
e677da31
RC
241
242 nfds = select(20, &readfds, 0, 0, 0);
a49a6aba 243 dprintf("got a message (%d, %#x)\n", nfds, readfds);
e677da31
RC
244 if (nfds == 0)
245 continue;
246 if (nfds < 0) {
247 if (errno == EINTR)
248 continue;
249 logerror("select");
250 continue;
251 }
a49a6aba 252 if (readfds & klogm) {
8a7154b1
RC
253 i = read(klog, line, sizeof(line) - 1);
254 if (i > 0) {
255 line[i] = '\0';
256 printsys(line);
a49a6aba 257 } else if (i < 0 && errno != EINTR) {
8a7154b1 258 logerror("read");
a49a6aba
RC
259 defreadfds &= ~klogm;
260 klog = -1;
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 }
a49a6aba 273 if (readfds & mask(finet)) {
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;
401
a49a6aba
RC
402 if ((flags & NOCOPY) == 0) {
403 register char *cp;
404
405 /*
406 * Check to see if copies should be supressed or
407 * msg looks non-standard (e.g., 'prog: Feb 16 13:23:56-- ').
408 */
409 if ((Copymask & mask(pri)) == 0 ||
410 (cp = index(msg, ':')) == NULL || strlen(cp) < 20 ||
411 cp[5] != ' ' || cp[8] != ' ' || cp[11] != ':' ||
412 cp[14] != ':' || cp[17] != '-' || cp[18] != '-' ||
413 cp[19] != ' ')
414 flushmsg();
415 else if (!strncmp(msg, prevline, cp-msg) &&
416 !strcmp(cp+20, prevdate+18)) {
417 /* we found a match, update the time */
418 strncpy(prevdate, cp+2, 15);
419 count++;
420 return;
421 } else {
422 /* new line, save it */
423 flushmsg();
424 strcpy(prevline, msg);
425 strcpy(prevhost, from);
426 prevdate = prevline + (cp - msg) + 2;
427 prevflags = flags;
428 prevpri = pri;
429 }
430 }
431
ada83039
RC
432 v->iov_base = from;
433 v->iov_len = strlen(v->iov_base);
434 v++;
435 v->iov_base = " ";
436 v->iov_len = 1;
437 v++;
438 v->iov_base = msg;
439 v->iov_len = strlen(v->iov_base);
440 v++;
e677da31
RC
441 /* log the message to the particular outputs */
442 for (f = Files; f < &Files[NLOGS]; f++) {
a49a6aba 443 if (f->f_file < 0)
1386dfed 444 continue;
a49a6aba 445 if (flags & ISMARK) { /* mark message */
1386dfed
RC
446 struct stat stb;
447 long now;
448
449 if (!(f->f_flags & F_MARK))
450 continue;
451 if (fstat(f->f_file, &stb) < 0)
452 continue;
453 time(&now);
454 if (!(f->f_flags & F_CONS) &&
455 stb.st_mtime > now - MarkIntvl * 60)
456 continue;
a49a6aba
RC
457 } else if ((f->f_pmask & mask(pri)) == 0 ||
458 (flags & IGN_CONS) && (f->f_flags & F_CONS))
459 continue;
e677da31
RC
460 if (f->f_flags & F_FORW) {
461 sprintf(line, "<%d>%s", pri, msg);
462 l = strlen(line);
463 if (l > MAXLINE)
464 l = MAXLINE;
465 if (sendto(f->f_file, line, l, 0,
8a7154b1
RC
466 &f->f_addr, sizeof f->f_addr) != l) {
467 int e = errno;
468 (void) close(f->f_file);
469 f->f_file = -1;
470 errno = e;
e677da31 471 logerror("sendto");
8a7154b1 472 }
e677da31
RC
473 continue;
474 }
ada83039
RC
475 if (f->f_flags & F_TTY) {
476 v->iov_base = "\r\n";
477 v->iov_len = 2;
478 } else {
479 v->iov_base = "\n";
480 v->iov_len = 1;
e677da31 481 }
ada83039 482 if (writev(f->f_file, iov, 4) < 0) {
8a7154b1 483 int e = errno;
e677da31
RC
484 (void) close(f->f_file);
485 f->f_file = -1;
8a7154b1
RC
486 errno = e;
487 logerror(f->f_name);
488 } else if (flags & SYNC_FILE)
489 (void) fsync(f->f_file);
e677da31
RC
490 }
491
492 /*
493 * Output high priority messages to terminals.
494 */
a49a6aba 495 if (mask(pri) & Sumask)
ada83039 496 wallmsg(pri, msg, from);
e677da31
RC
497}
498
499/*
a49a6aba 500 * INIT -- Initialize syslogd from configuration table
e677da31 501 *
a49a6aba
RC
502 * The configuration table consists of a series of lines broken
503 * into two sections by a blank line. The first section gives a
504 * list of files to log on. Each line begins with a
505 * comma-separated list of digits or ranges of digits (pairs of
506 * digits separated by a dash); if the priority of a message falls
507 * in the set of digits defined by this list, then the message is
508 * logged in the file corresponding to this line. If the
509 * following character is an asterisk, then syslogd arranges for
510 * something to be printed every fifteen minutes (even if only a
511 * null line), so that crashes and other events can be localized.
512 * The rest of the line is the pathname of the log file. The
513 * second section is a list of user names; these people are all
514 * notified when subalert messages occur (if they are logged on).
515 * These lines may also have associated priority lists.
e677da31 516 *
a49a6aba
RC
517 * The configuration table will be reread by this routine if a
518 * SIGHUP signal occurs; for that reason, it is tricky about not
519 * re-opening files and closing files it will not be using.
e677da31
RC
520 */
521
522init()
523{
524 register int i;
525 register FILE *cf;
526 register struct filed *f;
527 register char *p;
528 char cline[BUFSIZ];
e677da31
RC
529 struct hostent *hp;
530 int pmask, flags;
531 long now;
a49a6aba 532 char *getpmask();
e677da31
RC
533
534 dprintf("init\n");
535
536 /* ignore interrupts during this routine */
537 signal(SIGHUP, SIG_IGN);
538
a49a6aba
RC
539 /* flush any pending output */
540 flushmsg();
541
e677da31
RC
542 /*
543 * Close all open log files.
544 */
545 for (f = Files; f < &Files[NLOGS]; f++) {
1386dfed 546 if (f->f_file >= 0)
e677da31
RC
547 (void) close(f->f_file);
548 f->f_file = -1;
549 }
550
551 /* open the configuration file */
552 if ((cf = fopen(ConfFile, "r")) == NULL) {
553 dprintf("cannot open %s\n", ConfFile);
554 f = Files;
555 if ((f->f_file = open(ctty, O_WRONLY)) >= 0) {
556 strncpy(f->f_name, ctty, sizeof(f->f_name)-1);
a49a6aba 557 f->f_pmask = mask(LOG_CRIT);
1386dfed 558 f->f_flags = F_TTY|F_MARK|F_CONS;
a49a6aba 559 untty();
e677da31
RC
560 }
561 return;
562 }
563
564 /*
565 * Foreach line in the conf table, open that file.
566 */
567 f = Files;
e677da31
RC
568 while (fgets(cline, sizeof cline, cf) != NULL) {
569 /* check for end-of-section */
570 if (cline[0] == '\n')
571 break;
572
573 /* strip off newline character */
a24c481a
RC
574 p = index(cline, '\n');
575 if (p)
576 *p = '\0';
e677da31
RC
577
578 dprintf("F: got line '%s'\n", cline);
579
580 /* extract priority mask and mark flag */
581 p = cline;
582 flags = 0;
a49a6aba 583 p = getpmask(p, &pmask);
e677da31
RC
584 if (*p == '*') {
585 p++;
586 flags |= F_MARK;
587 }
588
589 if (f >= &Files[NLOGS])
590 continue;
591
592 /* mark entry as used and update flags */
593 if (*p == '@') {
ada83039
RC
594 if (!inet)
595 continue;
e677da31 596 hp = gethostbyname(++p);
ada83039
RC
597 if (hp == NULL) {
598 char buf[100];
599
600 sprintf(buf, "unknown host %s", p);
601 errno = 0;
602 logerror(buf);
603 continue;
604 }
605 bzero(&f->f_addr, sizeof f->f_addr);
606 f->f_addr.sin_family = AF_INET;
607 f->f_addr.sin_port = port;
608 bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length);
609 f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
610 if (f->f_file < 0) {
611 logerror("socket");
612 continue;
e677da31
RC
613 }
614 flags |= F_FORW;
615 f->f_pmask = pmask;
616 f->f_flags = flags;
a49a6aba 617 dprintf("Host %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
618 f++;
619 continue;
620 }
621 strncpy(f->f_name, p, sizeof(f->f_name)-1);
1386dfed 622 if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NDELAY)) < 0) {
e677da31
RC
623 logerror(p);
624 continue;
625 }
a49a6aba 626 if (isatty(f->f_file)) {
e677da31 627 flags |= F_TTY;
a49a6aba
RC
628 untty();
629 }
1386dfed
RC
630 if (strcmp(p, ctty) == 0)
631 flags |= F_CONS;
e677da31
RC
632 f->f_pmask = pmask;
633 f->f_flags = flags;
a49a6aba 634 dprintf("File %s pmask %#x flags %#x\n", p, pmask, flags);
e677da31
RC
635 f++;
636 }
637
638 /*
639 * Read the list of users.
640 *
641 * Anyone in this list is informed directly if s/he
642 * is logged in when a high priority message comes through.
643 */
a49a6aba 644 Sumask = mask(LOG_SALERT);
e677da31
RC
645 for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) {
646 /* strip off newline */
a24c481a
RC
647 p = index(cline, '\n');
648 if (p)
649 *p = '\0';
e677da31
RC
650 dprintf("U: got line '%s'\n", cline);
651 p = cline;
652 if (isdigit(*p)) {
a49a6aba
RC
653 p = getpmask(p, &pmask);
654 Sumask |= pmask;
655 Susers[i].s_pmask = pmask;
e677da31 656 } else
a49a6aba 657 Susers[i].s_pmask = pmask = mask(LOG_SALERT);
e677da31 658 strncpy(Susers[i].s_name, p, UNAMESZ);
a49a6aba 659 dprintf("Suser %s pmask %#x\n", p, pmask);
e677da31
RC
660 }
661
662 /* zero the rest of the old superusers */
663 while (i < NSUSERS)
664 Susers[i++].s_name[0] = '\0';
665
666 /* close the configuration file */
667 (void) fclose(cf);
668
ada83039 669 dprintf("syslogd: restarted\n");
e677da31
RC
670
671 /* arrange for signal 1 to reconfigure */
672 signal(SIGHUP, init);
673}
674
675/*
676 * WALLMSG -- Write a message to the world at large
677 *
678 * Write the specified message to either the entire
679 * world, or a list of approved users.
680 */
681
ada83039 682wallmsg(pri, msg, from)
e677da31 683 int pri;
ada83039 684 char *msg, *from;
e677da31
RC
685{
686 register char *p;
687 register int i;
ada83039
RC
688 int f, flags, len, e;
689 FILE *uf;
e677da31
RC
690 struct utmp ut;
691 long now;
692 char line[MAXLINE + 100];
e677da31
RC
693
694 /* open the user login file */
ada83039
RC
695 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
696 logerror("/etc/utmp");
e677da31 697 return;
ada83039 698 }
e677da31
RC
699
700 time(&now);
e677da31 701 sprintf(line,
ada83039
RC
702 "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n",
703 from, ctime(&now), msg);
e677da31
RC
704 len = strlen(line);
705
706 /* scan the user login file */
ada83039 707 while (fread(&ut, sizeof ut, 1, uf) == 1) {
e677da31
RC
708 /* is this slot used? */
709 if (ut.ut_name[0] == '\0')
710 continue;
711
712 /* should we send the message to this user? */
713 if (pri != LOG_ALERT) {
714 for (i = 0; i < NSUSERS; i++) {
a49a6aba 715 if ((mask(pri) & Susers[i].s_pmask) == 0)
e677da31
RC
716 continue;
717 if (strncmp(Susers[i].s_name, ut.ut_name,
718 sizeof ut.ut_name) == 0)
719 goto prmsg;
720 }
721 continue;
722 }
1386dfed 723 prmsg:
e677da31
RC
724
725 /* compute the device name */
726 p = "/dev/12345678";
727 strcpyn(&p[5], ut.ut_line, UNAMESZ);
728
729 /* open the terminal */
730 f = open(p, O_WRONLY|O_NDELAY);
731 if (f < 0)
732 continue;
1386dfed
RC
733 if ((flags = fcntl(f, F_GETFL, 0)) == -1) {
734 (void) close(f);
e677da31 735 continue;
1386dfed 736 }
e677da31
RC
737 if (fcntl(f, F_SETFL, flags | FNDELAY) == -1)
738 goto oldway;
739 i = write(f, line, len);
740 e = errno;
741 (void) fcntl(f, F_SETFL, flags);
742 if (i == len || e != EWOULDBLOCK) {
743 (void) close(f);
744 continue;
745 }
746 oldway:
747 if (fork() == 0) {
748 (void) write(f, line, len);
749 exit(0);
750 }
751 (void) close(f);
752 }
753
754 /* close the user login file */
755 (void) close(uf);
756}
757
758/*
759 * Make sure every marked file gets written to periodically.
760 * Reset the alarm clock to call itself after MarkIntvl minutes.
761 */
762domark()
763{
e677da31
RC
764 char buf[40];
765 long now;
766
767 dprintf("domark\n");
768
769 time(&now);
1386dfed 770 sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now));
a49a6aba
RC
771 flushmsg();
772 logmsg(0, buf, host, NOCOPY|ISMARK);
e677da31
RC
773 alarm(MarkIntvl * 60);
774}
775
776/*
777 * Check to see if we should log this message.
778 */
779chkhost(f)
780 struct sockaddr_in *f;
781{
782 struct hostent *hp;
783 extern char *inet_ntoa();
784
785 dprintf("chkhost\n");
786
787 if (f->sin_family != AF_INET) {
788 dprintf("Malformed from address\n");
789 return (0);
790 }
791 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
792 if (hp == 0) {
793 dprintf("Host name for your address (%s) unknown\n",
794 inet_ntoa(f->sin_addr));
795 return (0);
796 }
797 strncpy(rhost, hp->h_name, sizeof rhost);
798 return (1);
799}
800
a49a6aba
RC
801/*
802 * Compare current message with previous and return true if match.
803 * Side effect is to update the time in the previous message.
804 */
805match(msg)
806 char *msg;
807{
808 register char *cp;
809
810}
811
812flushmsg()
813{
814 if (count == 0)
815 return;
816 if (count > 1)
817 sprintf(prevdate+18, "last message repeated %d times", count);
818 logmsg(prevpri, prevline, prevhost, prevflags|NOCOPY);
819 prevline[0] = '\0';
820 count = 0;
821}
822
e677da31
RC
823/*
824 * Print syslogd errors some place.
825 */
826logerror(type)
827 char *type;
828{
829 char buf[100];
ada83039 830 long now;
e677da31 831
ada83039 832 time(&now);
e677da31 833 if (errno == 0)
ada83039 834 sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type);
e677da31 835 else if ((unsigned) errno > sys_nerr)
ada83039
RC
836 sprintf(buf, "syslogd: %.24s-- %s: error %d",
837 ctime(&now), type, errno);
e677da31 838 else
ada83039
RC
839 sprintf(buf, "syslogd: %.24s-- %s: %s",
840 ctime(&now), type, sys_errlist[errno]);
e677da31 841 errno = 0;
ada83039 842 dprintf("%s\n", buf);
1386dfed 843 logmsg(LOG_ERR, buf, host, 0);
e677da31
RC
844}
845
846die()
847{
ada83039 848
a49a6aba 849 flushmsg();
ada83039 850 dprintf("syslogd: going down\n");
e677da31
RC
851 (void) unlink(logname);
852 exit(0);
853}
a49a6aba
RC
854
855/*
856 * getpmask() parses a string cp looking for a set of numbers like
857 * '1-5,8,16' and returns in *ppmask the set of bits represented by
858 * these numbers. A notation '1-5' is interpreted to mean 'turn on
859 * bits 1 through 5 inclusive'. getpmask() returns the address of
860 * first byte after the number set.
861 */
862char *
863getpmask(cp, ppmask)
864 register char *cp;
865 unsigned *ppmask;
866{
867 int count1, count2;
868 register int i;
869
870 *ppmask = 0;
871 while (isdigit(*cp)) {
872 count1 = count2 = 0;
873 do {
874 count1 = 10 * count1 + (*cp++ - '0');
875 } while (isdigit(*cp));
876 switch (*cp) {
877 case ',':
878 ++cp;
879 /* FALL THRU */
880 default:
881 *ppmask |= mask(count1);
882 continue;
883
884 case '-':
885 while (isdigit(*++cp))
886 count2 = 10 * count2 + (*cp - '0');
887 for (i = count1; i <= count2; ++i)
888 *ppmask |= mask(i);
889 if (*cp == ',')
890 ++cp;
891 continue;
892 }
893 }
894
895 return (cp);
896}