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