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