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