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