BSD 4_4 release
[unix-history] / usr / src / contrib / news / inn / syslog / syslogd.c
CommitLineData
ad787160
C
1/* $Revision: 1.9 $
2** This file has been modified to get it to compile more easily
3** on pre-4.4BSD (e.g., SysVr4 :-) systems. Rich $alz, June 1991.
4*/
5
6 /* change these three if you must keep running an old syslog. */
7#define _PATH_LOGFILE "/dev/log"
8#define _PATH_LOGCONF "/etc/syslog.conf"
9#define _PATH_LOGPID "/etc/syslog.pid"
10
11 /* #define this to enable verbose debugging of all messages. */
12#undef VERBOSE_DEBUG
13 /* #define this to line to listen on the INET port. */
14#undef DO_INET_SOCKET
15 /* #undef this to not read kernel syslog messages. */
16#define _PATH_KLOG "/dev/klog"
17#undef _PATH_KLOG
18 /* set this depending on what your sighandler is. */
19 /* =()<#define SIGHANDLER @<SIGHANDLER>@>()= */
20#define SIGHANDLER void
21 /* if you need various BSD functions, set this. */
22#define NEED_BZERO_ETC
23
24 /* Use "union wait" instead of int? */
25 /* =()<#define @<USE_UNION_WAIT>@_USE_UNION_WAIT>()= */
26#define DONT_USE_UNION_WAIT
27#if defined(DO_USE_UNION_WAIT)
28#define WAITVALUE union wait
29#else
30#define WAITVALUE int
31#endif /* defined(DO_USE_UNION_WAIT) */
32
8c5eec2f 33/*
e15840af
KB
34 * Copyright (c) 1983, 1988 Regents of the University of California.
35 * All rights reserved.
36 *
1c15e888
C
37 * Redistribution and use in source and binary forms are permitted provided
38 * that: (1) source distributions retain this entire copyright notice and
39 * comment, and (2) distributions including binaries display the following
40 * acknowledgement: ``This product includes software developed by the
41 * University of California, Berkeley and its contributors'' in the
42 * documentation or other materials provided with the distribution and in
43 * all advertising materials mentioning features or use of this software.
44 * Neither the name of the University nor the names of its contributors may
45 * be used to endorse or promote products derived from this software without
46 * specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
48 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
8c5eec2f
DF
50 */
51
52#ifndef lint
53char copyright[] =
e15840af 54"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
8c5eec2f 55 All rights reserved.\n";
e15840af 56#endif /* not lint */
8c5eec2f 57
e677da31 58#ifndef lint
1c15e888 59static char sccsid[] = "@(#)syslogd.c 5.42 (Berkeley) 6/29/90";
e15840af 60#endif /* not lint */
e677da31
RC
61
62/*
63 * syslogd -- log system messages
64 *
65 * This program implements a system log. It takes a series of lines.
66 * Each line may have a priority, signified as "<n>" as
a49a6aba
RC
67 * the first characters of the line. If this is
68 * not present, a default priority is used.
e677da31
RC
69 *
70 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
71 * cause it to reread its configuration file.
72 *
73 * Defined Constants:
74 *
e677da31 75 * MAXLINE -- the maximimum line length that can be handled.
a49a6aba
RC
76 * DEFUPRI -- the default priority for user messages
77 * DEFSPRI -- the default priority for kernel messages
ada83039
RC
78 *
79 * Author: Eric Allman
a49a6aba 80 * extensive changes by Ralph Campbell
61a57de9 81 * more extensive changes by Eric Allman (again)
e677da31
RC
82 */
83
a49a6aba 84#define MAXLINE 1024 /* maximum line length */
35c3f83c 85#define MAXSVLINE 120 /* maximum saved line length */
64b300b4
EA
86#define DEFUPRI (LOG_USER|LOG_NOTICE)
87#define DEFSPRI (LOG_KERN|LOG_CRIT)
92e73e63 88#define TIMERINTVL 30 /* interval for checking flush, mark */
e677da31 89
2f6a4049 90#include <sys/param.h>
92e73e63 91#include <sys/errno.h>
e677da31
RC
92#include <sys/ioctl.h>
93#include <sys/stat.h>
84555b38 94#include <sys/wait.h>
e677da31
RC
95#include <sys/socket.h>
96#include <sys/file.h>
ada83039 97#include <sys/uio.h>
e677da31 98#include <sys/un.h>
64b300b4
EA
99#include <sys/time.h>
100#include <sys/resource.h>
92e73e63 101#include <sys/signal.h>
a24c481a 102
ad787160
C
103#ifdef MSG_BSIZE
104#undef MSG_BSIZE
105#endif
106#define MSG_BSIZE 4096
107
e677da31
RC
108#include <netinet/in.h>
109#include <netdb.h>
110
61b108ae 111#include <utmp.h>
61b108ae
KB
112#include <stdio.h>
113#include <ctype.h>
38dde0cd 114#include <string.h>
61b108ae 115
233e81a0 116#define SYSLOG_NAMES
ad787160
C
117#include "syslog.h"
118
119#define UT_NAMESIZE 8
120#define _PATH_UTMP "/etc/utmp"
121#define _PATH_DEV "/dev/"
122#define _PATH_CONSOLE "/dev/console"
233e81a0 123
ad787160
C
124#ifndef sigmask
125#define sigmask(m) (1 << ((m)-1))
126#endif
127char *LogName = _PATH_LOGFILE;
61b108ae
KB
128char *ConfFile = _PATH_LOGCONF;
129char *PidFile = _PATH_LOGPID;
130char ctty[] = _PATH_CONSOLE;
e677da31 131
64b300b4
EA
132#define FDMASK(fd) (1 << (fd))
133
e677da31
RC
134#define dprintf if (Debug) printf
135
64b300b4 136#define MAXUNAMES 20 /* maximum number of user names */
e677da31 137
ad787160
C
138#ifdef NEED_BZERO_ETC
139#include <fcntl.h>
140bzero(b, length)
141 char *b;
142 int length;
143{
144 while (--length >= 0)
145 *b++ = '\0';
146}
147bcopy(b1, b2, length)
148 char *b1;
149 char *b2;
150 int length;
151{
152 while (--length >= 0)
153 *b2++ = *b1++;
154}
155setlinebuf(f)
156 FILE *f;
157{
158 setbuf(f, (char *)NULL);
159}
160wait3(status, flags, np)
161 WAITVALUE *status;
162 int flags;
163 struct rusage *np;
164{
165 return waitpid(-1, status, WNOHANG);
166}
167
168/* Not a general mask handler -- it know what we call, below. */
169SIGHANDLER (*oldhup)(), (*oldalrm)();
170int
171sigsetmask(omask)
172 int omask;
173{
174 if (omask & sigmask(SIGHUP))
175 (void) signal(SIGHUP, oldhup);
176 if (omask & sigmask(SIGALRM))
177 (void) signal(SIGALRM, oldalrm);
178}
179int
180sigblock(mask)
181 int mask;
182{
183 if (mask & sigmask(SIGHUP))
184 oldhup = signal(SIGHUP, SIG_IGN);
185 if (mask & sigmask(SIGALRM))
186 oldhup = signal(SIGALRM, SIG_IGN);
187}
188#endif
189
8a7154b1
RC
190/*
191 * Flags to logmsg().
192 */
64b300b4
EA
193
194#define IGN_CONS 0x001 /* don't print on console */
195#define SYNC_FILE 0x002 /* do fsync on file after printing */
92e73e63
MK
196#define ADDDATE 0x004 /* add a date to the message */
197#define MARK 0x008 /* this message is a mark */
8a7154b1 198
e677da31
RC
199/*
200 * This structure represents the files that will have log
201 * copies printed.
202 */
203
204struct filed {
ad787160 205 struct filed *f_nextone; /* next in linked list */
64b300b4
EA
206 short f_type; /* entry type, see below */
207 short f_file; /* file descriptor */
ad58e75e 208 time_t f_time; /* time this was last written */
c16a39e2 209 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
64b300b4 210 union {
e185ee1c 211 char f_uname[MAXUNAMES][UT_NAMESIZE+1];
c16a39e2 212 struct {
74440133 213 char f_hname[MAXHOSTNAMELEN+1];
64b300b4 214 struct sockaddr_in f_addr;
c16a39e2 215 } f_forw; /* forwarding address */
e185ee1c 216 char f_fname[MAXPATHLEN];
c16a39e2 217 } f_un;
92e73e63
MK
218 char f_prevline[MAXSVLINE]; /* last message logged */
219 char f_lasttime[16]; /* time of last occurrence */
220 char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */
221 int f_prevpri; /* pri of f_prevline */
222 int f_prevlen; /* length of f_prevline */
223 int f_prevcount; /* repetition cnt of prevline */
224 int f_repeatcount; /* number of "repeated" msgs */
e677da31
RC
225};
226
92e73e63
MK
227/*
228 * Intervals at which we flush out "message repeated" messages,
229 * in seconds after previous message is logged. After each flush,
230 * we move to the next interval until we reach the largest.
231 */
232int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */
233#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
234#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
235#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
236 (f)->f_repeatcount = MAXREPEAT; \
237 }
238
64b300b4
EA
239/* values for f_type */
240#define F_UNUSED 0 /* unused entry */
241#define F_FILE 1 /* regular file */
242#define F_TTY 2 /* terminal */
243#define F_CONSOLE 3 /* console terminal */
244#define F_FORW 4 /* remote machine */
245#define F_USERS 5 /* list of users */
246#define F_WALL 6 /* everyone logged on */
247
248char *TypeNames[7] = {
249 "UNUSED", "FILE", "TTY", "CONSOLE",
250 "FORW", "USERS", "WALL"
e677da31
RC
251};
252
92e73e63
MK
253struct filed *Files;
254struct filed consfile;
e677da31
RC
255
256int Debug; /* debug flag */
74440133 257char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
ad58e75e 258char *LocalDomain; /* our local domain name */
64b300b4 259int InetInuse = 0; /* non-zero if INET sockets are being used */
92e73e63 260int finet; /* Internet datagram socket */
64b300b4 261int LogPort; /* port number for INET connections */
64b300b4 262int Initialized = 0; /* set when we have initialized ourselves */
92e73e63 263int MarkInterval = 20 * 60; /* interval between marks in seconds */
ad58e75e 264int MarkSeq = 0; /* mark sequence number */
e677da31 265
e185ee1c 266extern int errno;
ad787160
C
267extern char *ctime(), *strchr(), *malloc();
268SIGHANDLER die(), domark(), init(), reapchild();
e677da31 269
ad787160 270int
e677da31
RC
271main(argc, argv)
272 int argc;
273 char **argv;
274{
275 register int i;
276 register char *p;
92e73e63 277 int funix, inetm, fklog, klogm, len;
0d20624e 278 struct sockaddr_un sunx, fromunix;
e677da31
RC
279 struct sockaddr_in sin, frominet;
280 FILE *fp;
953d8fe3 281 int ch;
63cb489e 282 char line[MSG_BSIZE + 1];
981fd33c 283 extern int optind;
953d8fe3 284 extern char *optarg;
a49a6aba 285
953d8fe3
KB
286 while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
287 switch((char)ch) {
a49a6aba
RC
288 case 'd': /* debug */
289 Debug++;
290 break;
953d8fe3
KB
291 case 'f': /* configuration file */
292 ConfFile = optarg;
a49a6aba 293 break;
ad58e75e 294 case 'm': /* mark interval */
953d8fe3 295 MarkInterval = atoi(optarg) * 60;
ad58e75e 296 break;
953d8fe3
KB
297 case 'p': /* path */
298 LogName = optarg;
299 break;
300 case '?':
a49a6aba
RC
301 default:
302 usage();
e677da31 303 }
953d8fe3
KB
304 if (argc -= optind)
305 usage();
e677da31 306
43d42ac6
MK
307 if (!Debug)
308 daemon(0, 0);
309 else
84555b38
RC
310 setlinebuf(stdout);
311
92e73e63
MK
312 consfile.f_type = F_CONSOLE;
313 (void) strcpy(consfile.f_un.f_fname, ctty);
ad58e75e 314 (void) gethostname(LocalHostName, sizeof LocalHostName);
ad787160 315 if (p = strchr(LocalHostName, '.')) {
ad58e75e
EA
316 *p++ = '\0';
317 LocalDomain = p;
318 }
319 else
320 LocalDomain = "";
64b300b4 321 (void) signal(SIGTERM, die);
ad787160
C
322 if (Debug) {
323 (void) signal(SIGINT, die);
324 (void) signal(SIGQUIT, die);
325 }
326 else {
327 (void) signal(SIGINT, SIG_IGN);
328 (void) signal(SIGQUIT, SIG_IGN);
329 }
64b300b4 330 (void) signal(SIGCHLD, reapchild);
ad58e75e 331 (void) signal(SIGALRM, domark);
92e73e63 332 (void) alarm(TIMERINTVL);
64b300b4
EA
333 (void) unlink(LogName);
334
0f607d14 335 bzero((char *)&sunx, sizeof(sunx));
0d20624e
KM
336 sunx.sun_family = AF_UNIX;
337 (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
e677da31 338 funix = socket(AF_UNIX, SOCK_DGRAM, 0);
0d20624e 339 if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
ad787160 340 sizeof(sunx)) < 0 ||
64b300b4
EA
341 chmod(LogName, 0666) < 0) {
342 (void) sprintf(line, "cannot create %s", LogName);
343 logerror(line);
344 dprintf("cannot create %s (%d)\n", LogName, errno);
345 die(0);
e677da31 346 }
ad787160 347#ifdef DO_INET_SOCKET
e677da31
RC
348 finet = socket(AF_INET, SOCK_DGRAM, 0);
349 if (finet >= 0) {
350 struct servent *sp;
351
352 sp = getservbyname("syslog", "udp");
353 if (sp == NULL) {
354 errno = 0;
355 logerror("syslog/udp: unknown service");
64b300b4 356 die(0);
e677da31 357 }
ad787160 358 bzero((char *)&sin, sizeof(sin)); /* added uunet!rbj */
e677da31 359 sin.sin_family = AF_INET;
ad787160
C
360 sin.sin_addr.s_addr = INADDR_ANY;
361 sin.sin_port = LogPort = htons(sp->s_port);
e53dbb38 362 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
e677da31 363 logerror("bind");
64b300b4
EA
364 if (!Debug)
365 die(0);
366 } else {
367 inetm = FDMASK(finet);
368 InetInuse = 1;
e677da31 369 }
e677da31 370 }
ad787160
C
371#else
372 finet = -1;
373 inetm = 0;
374#endif /* DO_INET_SOCKET */
375#ifdef _PATH_KLOG
61b108ae 376 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
64b300b4 377 klogm = FDMASK(fklog);
84555b38 378 else {
61b108ae 379 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
a49a6aba
RC
380 klogm = 0;
381 }
ad787160
C
382#else
383 fklog = -1;
384 klogm = 0;
385#endif /* _PATH_KLOG */
e677da31
RC
386
387 /* tuck my process id away */
64b300b4 388 fp = fopen(PidFile, "w");
e677da31
RC
389 if (fp != NULL) {
390 fprintf(fp, "%d\n", getpid());
64b300b4 391 (void) fclose(fp);
e677da31
RC
392 }
393
394 dprintf("off & running....\n");
395
e677da31 396 init();
64b300b4 397 (void) signal(SIGHUP, init);
454c883a 398
e677da31 399 for (;;) {
64b300b4 400 int nfds, readfds = FDMASK(funix) | inetm | klogm;
e677da31 401
64b300b4 402 errno = 0;
ff8002b1 403 dprintf("readfds = %#x\n", readfds);
64b300b4 404 nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
e53dbb38 405 (fd_set *) NULL, (struct timeval *) NULL);
e677da31
RC
406 if (nfds == 0)
407 continue;
408 if (nfds < 0) {
64b300b4
EA
409 if (errno != EINTR)
410 logerror("select");
e677da31
RC
411 continue;
412 }
92e73e63 413 dprintf("got a message (%d, %#x)\n", nfds, readfds);
a49a6aba 414 if (readfds & klogm) {
84555b38 415 i = read(fklog, line, sizeof(line) - 1);
8a7154b1
RC
416 if (i > 0) {
417 line[i] = '\0';
418 printsys(line);
a49a6aba 419 } else if (i < 0 && errno != EINTR) {
84555b38
RC
420 logerror("klog");
421 fklog = -1;
a49a6aba
RC
422 klogm = 0;
423 }
8a7154b1 424 }
64b300b4 425 if (readfds & FDMASK(funix)) {
e677da31 426 len = sizeof fromunix;
64b300b4 427 i = recvfrom(funix, line, MAXLINE, 0,
e53dbb38 428 (struct sockaddr *) &fromunix, &len);
a24c481a
RC
429 if (i > 0) {
430 line[i] = '\0';
64b300b4 431 printline(LocalHostName, line);
a24c481a 432 } else if (i < 0 && errno != EINTR)
64b300b4 433 logerror("recvfrom unix");
a24c481a 434 }
84555b38 435 if (readfds & inetm) {
e677da31 436 len = sizeof frominet;
e53dbb38
KB
437 i = recvfrom(finet, line, MAXLINE, 0,
438 (struct sockaddr *) &frominet, &len);
64b300b4
EA
439 if (i > 0) {
440 extern char *cvthname();
441
a24c481a 442 line[i] = '\0';
64b300b4 443 printline(cvthname(&frominet), line);
a24c481a 444 } else if (i < 0 && errno != EINTR)
64b300b4 445 logerror("recvfrom inet");
ad787160 446 }
e677da31
RC
447 }
448}
449
a49a6aba
RC
450usage()
451{
e185ee1c 452 (void) fprintf(stderr,
1c15e888 453 "usage: syslogd [-d] [-f conffile] [-m markinterval] [-p path]\n");
a49a6aba
RC
454 exit(1);
455}
456
e677da31
RC
457/*
458 * Take a raw input line, decode the message, and print the message
459 * on the appropriate log files.
460 */
461
64b300b4
EA
462printline(hname, msg)
463 char *hname;
e677da31
RC
464 char *msg;
465{
466 register char *p, *q;
467 register int c;
63cb489e 468 char line[MAXLINE + 1];
e677da31
RC
469 int pri;
470
471 /* test for special codes */
a49a6aba 472 pri = DEFUPRI;
e677da31 473 p = msg;
a49a6aba
RC
474 if (*p == '<') {
475 pri = 0;
476 while (isdigit(*++p))
477 pri = 10 * pri + (*p - '0');
478 if (*p == '>')
479 ++p;
e677da31 480 }
35c3f83c
MK
481 if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
482 pri = DEFUPRI;
e677da31 483
64b300b4 484 /* don't allow users to log kernel messages */
35c3f83c
MK
485 if (LOG_FAC(pri) == LOG_KERN)
486 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
64b300b4 487
e677da31 488 q = line;
64b300b4 489
953d8fe3
KB
490 while ((c = *p++ & 0177) != '\0' &&
491 q < &line[sizeof(line) - 1])
0d52e368
KB
492 if (iscntrl(c))
493 if (c == '\n')
494 *q++ = ' ';
495 else if (c == '\t')
496 *q++ = '\t';
497 else {
498 *q++ = '^';
499 *q++ = c ^ 0100;
500 }
501 else
e677da31 502 *q++ = c;
e677da31
RC
503 *q = '\0';
504
64b300b4 505 logmsg(pri, line, hname, 0);
e677da31
RC
506}
507
63cb489e
RC
508/*
509 * Take a raw input line from /dev/klog, split and format similar to syslog().
510 */
511
512printsys(msg)
513 char *msg;
514{
515 register char *p, *q;
516 register int c;
517 char line[MAXLINE + 1];
8a7154b1 518 int pri, flags;
a49a6aba 519 char *lp;
63cb489e 520
e185ee1c 521 (void) strcpy(line, "vmunix: ");
a49a6aba 522 lp = line + strlen(line);
63cb489e 523 for (p = msg; *p != '\0'; ) {
92e73e63 524 flags = SYNC_FILE | ADDDATE; /* fsync file after write */
a49a6aba
RC
525 pri = DEFSPRI;
526 if (*p == '<') {
527 pri = 0;
528 while (isdigit(*++p))
529 pri = 10 * pri + (*p - '0');
530 if (*p == '>')
531 ++p;
8a7154b1
RC
532 } else {
533 /* kernel printf's come out on console */
534 flags |= IGN_CONS;
535 }
35c3f83c
MK
536 if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
537 pri = DEFSPRI;
a49a6aba
RC
538 q = lp;
539 while (*p != '\0' && (c = *p++) != '\n' &&
540 q < &line[MAXLINE])
63cb489e
RC
541 *q++ = c;
542 *q = '\0';
64b300b4 543 logmsg(pri, line, LocalHostName, flags);
63cb489e
RC
544 }
545}
546
ad787160
C
547
548#ifdef VERBOSE_DEBUG
549/*
550 * Decode a numeric value to a symbolic name
551 */
552char *
553edoced(val, codetab)
554 int val;
555 CODE *codetab;
556{
557 register CODE *c;
558
559 if (val >= 0)
560 for (c = codetab; c->c_val != -1; c++)
561 if (c->c_val == val)
562 return (c->c_name);
563 return ("???");
564}
565#endif
566
92e73e63
MK
567time_t now;
568
e677da31
RC
569/*
570 * Log a message to the appropriate log files, users, etc. based on
571 * the priority.
572 */
573
8a7154b1 574logmsg(pri, msg, from, flags)
64b300b4
EA
575 int pri;
576 char *msg, *from;
577 int flags;
e677da31 578{
e677da31 579 register struct filed *f;
64b300b4 580 int fac, prilev;
92e73e63
MK
581 int omask, msglen;
582 char *timestamp;
e53dbb38 583 time_t time();
84555b38 584
ad787160
C
585#ifdef VERBOSE_DEBUG
586 if (Debug) {
587 int pfac = (flags & MARK) ? INTERNAL_MARK : (pri & LOG_FACMASK);
588 printf("logmsg: {%s.%s} pri %o, flags %x, from %s, msg %s\n",
589 edoced(pfac, facilitynames),
590 edoced(LOG_PRI(pri), prioritynames),
591 pri, flags, from, msg);
592 }
593#else
e185ee1c
KB
594 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
595 pri, flags, from, msg);
ad787160 596#endif
64b300b4 597
ad58e75e 598 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
ada83039 599
64b300b4
EA
600 /*
601 * Check to see if msg looks non-standard.
602 */
92e73e63
MK
603 msglen = strlen(msg);
604 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
ad58e75e 605 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
64b300b4 606 flags |= ADDDATE;
a49a6aba 607
ad58e75e
EA
608 (void) time(&now);
609 if (flags & ADDDATE)
92e73e63
MK
610 timestamp = ctime(&now) + 4;
611 else {
612 timestamp = msg;
613 msg += 16;
614 msglen -= 16;
615 }
64b300b4
EA
616
617 /* extract facility and priority level */
c16a39e2
MK
618 if (flags & MARK)
619 fac = LOG_NFACILITIES;
35c3f83c
MK
620 else
621 fac = LOG_FAC(pri);
622 prilev = LOG_PRI(pri);
64b300b4 623
e677da31 624 /* log the message to the particular outputs */
64b300b4 625 if (!Initialized) {
92e73e63 626 f = &consfile;
e53dbb38 627 f->f_file = open(ctty, O_WRONLY, 0);
64b300b4 628
92e73e63 629 if (f->f_file >= 0) {
c49273cf 630 fprintlog(f, flags, msg);
92e73e63 631 (void) close(f->f_file);
64b300b4 632 }
7eefe9c1 633 (void) sigsetmask(omask);
64b300b4
EA
634 return;
635 }
ad787160 636 for (f = Files; f; f = f->f_nextone) {
64b300b4 637 /* skip messages that are incorrect priority */
ad787160 638 if ((int)f->f_pmask[fac] < prilev ||
233e81a0 639 f->f_pmask[fac] == INTERNAL_NOPRI)
a49a6aba 640 continue;
64b300b4 641
35c3f83c
MK
642 if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
643 continue;
644
ad58e75e 645 /* don't output marks to recently written files */
92e73e63 646 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
ad58e75e
EA
647 continue;
648
92e73e63
MK
649 /*
650 * suppress duplicate lines to this file
651 */
652 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
653 !strcmp(msg, f->f_prevline) &&
654 !strcmp(from, f->f_prevhost)) {
655 (void) strncpy(f->f_lasttime, timestamp, 15);
656 f->f_prevcount++;
953d8fe3 657 dprintf("msg repeated %d times, %ld sec of %d\n",
92e73e63
MK
658 f->f_prevcount, now - f->f_time,
659 repeatinterval[f->f_repeatcount]);
660 /*
661 * If domark would have logged this by now,
662 * flush it now (so we don't hold isolated messages),
663 * but back off so we'll flush less often
664 * in the future.
665 */
666 if (now > REPEATTIME(f)) {
35c3f83c 667 fprintlog(f, flags, (char *)NULL);
92e73e63 668 BACKOFF(f);
8a7154b1 669 }
92e73e63
MK
670 } else {
671 /* new line, save it */
35c3f83c
MK
672 if (f->f_prevcount)
673 fprintlog(f, 0, (char *)NULL);
674 f->f_repeatcount = 0;
92e73e63 675 (void) strncpy(f->f_lasttime, timestamp, 15);
35c3f83c
MK
676 (void) strncpy(f->f_prevhost, from,
677 sizeof(f->f_prevhost));
678 if (msglen < MAXSVLINE) {
92e73e63
MK
679 f->f_prevlen = msglen;
680 f->f_prevpri = pri;
681 (void) strcpy(f->f_prevline, msg);
35c3f83c
MK
682 fprintlog(f, flags, (char *)NULL);
683 } else {
92e73e63 684 f->f_prevline[0] = 0;
35c3f83c
MK
685 f->f_prevlen = 0;
686 fprintlog(f, flags, msg);
687 }
92e73e63
MK
688 }
689 }
690 (void) sigsetmask(omask);
691}
64b300b4 692
35c3f83c 693fprintlog(f, flags, msg)
92e73e63
MK
694 register struct filed *f;
695 int flags;
35c3f83c 696 char *msg;
92e73e63
MK
697{
698 struct iovec iov[6];
e53dbb38 699 register struct iovec *v;
92e73e63 700 register int l;
e53dbb38 701 char line[MAXLINE + 1], repbuf[80], greetings[200];
92e73e63 702
e53dbb38
KB
703 v = iov;
704 if (f->f_type == F_WALL) {
705 v->iov_base = greetings;
ad787160 706 sprintf(greetings,
e53dbb38
KB
707 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
708 f->f_prevhost, ctime(&now));
ad787160 709 v->iov_len = strlen(greetings);
e53dbb38
KB
710 v++;
711 v->iov_base = "";
712 v->iov_len = 0;
713 v++;
714 } else {
715 v->iov_base = f->f_lasttime;
716 v->iov_len = 15;
717 v++;
718 v->iov_base = " ";
719 v->iov_len = 1;
720 v++;
721 }
92e73e63
MK
722 v->iov_base = f->f_prevhost;
723 v->iov_len = strlen(v->iov_base);
724 v++;
725 v->iov_base = " ";
726 v->iov_len = 1;
727 v++;
e53dbb38 728
35c3f83c
MK
729 if (msg) {
730 v->iov_base = msg;
731 v->iov_len = strlen(msg);
732 } else if (f->f_prevcount > 1) {
92e73e63 733 v->iov_base = repbuf;
ad787160 734 sprintf(repbuf, "last message repeated %d times",
e53dbb38 735 f->f_prevcount);
ad787160 736 v->iov_len = strlen(repbuf);
92e73e63
MK
737 } else {
738 v->iov_base = f->f_prevline;
739 v->iov_len = f->f_prevlen;
740 }
741 v++;
742
743 dprintf("Logging to %s", TypeNames[f->f_type]);
744 f->f_time = now;
745
746 switch (f->f_type) {
747 case F_UNUSED:
748 dprintf("\n");
749 break;
750
751 case F_FORW:
752 dprintf(" %s\n", f->f_un.f_forw.f_hname);
ad787160 753 sprintf(line, "<%d>%.15s %s", f->f_prevpri,
e53dbb38 754 iov[0].iov_base, iov[4].iov_base);
ad787160 755 l = strlen(line);
92e73e63
MK
756 if (l > MAXLINE)
757 l = MAXLINE;
758 if (sendto(finet, line, l, 0, &f->f_un.f_forw.f_addr,
759 sizeof f->f_un.f_forw.f_addr) != l) {
760 int e = errno;
761 (void) close(f->f_file);
762 f->f_type = F_UNUSED;
763 errno = e;
764 logerror("sendto");
765 }
766 break;
767
768 case F_CONSOLE:
769 if (flags & IGN_CONS) {
770 dprintf(" (ignored)\n");
64b300b4 771 break;
92e73e63
MK
772 }
773 /* FALLTHROUGH */
e677da31 774
92e73e63
MK
775 case F_TTY:
776 case F_FILE:
777 dprintf(" %s\n", f->f_un.f_fname);
778 if (f->f_type != F_FILE) {
64b300b4
EA
779 v->iov_base = "\r\n";
780 v->iov_len = 2;
92e73e63
MK
781 } else {
782 v->iov_base = "\n";
783 v->iov_len = 1;
64b300b4 784 }
92e73e63
MK
785 again:
786 if (writev(f->f_file, iov, 6) < 0) {
787 int e = errno;
788 (void) close(f->f_file);
789 /*
604d6f83 790 * Check for errors on TTY's due to loss of tty
92e73e63 791 */
604d6f83 792 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
e53dbb38
KB
793 f->f_file = open(f->f_un.f_fname,
794 O_WRONLY|O_APPEND, 0);
92e73e63
MK
795 if (f->f_file < 0) {
796 f->f_type = F_UNUSED;
797 logerror(f->f_un.f_fname);
43d42ac6 798 } else
92e73e63 799 goto again;
92e73e63
MK
800 } else {
801 f->f_type = F_UNUSED;
802 errno = e;
803 logerror(f->f_un.f_fname);
804 }
805 } else if (flags & SYNC_FILE)
806 (void) fsync(f->f_file);
807 break;
e677da31 808
92e73e63
MK
809 case F_USERS:
810 case F_WALL:
811 dprintf("\n");
812 v->iov_base = "\r\n";
813 v->iov_len = 2;
814 wallmsg(f, iov);
815 break;
816 }
817 f->f_prevcount = 0;
e677da31
RC
818}
819
820/*
821 * WALLMSG -- Write a message to the world at large
822 *
823 * Write the specified message to either the entire
824 * world, or a list of approved users.
825 */
826
64b300b4
EA
827wallmsg(f, iov)
828 register struct filed *f;
829 struct iovec *iov;
e677da31 830{
e53dbb38
KB
831 static int reenter; /* avoid calling ourselves */
832 register FILE *uf;
e677da31 833 register int i;
e677da31 834 struct utmp ut;
e53dbb38 835 char *p, *ttymsg();
64b300b4
EA
836
837 if (reenter++)
838 return;
61b108ae 839 if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
3cdeaa19 840 logerror(_PATH_UTMP);
64b300b4 841 reenter = 0;
e677da31 842 return;
ada83039 843 }
e53dbb38
KB
844 /* NOSTRICT */
845 while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
846 if (ut.ut_name[0] == '\0')
847 continue;
848 if (f->f_type == F_WALL) {
233e81a0
KB
849 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
850 errno = 0; /* already in msg */
e53dbb38 851 logerror(p);
233e81a0 852 }
e53dbb38
KB
853 continue;
854 }
855 /* should we send the message to this user? */
856 for (i = 0; i < MAXUNAMES; i++) {
857 if (!f->f_un.f_uname[i][0])
858 break;
859 if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
860 UT_NAMESIZE)) {
233e81a0
KB
861 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
862 errno = 0; /* already in msg */
e53dbb38 863 logerror(p);
233e81a0 864 }
e53dbb38 865 break;
fcd484c8 866 }
e677da31 867 }
e677da31 868 }
84555b38 869 (void) fclose(uf);
64b300b4 870 reenter = 0;
84555b38
RC
871}
872
ad787160 873SIGHANDLER
84555b38
RC
874reapchild()
875{
ad787160 876 WAITVALUE status;
84555b38 877
64b300b4 878 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
ad787160 879 continue;
e677da31
RC
880}
881
882/*
64b300b4 883 * Return a printable representation of a host address.
e677da31 884 */
64b300b4
EA
885char *
886cvthname(f)
e677da31
RC
887 struct sockaddr_in *f;
888{
889 struct hostent *hp;
ad58e75e 890 register char *p;
e677da31
RC
891 extern char *inet_ntoa();
892
64b300b4 893 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
e677da31
RC
894
895 if (f->sin_family != AF_INET) {
896 dprintf("Malformed from address\n");
64b300b4 897 return ("???");
e677da31
RC
898 }
899 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
900 if (hp == 0) {
901 dprintf("Host name for your address (%s) unknown\n",
902 inet_ntoa(f->sin_addr));
64b300b4 903 return (inet_ntoa(f->sin_addr));
e677da31 904 }
ad787160 905 if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
ad58e75e 906 *p = '\0';
64b300b4 907 return (hp->h_name);
e677da31
RC
908}
909
ad787160 910SIGHANDLER
ad58e75e
EA
911domark()
912{
92e73e63 913 register struct filed *f;
e53dbb38 914 time_t time();
ad58e75e 915
e53dbb38 916 now = time((time_t *)NULL);
92e73e63
MK
917 MarkSeq += TIMERINTVL;
918 if (MarkSeq >= MarkInterval) {
c16a39e2 919 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
92e73e63
MK
920 MarkSeq = 0;
921 }
ad58e75e 922
ad787160 923 for (f = Files; f; f = f->f_nextone) {
92e73e63
MK
924 if (f->f_prevcount && now >= REPEATTIME(f)) {
925 dprintf("flush %s: repeated %d times, %d sec.\n",
926 TypeNames[f->f_type], f->f_prevcount,
927 repeatinterval[f->f_repeatcount]);
35c3f83c 928 fprintlog(f, 0, (char *)NULL);
92e73e63
MK
929 BACKOFF(f);
930 }
931 }
932 (void) alarm(TIMERINTVL);
a49a6aba
RC
933}
934
ad787160
C
935static char *
936xstrerror()
937{
938 extern int sys_nerr;
939 extern char *sys_errlist[];
940 extern int errno;
941 static char buff[30];
942
943 if (errno >= 0 && errno < sys_nerr)
944 return sys_errlist[errno];
945 (void)sprintf(buff, "Error code %d\n", errno);
946 return buff;
947}
948
e677da31
RC
949/*
950 * Print syslogd errors some place.
951 */
952logerror(type)
953 char *type;
954{
ad787160 955 char buf[100];
e677da31 956
e185ee1c 957 if (errno)
ad787160 958 (void) sprintf(buf, "syslogd: %s: %s", type, xstrerror(errno));
e677da31 959 else
e185ee1c 960 (void) sprintf(buf, "syslogd: %s", type);
e677da31 961 errno = 0;
ada83039 962 dprintf("%s\n", buf);
ad58e75e 963 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
e677da31
RC
964}
965
ad787160 966SIGHANDLER
64b300b4 967die(sig)
e677da31 968{
92e73e63 969 register struct filed *f;
64b300b4 970 char buf[100];
ada83039 971
ad787160 972 for (f = Files; f != NULL; f = f->f_nextone) {
92e73e63
MK
973 /* flush any pending output */
974 if (f->f_prevcount)
35c3f83c 975 fprintlog(f, 0, (char *)NULL);
92e73e63 976 }
a075f884 977 if (sig) {
92e73e63
MK
978 dprintf("syslogd: exiting on signal %d\n", sig);
979 (void) sprintf(buf, "exiting on signal %d", sig);
d34bf11a 980 errno = 0;
a075f884
MK
981 logerror(buf);
982 }
64b300b4 983 (void) unlink(LogName);
e677da31
RC
984 exit(0);
985}
a49a6aba
RC
986
987/*
64b300b4 988 * INIT -- Initialize syslogd from configuration table
a49a6aba 989 */
64b300b4 990
ad787160 991SIGHANDLER
64b300b4 992init()
a49a6aba 993{
a49a6aba 994 register int i;
64b300b4 995 register FILE *cf;
92e73e63 996 register struct filed *f, *next, **nextp;
64b300b4
EA
997 register char *p;
998 char cline[BUFSIZ];
a49a6aba 999
64b300b4
EA
1000 dprintf("init\n");
1001
64b300b4
EA
1002 /*
1003 * Close all open log files.
1004 */
d34bf11a 1005 Initialized = 0;
92e73e63
MK
1006 for (f = Files; f != NULL; f = next) {
1007 /* flush any pending output */
1008 if (f->f_prevcount)
35c3f83c 1009 fprintlog(f, 0, (char *)NULL);
92e73e63 1010
bb112360
EA
1011 switch (f->f_type) {
1012 case F_FILE:
1013 case F_TTY:
bb112360 1014 case F_CONSOLE:
2efc48b0 1015 case F_FORW:
64b300b4 1016 (void) close(f->f_file);
bb112360
EA
1017 break;
1018 }
ad787160 1019 next = f->f_nextone;
92e73e63 1020 free((char *) f);
64b300b4 1021 }
92e73e63
MK
1022 Files = NULL;
1023 nextp = &Files;
64b300b4
EA
1024
1025 /* open the configuration file */
1026 if ((cf = fopen(ConfFile, "r")) == NULL) {
1027 dprintf("cannot open %s\n", ConfFile);
ad787160 1028 *nextp = (struct filed *)malloc(sizeof(*f));
92e73e63 1029 cfline("*.ERR\t/dev/console", *nextp);
ad787160
C
1030 (*nextp)->f_nextone = (struct filed *)malloc(sizeof(*f));
1031 cfline("*.PANIC\t*", (*nextp)->f_nextone);
92e73e63 1032 Initialized = 1;
64b300b4
EA
1033 return;
1034 }
1035
1036 /*
1037 * Foreach line in the conf table, open that file.
1038 */
92e73e63
MK
1039 f = NULL;
1040 while (fgets(cline, sizeof cline, cf) != NULL) {
e15840af
KB
1041 /*
1042 * check for end-of-section, comments, strip off trailing
1043 * spaces and newline character.
1044 */
1045 for (p = cline; isspace(*p); ++p);
1046 if (*p == NULL || *p == '#')
a49a6aba 1047 continue;
ad787160 1048 for (p = strchr(cline, '\0'); isspace(*--p););
e15840af 1049 *++p = '\0';
ad787160 1050 f = (struct filed *)malloc(sizeof(*f));
92e73e63 1051 *nextp = f;
ad787160 1052 nextp = &f->f_nextone;
92e73e63 1053 cfline(cline, f);
64b300b4
EA
1054 }
1055
1056 /* close the configuration file */
1057 (void) fclose(cf);
1058
1059 Initialized = 1;
1060
1061 if (Debug) {
ad787160 1062 for (f = Files; f; f = f->f_nextone) {
c16a39e2 1063 for (i = 0; i <= LOG_NFACILITIES; i++)
233e81a0 1064 if (f->f_pmask[i] == INTERNAL_NOPRI)
64b300b4
EA
1065 printf("X ");
1066 else
1067 printf("%d ", f->f_pmask[i]);
1068 printf("%s: ", TypeNames[f->f_type]);
1069 switch (f->f_type) {
1070 case F_FILE:
1071 case F_TTY:
1072 case F_CONSOLE:
1073 printf("%s", f->f_un.f_fname);
1074 break;
1075
1076 case F_FORW:
1077 printf("%s", f->f_un.f_forw.f_hname);
1078 break;
1079
1080 case F_USERS:
1081 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1082 printf("%s, ", f->f_un.f_uname[i]);
1083 break;
1084 }
1085 printf("\n");
1086 }
1087 }
1088
ad58e75e 1089 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
64b300b4
EA
1090 dprintf("syslogd: restarted\n");
1091}
1092
1093/*
1094 * Crack a configuration file line
1095 */
1096
64b300b4
EA
1097cfline(line, f)
1098 char *line;
1099 register struct filed *f;
1100{
1101 register char *p;
1102 register char *q;
1103 register int i;
1104 char *bp;
1105 int pri;
1106 struct hostent *hp;
1107 char buf[MAXLINE];
1108
1109 dprintf("cfline(%s)\n", line);
1110
e185ee1c 1111 errno = 0; /* keep strerror() stuff out of logerror messages */
d34bf11a 1112
64b300b4
EA
1113 /* clear out file entry */
1114 bzero((char *) f, sizeof *f);
c16a39e2 1115 for (i = 0; i <= LOG_NFACILITIES; i++)
233e81a0 1116 f->f_pmask[i] = INTERNAL_NOPRI;
64b300b4
EA
1117
1118 /* scan through the list of selectors */
1119 for (p = line; *p && *p != '\t';) {
1120
1121 /* find the end of this facility name list */
1122 for (q = p; *q && *q != '\t' && *q++ != '.'; )
a49a6aba 1123 continue;
64b300b4
EA
1124
1125 /* collect priority name */
ad787160 1126 for (bp = buf; *q && !strchr("\t,;", *q); )
64b300b4
EA
1127 *bp++ = *q++;
1128 *bp = '\0';
1129
1130 /* skip cruft */
ad787160 1131 while (strchr(", ;", *q))
64b300b4
EA
1132 q++;
1133
1134 /* decode priority name */
1c15e888 1135 pri = decode(buf, prioritynames);
64b300b4
EA
1136 if (pri < 0) {
1137 char xbuf[200];
1138
1c15e888
C
1139 (void) sprintf(xbuf, "unknown priority name \"%s\"",
1140 buf);
64b300b4
EA
1141 logerror(xbuf);
1142 return;
1143 }
1144
1145 /* scan facilities */
ad787160
C
1146 while (*p && !strchr("\t.;", *p)) {
1147 for (bp = buf; *p && !strchr("\t,;.", *p); )
64b300b4
EA
1148 *bp++ = *p++;
1149 *bp = '\0';
1150 if (*buf == '*')
1151 for (i = 0; i < LOG_NFACILITIES; i++)
1152 f->f_pmask[i] = pri;
1153 else {
233e81a0 1154 i = decode(buf, facilitynames);
64b300b4
EA
1155 if (i < 0) {
1156 char xbuf[200];
1157
1c15e888 1158 (void) sprintf(xbuf,
e53dbb38
KB
1159 "unknown facility name \"%s\"",
1160 buf);
64b300b4
EA
1161 logerror(xbuf);
1162 return;
1163 }
1164 f->f_pmask[i >> 3] = pri;
1165 }
1166 while (*p == ',' || *p == ' ')
1167 p++;
1168 }
1169
1170 p = q;
1171 }
1172
1173 /* skip to action part */
1174 while (*p == '\t')
1175 p++;
1176
1177 switch (*p)
1178 {
1179 case '@':
1180 if (!InetInuse)
1181 break;
1182 (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1183 hp = gethostbyname(p);
1184 if (hp == NULL) {
ad787160 1185 logerror("hostname lookup error");
64b300b4
EA
1186 break;
1187 }
1188 bzero((char *) &f->f_un.f_forw.f_addr,
1189 sizeof f->f_un.f_forw.f_addr);
1190 f->f_un.f_forw.f_addr.sin_family = AF_INET;
1191 f->f_un.f_forw.f_addr.sin_port = LogPort;
1192 bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
64b300b4
EA
1193 f->f_type = F_FORW;
1194 break;
1195
1196 case '/':
1197 (void) strcpy(f->f_un.f_fname, p);
e53dbb38 1198 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
e15840af 1199 f->f_file = F_UNUSED;
64b300b4
EA
1200 logerror(p);
1201 break;
1202 }
43d42ac6 1203 if (isatty(f->f_file))
64b300b4 1204 f->f_type = F_TTY;
64b300b4
EA
1205 else
1206 f->f_type = F_FILE;
1207 if (strcmp(p, ctty) == 0)
1208 f->f_type = F_CONSOLE;
1209 break;
1210
1211 case '*':
1212 f->f_type = F_WALL;
1213 break;
1214
1215 default:
1216 for (i = 0; i < MAXUNAMES && *p; i++) {
1217 for (q = p; *q && *q != ','; )
1218 q++;
e185ee1c
KB
1219 (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1220 if ((q - p) > UT_NAMESIZE)
1221 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
64b300b4
EA
1222 else
1223 f->f_un.f_uname[i][q - p] = '\0';
1224 while (*q == ',' || *q == ' ')
1225 q++;
1226 p = q;
1227 }
1228 f->f_type = F_USERS;
1229 break;
a49a6aba 1230 }
64b300b4
EA
1231}
1232
1233
1234/*
1235 * Decode a symbolic name to a numeric value
1236 */
1237
1238decode(name, codetab)
1239 char *name;
233e81a0 1240 CODE *codetab;
64b300b4 1241{
233e81a0 1242 register CODE *c;
64b300b4
EA
1243 register char *p;
1244 char buf[40];
1245
1246 if (isdigit(*name))
1247 return (atoi(name));
1248
1249 (void) strcpy(buf, name);
1250 for (p = buf; *p; p++)
1251 if (isupper(*p))
1252 *p = tolower(*p);
1253 for (c = codetab; c->c_name; c++)
1254 if (!strcmp(buf, c->c_name))
1255 return (c->c_val);
a49a6aba 1256
64b300b4 1257 return (-1);
a49a6aba 1258}
ad787160
C
1259
1260daemon(nochdir, noclose)
1261 int nochdir, noclose;
1262{
1263 int cpid;
1264
1265 if ((cpid = fork()) == -1)
1266 return (-1);
1267 if (cpid)
1268 exit(0);
1269 (void) setsid();
1270 if (!nochdir)
1271 (void) chdir("/");
1272 if (!noclose) {
1273 int devnull = open("/dev/null", O_RDWR, 0);
1274
1275 if (devnull != -1) {
1276 (void) dup2(devnull, 0);
1277 (void) dup2(devnull, 1);
1278 (void) dup2(devnull, 2);
1279 if (devnull > 2)
1280 (void) close(devnull);
1281 }
1282 }
1283}
1284
1285
1286/*
1287 * Display the contents of a uio structure on a terminal. Used by wall(1)
1288 * and syslogd(8). Forks and finishes in child if write would block, waiting
1289 * at most five minutes. Returns pointer to error string on unexpected error;
1290 * string is not newline-terminated. Various "normal" errors are ignored
1291 * (exclusive-use, lack of permission, etc.).
1292 */
1293char *
1294ttymsg(iov, iovcnt, line)
1295 struct iovec *iov;
1296 int iovcnt;
1297 char *line;
1298{
1299 static char device[64] = _PATH_DEV;
1300 static char errbuf[1024];
1301 register int cnt, fd, left, wret;
1302 struct iovec localiov[6];
1303 int forked = 0;
1304
1305 if (iovcnt > 6)
1306 return ("too many iov's");
1307 /*
1308 * open will fail on slip lines or exclusive-use lines
1309 * if not running as root; not an error.
1310 */
1311 (void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
1312 if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
1313 if (errno == EBUSY || errno == EACCES)
1314 return (NULL);
1315 (void) sprintf(errbuf, "%s: error %d", device, errno);
1316 return (errbuf);
1317 }
1318
1319 for (cnt = left = 0; cnt < iovcnt; ++cnt)
1320 left += iov[cnt].iov_len;
1321
1322 for (;;) {
1323 wret = writev(fd, iov, iovcnt);
1324 if (wret >= left)
1325 break;
1326 if (wret >= 0) {
1327 left -= wret;
1328 if (iov != localiov) {
1329 bcopy(iov, localiov,
1330 iovcnt * sizeof(struct iovec));
1331 iov = localiov;
1332 }
1333 for (cnt = 0; wret >= iov->iov_len; ++cnt) {
1334 wret -= iov->iov_len;
1335 ++iov;
1336 --iovcnt;
1337 }
1338 if (wret) {
1339 iov->iov_base += wret;
1340 iov->iov_len -= wret;
1341 }
1342 continue;
1343 }
1344 if (errno == EWOULDBLOCK) {
1345 int cpid, off = 0;
1346
1347 if (forked) {
1348 (void) close(fd);
1349 _exit(1);
1350 }
1351 cpid = fork();
1352 if (cpid < 0) {
1353 (void) sprintf(errbuf,
1354 "fork: error %d", errno);
1355 (void) close(fd);
1356 return (errbuf);
1357 }
1358 if (cpid) { /* parent */
1359 (void) close(fd);
1360 return (NULL);
1361 }
1362 forked++;
1363 /* wait at most 5 minutes */
1364 (void) signal(SIGALRM, SIG_DFL);
1365 (void) signal(SIGTERM, SIG_DFL); /* XXX */
1366 (void) sigsetmask(0);
1367 (void) alarm((u_int)(60 * 5));
1368 (void) fcntl(fd, FNDELAY, &off);
1369 continue;
1370 }
1371 /*
1372 * We get ENODEV on a slip line if we're running as root,
1373 * and EIO if the line just went away.
1374 */
1375 if (errno == ENODEV || errno == EIO)
1376 break;
1377 (void) close(fd);
1378 if (forked)
1379 _exit(1);
1380 (void) sprintf(errbuf, "%s: error %d", errno);
1381 return (errbuf);
1382 }
1383
1384 (void) close(fd);
1385 if (forked)
1386 _exit(0);
1387 return (NULL);
1388}