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