added LOG_SYSLOG facility for internally generated messages
[unix-history] / usr / src / usr.sbin / syslogd / syslogd.c
CommitLineData
8c5eec2f
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
e677da31 13#ifndef lint
7eefe9c1 14static char sccsid[] = "@(#)syslogd.c 5.8 (Berkeley) %G%";
8c5eec2f 15#endif not lint
e677da31 16
64b300b4
EA
17#define COMPAT /* include 4.3 Alpha compatibility */
18
e677da31
RC
19/*
20 * syslogd -- log system messages
21 *
22 * This program implements a system log. It takes a series of lines.
23 * Each line may have a priority, signified as "<n>" as
a49a6aba
RC
24 * the first characters of the line. If this is
25 * not present, a default priority is used.
e677da31
RC
26 *
27 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
28 * cause it to reread its configuration file.
29 *
30 * Defined Constants:
31 *
e677da31 32 * MAXLINE -- the maximimum line length that can be handled.
a49a6aba 33 * NLOGS -- the maximum number of simultaneous log files.
a49a6aba
RC
34 * DEFUPRI -- the default priority for user messages
35 * DEFSPRI -- the default priority for kernel messages
ada83039
RC
36 *
37 * Author: Eric Allman
a49a6aba 38 * extensive changes by Ralph Campbell
e677da31
RC
39 */
40
64b300b4 41#define NLOGS 20 /* max number of log files */
a49a6aba 42#define MAXLINE 1024 /* maximum line length */
64b300b4
EA
43#define DEFUPRI (LOG_USER|LOG_NOTICE)
44#define DEFSPRI (LOG_KERN|LOG_CRIT)
e677da31
RC
45
46#include <syslog.h>
47#include <errno.h>
48#include <stdio.h>
49#include <utmp.h>
50#include <ctype.h>
a24c481a
RC
51#include <signal.h>
52#include <sysexits.h>
53#include <strings.h>
54
e677da31 55#include <sys/types.h>
2f6a4049 56#include <sys/param.h>
e677da31
RC
57#include <sys/ioctl.h>
58#include <sys/stat.h>
84555b38 59#include <sys/wait.h>
e677da31
RC
60#include <sys/socket.h>
61#include <sys/file.h>
63cb489e 62#include <sys/msgbuf.h>
ada83039 63#include <sys/uio.h>
e677da31 64#include <sys/un.h>
64b300b4
EA
65#include <sys/time.h>
66#include <sys/resource.h>
a24c481a 67
e677da31
RC
68#include <netinet/in.h>
69#include <netdb.h>
70
64b300b4
EA
71char *LogName = "/dev/log";
72char *ConfFile = "/etc/syslog.conf";
73char *PidFile = "/etc/syslog.pid";
e677da31
RC
74char ctty[] = "/dev/console";
75
64b300b4
EA
76#define FDMASK(fd) (1 << (fd))
77
e677da31
RC
78#define dprintf if (Debug) printf
79
64b300b4
EA
80#define UNAMESZ 8 /* length of a login name */
81#define MAXUNAMES 20 /* maximum number of user names */
82#define MAXFNAME 200 /* max file pathname length */
e677da31 83
64b300b4 84#define NOPRI 0x10 /* the "no priority" priority */
a49a6aba 85
8a7154b1
RC
86/*
87 * Flags to logmsg().
88 */
64b300b4
EA
89
90#define IGN_CONS 0x001 /* don't print on console */
91#define SYNC_FILE 0x002 /* do fsync on file after printing */
92#define NOCOPY 0x004 /* don't suppress duplicate messages */
93#define ADDDATE 0x008 /* add a date to the message */
8a7154b1 94
e677da31
RC
95/*
96 * This structure represents the files that will have log
97 * copies printed.
98 */
99
100struct filed {
64b300b4
EA
101 short f_type; /* entry type, see below */
102 short f_file; /* file descriptor */
103 u_char f_pmask[LOG_NFACILITIES]; /* priority mask */
104 union {
486e5830 105 char f_uname[MAXUNAMES][UNAMESZ+1];
64b300b4
EA
106 struct
107 {
74440133 108 char f_hname[MAXHOSTNAMELEN+1];
64b300b4
EA
109 struct sockaddr_in f_addr;
110 } f_forw; /* forwarding address */
111 char f_fname[MAXFNAME];
112 } f_un;
e677da31
RC
113};
114
64b300b4
EA
115/* values for f_type */
116#define F_UNUSED 0 /* unused entry */
117#define F_FILE 1 /* regular file */
118#define F_TTY 2 /* terminal */
119#define F_CONSOLE 3 /* console terminal */
120#define F_FORW 4 /* remote machine */
121#define F_USERS 5 /* list of users */
122#define F_WALL 6 /* everyone logged on */
123
124char *TypeNames[7] = {
125 "UNUSED", "FILE", "TTY", "CONSOLE",
126 "FORW", "USERS", "WALL"
e677da31
RC
127};
128
64b300b4 129struct filed Files[NLOGS];
e677da31
RC
130
131int Debug; /* debug flag */
74440133 132char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
64b300b4
EA
133int InetInuse = 0; /* non-zero if INET sockets are being used */
134int LogPort; /* port number for INET connections */
135char PrevLine[MAXLINE + 1]; /* copy of last line to supress repeats */
74440133 136char PrevHost[MAXHOSTNAMELEN+1]; /* previous host */
64b300b4
EA
137int PrevFlags;
138int PrevPri;
139int PrevCount = 0; /* number of times seen */
140int Initialized = 0; /* set when we have initialized ourselves */
e677da31
RC
141
142extern int errno, sys_nerr;
143extern char *sys_errlist[];
a49a6aba 144extern char *ctime(), *index();
e677da31 145
64b300b4
EA
146#ifdef COMPAT
147int CompatMode = 0; /* run in compatibility mode */
148int CompatCodes[32] = {
149 LOG_USER|LOG_ALERT, /* 0 -- undefined */
150 /* kernel priorities */
151 LOG_KERN|LOG_EMERG, /* KERN_EMERG */
152 LOG_KERN|LOG_ALERT, /* KERN_ALERT */
153 LOG_KERN|LOG_CRIT, /* KERN_ERR */
154 LOG_KERN|LOG_ERR, /* KERN_FAIL */
155 LOG_KERN|LOG_WARNING, /* KERN_RECOV */
156 LOG_KERN|LOG_INFO, /* KERN_INFO */
157 /* user abnormal conditions priorities */
158 LOG_USER|LOG_EMERG, /* LOG_EMERG */
159 LOG_USER|LOG_ALERT, /* LOG_ALERT */
160 LOG_USER|LOG_CRIT, /* LOG_CRIT */
161 LOG_USER|LOG_ERR, /* LOG_ERR */
162 LOG_USER|LOG_ERR, /* LOG_ERR */
163 LOG_USER|LOG_WARNING, /* LOG_WARNING */
164 /* user priorities */
165 LOG_USER|LOG_ALERT, /* LOG_SALERT */
166 LOG_AUTH|LOG_NOTICE, /* LOG_SECURITY */
167 LOG_USER|LOG_INFO, /* LOG_FIXED */
168 LOG_MAIL|LOG_ERR, /* LOG_MAIL */
169 LOG_DAEMON|LOG_ERR, /* LOG_REJECT */
170 LOG_USER|LOG_NOTICE, /* LOG_NOTICE */
171 /* user information priorities */
172 LOG_USER|LOG_INFO, /* LOG_INFO */
173 LOG_LOCAL1|LOG_INFO, /* LOG_INFO1 */
174 LOG_LOCAL2|LOG_INFO, /* LOG_INFO2 */
175 LOG_LOCAL3|LOG_INFO, /* LOG_INFO3 */
176 LOG_LOCAL4|LOG_INFO, /* LOG_INFO4 */
177 LOG_LOCAL5|LOG_INFO, /* LOG_INFO5 */
178 /* user debug/local priorities */
179 LOG_USER|LOG_DEBUG, /* LOG_DEBUG */
180 LOG_LOCAL1|LOG_DEBUG, /* LOG_LOCAL1 */
181 LOG_LOCAL2|LOG_DEBUG, /* LOG_LOCAL2 */
182 LOG_LOCAL3|LOG_DEBUG, /* LOG_LOCAL3 */
183 LOG_LOCAL4|LOG_DEBUG, /* LOG_LOCAL4 */
184 LOG_LOCAL5|LOG_DEBUG, /* LOG_LOCAL5 */
185 LOG_LOCAL6|LOG_DEBUG, /* LOG_LOCAL6 */
186};
187#endif COMPAT
188
e677da31
RC
189main(argc, argv)
190 int argc;
191 char **argv;
192{
193 register int i;
194 register char *p;
84555b38 195 int funix, finet, inetm, fklog, klogm, len;
e677da31
RC
196 struct sockaddr_un sun, fromunix;
197 struct sockaddr_in sin, frominet;
198 FILE *fp;
63cb489e 199 char line[MSG_BSIZE + 1];
84555b38 200 extern int die(), domark(), reapchild();
e677da31 201
e677da31
RC
202 while (--argc > 0) {
203 p = *++argv;
a49a6aba
RC
204 if (p[0] != '-')
205 usage();
206 switch (p[1]) {
a49a6aba
RC
207 case 'f': /* configuration file */
208 if (p[2] != '\0')
209 ConfFile = &p[2];
210 break;
211
212 case 'd': /* debug */
213 Debug++;
214 break;
215
64b300b4
EA
216#ifdef COMPAT
217 case 'C': /* run in compat mode */
218 CompatMode++;
219 break;
220#endif COMPAT
221
a49a6aba
RC
222 case 'p': /* path */
223 if (p[2] != '\0')
64b300b4 224 LogName = &p[2];
a49a6aba
RC
225 break;
226
227 default:
228 usage();
e677da31
RC
229 }
230 }
231
232 if (!Debug) {
233 if (fork())
234 exit(0);
235 for (i = 0; i < 10; i++)
236 (void) close(i);
237 (void) open("/", 0);
238 (void) dup2(0, 1);
239 (void) dup2(0, 2);
a49a6aba 240 untty();
84555b38
RC
241 } else
242 setlinebuf(stdout);
243
64b300b4 244 (void) signal(SIGTERM, die);
67f1f408
EA
245 (void) signal(SIGINT, Debug ? die : SIG_IGN);
246 (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
64b300b4
EA
247 (void) signal(SIGCHLD, reapchild);
248 (void) unlink(LogName);
249
250 sun.sun_family = AF_UNIX;
251 (void) strncpy(sun.sun_path, LogName, sizeof sun.sun_path);
252 (void) gethostname(LocalHostName, sizeof LocalHostName);
e677da31 253 funix = socket(AF_UNIX, SOCK_DGRAM, 0);
64b300b4 254 if (funix < 0 || bind(funix, (struct sockaddr *) &sun,
84555b38 255 sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0 ||
64b300b4
EA
256 chmod(LogName, 0666) < 0) {
257 (void) sprintf(line, "cannot create %s", LogName);
258 logerror(line);
259 dprintf("cannot create %s (%d)\n", LogName, errno);
260 die(0);
e677da31 261 }
e677da31
RC
262 finet = socket(AF_INET, SOCK_DGRAM, 0);
263 if (finet >= 0) {
264 struct servent *sp;
265
266 sp = getservbyname("syslog", "udp");
267 if (sp == NULL) {
268 errno = 0;
269 logerror("syslog/udp: unknown service");
64b300b4 270 die(0);
e677da31
RC
271 }
272 sin.sin_family = AF_INET;
64b300b4
EA
273 sin.sin_port = LogPort = sp->s_port;
274 if (bind(finet, &sin, sizeof(sin)) < 0) {
e677da31 275 logerror("bind");
64b300b4
EA
276 if (!Debug)
277 die(0);
278 } else {
279 inetm = FDMASK(finet);
280 InetInuse = 1;
e677da31 281 }
e677da31 282 }
84555b38 283 if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
64b300b4 284 klogm = FDMASK(fklog);
84555b38 285 else {
63cb489e 286 dprintf("can't open /dev/klog (%d)\n", errno);
a49a6aba
RC
287 klogm = 0;
288 }
e677da31
RC
289
290 /* tuck my process id away */
64b300b4 291 fp = fopen(PidFile, "w");
e677da31
RC
292 if (fp != NULL) {
293 fprintf(fp, "%d\n", getpid());
64b300b4 294 (void) fclose(fp);
e677da31
RC
295 }
296
297 dprintf("off & running....\n");
298
e677da31 299 init();
64b300b4 300 (void) signal(SIGHUP, init);
454c883a 301
e677da31 302 for (;;) {
64b300b4 303 int nfds, readfds = FDMASK(funix) | inetm | klogm;
e677da31 304
64b300b4 305 errno = 0;
84555b38 306 dprintf("readfds = %#x\n", readfds, funix, finet, fklog);
64b300b4
EA
307 nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
308 (fd_set *) NULL, (struct timeval *) NULL);
a49a6aba 309 dprintf("got a message (%d, %#x)\n", nfds, readfds);
e677da31
RC
310 if (nfds == 0)
311 continue;
312 if (nfds < 0) {
64b300b4
EA
313 if (errno != EINTR)
314 logerror("select");
e677da31
RC
315 continue;
316 }
a49a6aba 317 if (readfds & klogm) {
84555b38 318 i = read(fklog, line, sizeof(line) - 1);
8a7154b1
RC
319 if (i > 0) {
320 line[i] = '\0';
321 printsys(line);
a49a6aba 322 } else if (i < 0 && errno != EINTR) {
84555b38
RC
323 logerror("klog");
324 fklog = -1;
a49a6aba
RC
325 klogm = 0;
326 }
8a7154b1 327 }
64b300b4 328 if (readfds & FDMASK(funix)) {
e677da31 329 len = sizeof fromunix;
64b300b4
EA
330 i = recvfrom(funix, line, MAXLINE, 0,
331 (struct sockaddr *) &fromunix, &len);
a24c481a
RC
332 if (i > 0) {
333 line[i] = '\0';
64b300b4 334 printline(LocalHostName, line);
a24c481a 335 } else if (i < 0 && errno != EINTR)
64b300b4 336 logerror("recvfrom unix");
a24c481a 337 }
84555b38 338 if (readfds & inetm) {
e677da31
RC
339 len = sizeof frominet;
340 i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len);
64b300b4
EA
341 if (i > 0) {
342 extern char *cvthname();
343
a24c481a 344 line[i] = '\0';
64b300b4 345 printline(cvthname(&frominet), line);
a24c481a 346 } else if (i < 0 && errno != EINTR)
64b300b4 347 logerror("recvfrom inet");
a24c481a 348 }
e677da31
RC
349 }
350}
351
a49a6aba
RC
352usage()
353{
64b300b4 354 fprintf(stderr, "usage: syslogd [-d] [-ppath] [-fconffile]\n");
a49a6aba
RC
355 exit(1);
356}
357
358untty()
359{
360 int i;
361
362 if (!Debug) {
363 i = open("/dev/tty", O_RDWR);
364 if (i >= 0) {
64b300b4 365 (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
a49a6aba
RC
366 (void) close(i);
367 }
368 }
369}
370
e677da31
RC
371/*
372 * Take a raw input line, decode the message, and print the message
373 * on the appropriate log files.
374 */
375
64b300b4
EA
376printline(hname, msg)
377 char *hname;
e677da31
RC
378 char *msg;
379{
380 register char *p, *q;
381 register int c;
63cb489e 382 char line[MAXLINE + 1];
e677da31
RC
383 int pri;
384
385 /* test for special codes */
a49a6aba 386 pri = DEFUPRI;
e677da31 387 p = msg;
a49a6aba
RC
388 if (*p == '<') {
389 pri = 0;
390 while (isdigit(*++p))
391 pri = 10 * pri + (*p - '0');
392 if (*p == '>')
393 ++p;
64b300b4 394 if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
a49a6aba 395 pri = DEFUPRI;
e677da31
RC
396 }
397
64b300b4
EA
398 /* don't allow users to log kernel messages */
399 if ((pri & LOG_PRIMASK) == LOG_KERN)
400 pri |= LOG_USER;
401
e677da31 402 q = line;
64b300b4
EA
403#ifdef COMPAT
404 if (CompatMode) {
405 register char *lp = index(p, ':');
406
407 if (lp && lp[1] == ' ' && lp[17] == '-' && lp[18] == '-') {
408 /*
409 * Old format message
410 */
411 dprintf("mapping <%d> to <%d>\n", pri, CompatCodes[pri]);
412 pri = CompatCodes[pri];
413 (void) strncpy(q, lp + 2, 15);
414 q += 15;
415 *q++ = ' ';
416 (void) strncpy(q, p, lp - p + 1);
417 q += lp - p + 1;
418 p = lp + 19;
419 }
420 }
421#endif COMPAT
422
e677da31 423 while ((c = *p++ & 0177) != '\0' && c != '\n' &&
63cb489e 424 q < &line[sizeof(line) - 1]) {
e677da31
RC
425 if (iscntrl(c)) {
426 *q++ = '^';
427 *q++ = c ^ 0100;
428 } else
429 *q++ = c;
430 }
e677da31
RC
431 *q = '\0';
432
64b300b4 433 logmsg(pri, line, hname, 0);
e677da31
RC
434}
435
63cb489e
RC
436/*
437 * Take a raw input line from /dev/klog, split and format similar to syslog().
438 */
439
440printsys(msg)
441 char *msg;
442{
443 register char *p, *q;
444 register int c;
445 char line[MAXLINE + 1];
8a7154b1 446 int pri, flags;
a49a6aba 447 char *lp;
64b300b4 448 time_t now;
63cb489e 449
64b300b4
EA
450 (void) time(&now);
451 (void) sprintf(line, "%.15s vmunix: ", ctime(&now) + 4);
a49a6aba 452 lp = line + strlen(line);
63cb489e 453 for (p = msg; *p != '\0'; ) {
8a7154b1 454 flags = SYNC_FILE; /* fsync file after write */
a49a6aba
RC
455 pri = DEFSPRI;
456 if (*p == '<') {
457 pri = 0;
458 while (isdigit(*++p))
459 pri = 10 * pri + (*p - '0');
460 if (*p == '>')
461 ++p;
64b300b4 462 if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
a49a6aba 463 pri = DEFSPRI;
64b300b4
EA
464#ifdef COMPAT
465 else if (CompatMode) {
466 dprintf("mapping <%d> to <%d>\n", pri, CompatCodes[pri]);
467 pri = CompatCodes[pri];
468 }
469#endif COMPAT
8a7154b1
RC
470 } else {
471 /* kernel printf's come out on console */
472 flags |= IGN_CONS;
473 }
a49a6aba
RC
474 q = lp;
475 while (*p != '\0' && (c = *p++) != '\n' &&
476 q < &line[MAXLINE])
63cb489e
RC
477 *q++ = c;
478 *q = '\0';
64b300b4 479 logmsg(pri, line, LocalHostName, flags);
63cb489e
RC
480 }
481}
482
e677da31
RC
483/*
484 * Log a message to the appropriate log files, users, etc. based on
485 * the priority.
486 */
487
8a7154b1 488logmsg(pri, msg, from, flags)
64b300b4
EA
489 int pri;
490 char *msg, *from;
491 int flags;
e677da31
RC
492{
493 char line[MAXLINE + 1];
494 register struct filed *f;
495 register int l;
64b300b4
EA
496 int fac, prilev;
497 struct iovec iov[6];
ada83039 498 register struct iovec *v = iov;
84555b38
RC
499 int omask;
500
64b300b4
EA
501 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);
502
7eefe9c1 503 omask = sigblock(sigmask(SIGHUP));
ada83039 504
64b300b4
EA
505 /*
506 * Check to see if msg looks non-standard.
507 */
508 if (!(flags & ADDDATE) && (strlen(msg) < 16 ||
509 msg[3] != ' ' || msg[6] != ' ' ||
510 msg[9] != ':' || msg[12] != ':' || msg[15] != ' '))
511 flags |= ADDDATE;
a49a6aba 512
64b300b4
EA
513 if ((flags & NOCOPY) == 0) {
514 if (flags & ADDDATE)
a49a6aba 515 flushmsg();
64b300b4 516 else if (!strcmp(msg + 16, PrevLine + 16)) {
a49a6aba 517 /* we found a match, update the time */
64b300b4
EA
518 (void) strncpy(PrevLine, msg, 15);
519 PrevCount++;
2af4dea2 520 (void) sigsetmask(omask);
a49a6aba
RC
521 return;
522 } else {
523 /* new line, save it */
524 flushmsg();
64b300b4
EA
525 (void) strcpy(PrevLine, msg);
526 (void) strcpy(PrevHost, from);
527 PrevFlags = flags;
528 PrevPri = pri;
a49a6aba
RC
529 }
530 }
531
64b300b4
EA
532 if (flags & ADDDATE) {
533 time_t now;
534
535 (void) time(&now);
536 v->iov_base = ctime(&now) + 4;
537 } else
538 v->iov_base = msg;
539 v->iov_len = 15;
540 v++;
541 v->iov_base = " ";
542 v->iov_len = 1;
543 v++;
ada83039
RC
544 v->iov_base = from;
545 v->iov_len = strlen(v->iov_base);
546 v++;
547 v->iov_base = " ";
548 v->iov_len = 1;
549 v++;
64b300b4
EA
550 if (flags & ADDDATE)
551 v->iov_base = msg;
552 else
553 v->iov_base = msg + 16;
ada83039
RC
554 v->iov_len = strlen(v->iov_base);
555 v++;
64b300b4
EA
556
557 /* extract facility and priority level */
558 fac = (pri & LOG_FACMASK) >> 3;
559 prilev = pri & LOG_PRIMASK;
560
e677da31 561 /* log the message to the particular outputs */
64b300b4
EA
562 if (!Initialized) {
563 int cfd = open(ctty, O_WRONLY);
564
565 if (cfd >= 0) {
566 v->iov_base = "\r\n";
567 v->iov_len = 2;
568 (void) writev(cfd, iov, 6);
569 (void) close(cfd);
570 }
67f1f408 571 untty();
7eefe9c1 572 (void) sigsetmask(omask);
64b300b4
EA
573 return;
574 }
e677da31 575 for (f = Files; f < &Files[NLOGS]; f++) {
64b300b4
EA
576 /* skip messages that are incorrect priority */
577 if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
a49a6aba 578 continue;
64b300b4
EA
579
580 dprintf("Logging to %s", TypeNames[f->f_type]);
581 switch (f->f_type) {
582 case F_UNUSED:
583 dprintf("\n");
584 break;
585
586 case F_FORW:
587 dprintf(" %s\n", f->f_un.f_forw.f_hname);
588 (void) sprintf(line, "<%d>%.15s %s", pri, v[0].iov_base,
589 v[4].iov_base);
e677da31
RC
590 l = strlen(line);
591 if (l > MAXLINE)
592 l = MAXLINE;
593 if (sendto(f->f_file, line, l, 0,
64b300b4
EA
594 &f->f_un.f_forw.f_addr,
595 sizeof f->f_un.f_forw.f_addr) != l) {
8a7154b1
RC
596 int e = errno;
597 (void) close(f->f_file);
64b300b4 598 f->f_type = F_UNUSED;
8a7154b1 599 errno = e;
e677da31 600 logerror("sendto");
8a7154b1 601 }
e677da31
RC
602 break;
603
64b300b4
EA
604 case F_CONSOLE:
605 if (flags & IGN_CONS) {
606 dprintf(" (ignored)\n");
607 break;
ada83039 608 }
64b300b4
EA
609
610 case F_TTY:
611 case F_FILE:
612 dprintf(" %s\n", f->f_un.f_fname);
613 if (f->f_type != F_FILE) {
614 v->iov_base = "\r\n";
615 v->iov_len = 2;
616 } else {
617 v->iov_base = "\n";
618 v->iov_len = 1;
e677da31 619 }
64b300b4
EA
620 if (writev(f->f_file, iov, 6) < 0) {
621 int e = errno;
622 (void) close(f->f_file);
623 /*
624 * Check for EBADF on TTY's due to vhangup() XXX
625 */
626 if (e == EBADF && f->f_type != F_FILE) {
627 f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
628 if (f->f_file < 0) {
629 f->f_type = F_UNUSED;
630 logerror(f->f_un.f_fname);
631 }
632 } else {
633 f->f_type = F_UNUSED;
634 errno = e;
635 logerror(f->f_un.f_fname);
636 }
637 } else if (flags & SYNC_FILE)
638 (void) fsync(f->f_file);
639 break;
e677da31 640
64b300b4
EA
641 case F_USERS:
642 case F_WALL:
643 dprintf("\n");
644 v->iov_base = "\r\n";
645 v->iov_len = 2;
646 wallmsg(f, iov);
647 break;
648 }
e677da31
RC
649 }
650
64b300b4 651 (void) sigsetmask(omask);
e677da31
RC
652}
653
64b300b4 654
e677da31
RC
655/*
656 * WALLMSG -- Write a message to the world at large
657 *
658 * Write the specified message to either the entire
659 * world, or a list of approved users.
660 */
661
64b300b4
EA
662wallmsg(f, iov)
663 register struct filed *f;
664 struct iovec *iov;
e677da31
RC
665{
666 register char *p;
667 register int i;
64b300b4 668 int ttyf, len;
ada83039 669 FILE *uf;
64b300b4 670 static int reenter = 0;
e677da31 671 struct utmp ut;
64b300b4
EA
672 time_t now;
673 char greetings[200];
674
675 if (reenter++)
676 return;
e677da31
RC
677
678 /* open the user login file */
ada83039
RC
679 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
680 logerror("/etc/utmp");
64b300b4 681 reenter = 0;
e677da31 682 return;
ada83039 683 }
e677da31 684
64b300b4
EA
685 (void) time(&now);
686 (void) sprintf(greetings,
687 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
688 iov[2].iov_base, ctime(&now));
689 len = strlen(greetings);
e677da31
RC
690
691 /* scan the user login file */
64b300b4 692 while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
e677da31
RC
693 /* is this slot used? */
694 if (ut.ut_name[0] == '\0')
695 continue;
696
697 /* should we send the message to this user? */
64b300b4
EA
698 if (f->f_type == F_USERS) {
699 for (i = 0; i < MAXUNAMES; i++) {
700 if (!f->f_un.f_uname[i][0]) {
701 i = MAXUNAMES;
702 break;
703 }
704 if (strncmp(f->f_un.f_uname[i], ut.ut_name,
84555b38 705 UNAMESZ) == 0)
64b300b4 706 break;
e677da31 707 }
64b300b4
EA
708 if (i >= MAXUNAMES)
709 continue;
e677da31 710 }
e677da31
RC
711
712 /* compute the device name */
713 p = "/dev/12345678";
714 strcpyn(&p[5], ut.ut_line, UNAMESZ);
715
84555b38
RC
716 /*
717 * Might as well fork instead of using nonblocking I/O
718 * and doing notty().
719 */
e677da31 720 if (fork() == 0) {
64b300b4
EA
721 if (f->f_type == F_WALL) {
722 iov[0].iov_base = greetings;
723 iov[0].iov_len = len;
724 }
725 (void) signal(SIGALRM, SIG_DFL);
726 (void) alarm(30);
84555b38 727 /* open the terminal */
64b300b4
EA
728 ttyf = open(p, O_WRONLY);
729 if (ttyf >= 0)
730 (void) writev(ttyf, iov, 6);
e677da31
RC
731 exit(0);
732 }
64b300b4
EA
733 /* avoid having them all pile up at once */
734 sleep(1);
e677da31 735 }
e677da31 736 /* close the user login file */
84555b38 737 (void) fclose(uf);
64b300b4 738 reenter = 0;
84555b38
RC
739}
740
741reapchild()
742{
743 union wait status;
744
64b300b4 745 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
84555b38 746 ;
e677da31
RC
747}
748
749/*
64b300b4 750 * Return a printable representation of a host address.
e677da31 751 */
64b300b4
EA
752char *
753cvthname(f)
e677da31
RC
754 struct sockaddr_in *f;
755{
756 struct hostent *hp;
757 extern char *inet_ntoa();
758
64b300b4 759 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
e677da31
RC
760
761 if (f->sin_family != AF_INET) {
762 dprintf("Malformed from address\n");
64b300b4 763 return ("???");
e677da31
RC
764 }
765 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
766 if (hp == 0) {
767 dprintf("Host name for your address (%s) unknown\n",
768 inet_ntoa(f->sin_addr));
64b300b4 769 return (inet_ntoa(f->sin_addr));
e677da31 770 }
64b300b4 771 return (hp->h_name);
e677da31
RC
772}
773
a49a6aba
RC
774flushmsg()
775{
64b300b4 776 if (PrevCount == 0)
a49a6aba 777 return;
64b300b4
EA
778 if (PrevCount > 1)
779 (void) sprintf(PrevLine+16, "last message repeated %d times", PrevCount);
780 PrevCount = 0;
781 logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY);
782 PrevLine[0] = '\0';
a49a6aba
RC
783}
784
e677da31
RC
785/*
786 * Print syslogd errors some place.
787 */
788logerror(type)
789 char *type;
790{
791 char buf[100];
792
793 if (errno == 0)
64b300b4 794 (void) sprintf(buf, "syslogd: %s", type);
e677da31 795 else if ((unsigned) errno > sys_nerr)
64b300b4 796 (void) sprintf(buf, "syslogd: %s: error %d", type, errno);
e677da31 797 else
64b300b4 798 (void) sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
e677da31 799 errno = 0;
ada83039 800 dprintf("%s\n", buf);
64b300b4 801 logmsg(LOG_DAEMON|LOG_ERR, buf, LocalHostName, ADDDATE);
e677da31
RC
802}
803
64b300b4 804die(sig)
e677da31 805{
64b300b4 806 char buf[100];
ada83039 807
64b300b4 808 dprintf("syslogd: going down on signal %d\n", sig);
a49a6aba 809 flushmsg();
64b300b4
EA
810 (void) sprintf(buf, "going down on signal %d", sig);
811 logerror(buf);
812 (void) unlink(LogName);
e677da31
RC
813 exit(0);
814}
a49a6aba
RC
815
816/*
64b300b4 817 * INIT -- Initialize syslogd from configuration table
a49a6aba 818 */
64b300b4
EA
819
820init()
a49a6aba 821{
a49a6aba 822 register int i;
64b300b4
EA
823 register FILE *cf;
824 register struct filed *f;
825 register char *p;
826 char cline[BUFSIZ];
a49a6aba 827
64b300b4
EA
828 dprintf("init\n");
829
830 /* flush any pending output */
831 flushmsg();
832
833 /*
834 * Close all open log files.
835 */
836 for (f = Files; f < &Files[NLOGS]; f++) {
837 if (f->f_type == F_FILE || f->f_type == F_TTY)
838 (void) close(f->f_file);
839 f->f_type = F_UNUSED;
840 }
841
842 /* open the configuration file */
843 if ((cf = fopen(ConfFile, "r")) == NULL) {
844 dprintf("cannot open %s\n", ConfFile);
845 cfline("*.ERR\t/dev/console", &Files[0]);
846 cfline("*.PANIC\t*", &Files[1]);
847 return;
848 }
849
850 /*
851 * Foreach line in the conf table, open that file.
852 */
853 f = Files;
854 while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) {
855 /* check for end-of-section */
856 if (cline[0] == '\n' || cline[0] == '#')
a49a6aba
RC
857 continue;
858
64b300b4
EA
859 /* strip off newline character */
860 p = index(cline, '\n');
861 if (p)
862 *p = '\0';
863
864 cfline(cline, f++);
865 }
866
867 /* close the configuration file */
868 (void) fclose(cf);
869
870 Initialized = 1;
871
872 if (Debug) {
873 for (f = Files; f < &Files[NLOGS]; f++) {
874 for (i = 0; i < LOG_NFACILITIES; i++)
875 if (f->f_pmask[i] == NOPRI)
876 printf("X ");
877 else
878 printf("%d ", f->f_pmask[i]);
879 printf("%s: ", TypeNames[f->f_type]);
880 switch (f->f_type) {
881 case F_FILE:
882 case F_TTY:
883 case F_CONSOLE:
884 printf("%s", f->f_un.f_fname);
885 break;
886
887 case F_FORW:
888 printf("%s", f->f_un.f_forw.f_hname);
889 break;
890
891 case F_USERS:
892 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
893 printf("%s, ", f->f_un.f_uname[i]);
894 break;
895 }
896 printf("\n");
897 }
898 }
899
900 logmsg(LOG_DAEMON|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
901 dprintf("syslogd: restarted\n");
902}
903
904/*
905 * Crack a configuration file line
906 */
907
908struct code {
909 char *c_name;
910 int c_val;
911};
912
913struct code PriNames[] = {
914 "panic", LOG_EMERG,
915 "emerg", LOG_EMERG,
916 "alert", LOG_ALERT,
917 "crit", LOG_CRIT,
918 "err", LOG_ERR,
919 "error", LOG_ERR,
920 "warn", LOG_WARNING,
921 "warning", LOG_WARNING,
922 "notice", LOG_NOTICE,
923 "info", LOG_INFO,
924 "debug", LOG_DEBUG,
925 NULL, -1
926};
927
928struct code FacNames[] = {
929 "kern", LOG_KERN,
930 "user", LOG_USER,
931 "mail", LOG_MAIL,
623d5539 932 "daemon", LOG_DAEMON,
64b300b4
EA
933 "auth", LOG_AUTH,
934 "security", LOG_AUTH,
935 "local0", LOG_LOCAL0,
936 "local1", LOG_LOCAL1,
937 "local2", LOG_LOCAL2,
938 "local3", LOG_LOCAL3,
939 "local4", LOG_LOCAL4,
940 "local5", LOG_LOCAL5,
941 "local6", LOG_LOCAL6,
942 "local7", LOG_LOCAL7,
943 NULL, -1
944};
945
946cfline(line, f)
947 char *line;
948 register struct filed *f;
949{
950 register char *p;
951 register char *q;
952 register int i;
953 char *bp;
954 int pri;
955 struct hostent *hp;
956 char buf[MAXLINE];
957
958 dprintf("cfline(%s)\n", line);
959
960 /* clear out file entry */
961 bzero((char *) f, sizeof *f);
962 for (i = 0; i < LOG_NFACILITIES; i++)
963 f->f_pmask[i] = NOPRI;
964
965 /* scan through the list of selectors */
966 for (p = line; *p && *p != '\t';) {
967
968 /* find the end of this facility name list */
969 for (q = p; *q && *q != '\t' && *q++ != '.'; )
a49a6aba 970 continue;
64b300b4
EA
971
972 /* collect priority name */
973 for (bp = buf; *q && !index("\t,;", *q); )
974 *bp++ = *q++;
975 *bp = '\0';
976
977 /* skip cruft */
978 while (index(", ;", *q))
979 q++;
980
981 /* decode priority name */
982 pri = decode(buf, PriNames);
983 if (pri < 0) {
984 char xbuf[200];
985
986 (void) sprintf(xbuf, "unknown priority name \"%s\"", buf);
987 logerror(xbuf);
988 return;
989 }
990
991 /* scan facilities */
992 while (*p && !index("\t.;", *p)) {
993 int i;
994
995 for (bp = buf; *p && !index("\t,;.", *p); )
996 *bp++ = *p++;
997 *bp = '\0';
998 if (*buf == '*')
999 for (i = 0; i < LOG_NFACILITIES; i++)
1000 f->f_pmask[i] = pri;
1001 else {
1002 i = decode(buf, FacNames);
1003 if (i < 0) {
1004 char xbuf[200];
1005
1006 (void) sprintf(xbuf, "unknown facility name \"%s\"", buf);
1007 logerror(xbuf);
1008 return;
1009 }
1010 f->f_pmask[i >> 3] = pri;
1011 }
1012 while (*p == ',' || *p == ' ')
1013 p++;
1014 }
1015
1016 p = q;
1017 }
1018
1019 /* skip to action part */
1020 while (*p == '\t')
1021 p++;
1022
1023 switch (*p)
1024 {
1025 case '@':
1026 if (!InetInuse)
1027 break;
1028 (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1029 hp = gethostbyname(p);
1030 if (hp == NULL) {
1031 char buf[100];
1032
1033 (void) sprintf(buf, "unknown host %s", p);
1034 errno = 0;
1035 logerror(buf);
1036 break;
1037 }
1038 bzero((char *) &f->f_un.f_forw.f_addr,
1039 sizeof f->f_un.f_forw.f_addr);
1040 f->f_un.f_forw.f_addr.sin_family = AF_INET;
1041 f->f_un.f_forw.f_addr.sin_port = LogPort;
1042 bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
1043 f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
1044 if (f->f_file < 0) {
1045 logerror("socket");
1046 break;
1047 }
1048 f->f_type = F_FORW;
1049 break;
1050
1051 case '/':
1052 (void) strcpy(f->f_un.f_fname, p);
1053 if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
1054 logerror(p);
1055 break;
1056 }
1057 if (isatty(f->f_file)) {
1058 f->f_type = F_TTY;
1059 untty();
a49a6aba 1060 }
64b300b4
EA
1061 else
1062 f->f_type = F_FILE;
1063 if (strcmp(p, ctty) == 0)
1064 f->f_type = F_CONSOLE;
1065 break;
1066
1067 case '*':
1068 f->f_type = F_WALL;
1069 break;
1070
1071 default:
1072 for (i = 0; i < MAXUNAMES && *p; i++) {
1073 for (q = p; *q && *q != ','; )
1074 q++;
1075 (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
1076 if ((q - p) > UNAMESZ)
1077 f->f_un.f_uname[i][UNAMESZ] = '\0';
1078 else
1079 f->f_un.f_uname[i][q - p] = '\0';
1080 while (*q == ',' || *q == ' ')
1081 q++;
1082 p = q;
1083 }
1084 f->f_type = F_USERS;
1085 break;
a49a6aba 1086 }
64b300b4
EA
1087}
1088
1089
1090/*
1091 * Decode a symbolic name to a numeric value
1092 */
1093
1094decode(name, codetab)
1095 char *name;
1096 struct code *codetab;
1097{
1098 register struct code *c;
1099 register char *p;
1100 char buf[40];
1101
1102 if (isdigit(*name))
1103 return (atoi(name));
1104
1105 (void) strcpy(buf, name);
1106 for (p = buf; *p; p++)
1107 if (isupper(*p))
1108 *p = tolower(*p);
1109 for (c = codetab; c->c_name; c++)
1110 if (!strcmp(buf, c->c_name))
1111 return (c->c_val);
a49a6aba 1112
64b300b4 1113 return (-1);
a49a6aba 1114}