2 * Copyright (c) 1983, 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static const char copyright
[] =
36 "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
42 static char sccsid
[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94";
47 * syslogd -- log system messages
49 * This program implements a system log. It takes a series of lines.
50 * Each line may have a priority, signified as "<n>" as
51 * the first characters of the line. If this is
52 * not present, a default priority is used.
54 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
55 * cause it to reread its configuration file.
59 * MAXLINE -- the maximimum line length that can be handled.
60 * DEFUPRI -- the default priority for user messages
61 * DEFSPRI -- the default priority for kernel messages
64 * extensive changes by Ralph Campbell
65 * more extensive changes by Eric Allman (again)
66 * Extension to log by program name as well as facility and priority
68 * -u and -v by Harlan Stenn.
69 * Priority comparison code by Harlan Stenn.
72 #define MAXLINE 1024 /* maximum line length */
73 #define MAXSVLINE 120 /* maximum saved line length */
74 #define DEFUPRI (LOG_USER|LOG_NOTICE)
75 #define DEFSPRI (LOG_KERN|LOG_CRIT)
76 #define TIMERINTVL 30 /* interval for checking flush, mark */
77 #define TTYMSGTIME 1 /* timed out passed to ttymsg */
79 #include <sys/param.h>
80 #include <sys/ioctl.h>
83 #include <sys/socket.h>
84 #include <sys/queue.h>
88 #include <sys/resource.h>
89 #include <sys/syslimits.h>
92 #include <netinet/in.h>
94 #include <arpa/inet.h>
106 #include <sysexits.h>
112 #ifndef NETWORK_CHANGE_NOTIFICATION
113 #define NETWORK_CHANGE_NOTIFICATION "com.apple.system.config.network_change"
116 #include "pathnames.h"
120 #include <sys/syslog.h>
122 #ifdef NI_WITHSCOPEID
123 static const int withscopeid
= NI_WITHSCOPEID
;
125 static const int withscopeid
;
128 const char *ConfFile
= _PATH_LOGCONF
;
129 const char *PidFile
= _PATH_LOGPID
;
130 const char ctty
[] = _PATH_CONSOLE
;
132 #define dprintf if (Debug) printf
134 #define MAXUNAMES 20 /* maximum number of user names */
139 const char *funixn
[MAXFUNIX
] = { _PATH_LOG
};
146 #define IGN_CONS 0x001 /* don't print on console */
147 #define SYNC_FILE 0x002 /* do fsync on file after printing */
148 #define ADDDATE 0x004 /* add a date to the message */
149 #define MARK 0x008 /* this message is a mark */
150 #define ISKERNEL 0x010 /* kernel generated message */
153 * This structure represents the files that will have log
158 struct filed
*f_next
; /* next in linked list */
159 short f_type
; /* entry type, see below */
160 short f_file
; /* file descriptor */
161 time_t f_time
; /* time this was last written */
162 char *f_host
; /* host from which to recd. */
163 u_char f_pmask
[LOG_NFACILITIES
+1]; /* priority mask */
164 u_char f_pcmp
[LOG_NFACILITIES
+1]; /* compare priority */
168 char *f_program
; /* program this applies to */
170 char f_uname
[MAXUNAMES
][UT_NAMESIZE
+1];
172 char f_hname
[MAXHOSTNAMELEN
];
173 struct addrinfo
*f_addr
;
175 } f_forw
; /* forwarding address */
176 char f_fname
[MAXPATHLEN
];
178 char f_pname
[MAXPATHLEN
];
182 char f_prevline
[MAXSVLINE
]; /* last message logged */
183 char f_lasttime
[16]; /* time of last occurrence */
184 char f_prevhost
[MAXHOSTNAMELEN
]; /* host from which recd. */
185 int f_prevpri
; /* pri of f_prevline */
186 int f_prevlen
; /* length of f_prevline */
187 int f_prevcount
; /* repetition cnt of prevline */
188 u_int f_repeatcount
; /* number of "repeated" msgs */
192 * Queue of about-to-be dead processes we should watch out for.
195 TAILQ_HEAD(stailhead
, deadq_entry
) deadq_head
;
196 struct stailhead
*deadq_headp
;
201 TAILQ_ENTRY(deadq_entry
) dq_entries
;
205 * The timeout to apply to processes waiting on the dead queue. Unit
206 * of measure is `mark intervals', i.e. 20 minutes by default.
207 * Processes on the dead queue will be terminated after that time.
210 #define DQ_TIMO_INIT 2
212 typedef struct deadq_entry
*dq_t
;
216 * Struct to hold records of network addresses that are allowed to log
224 struct sockaddr_storage addr
;
225 struct sockaddr_storage mask
;
229 #define a_addr u.numeric.addr
230 #define a_mask u.numeric.mask
231 #define a_name u.name
236 * Intervals at which we flush out "message repeated" messages,
237 * in seconds after previous message is logged. After each flush,
238 * we move to the next interval until we reach the largest.
240 int repeatinterval
[] = { 30, 120, 600 }; /* # of secs before flush */
241 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
242 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
243 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
244 (f)->f_repeatcount = MAXREPEAT; \
247 /* values for f_type */
248 #define F_UNUSED 0 /* unused entry */
249 #define F_FILE 1 /* regular file */
250 #define F_TTY 2 /* terminal */
251 #define F_CONSOLE 3 /* console terminal */
252 #define F_FORW 4 /* remote machine */
253 #define F_USERS 5 /* list of users */
254 #define F_WALL 6 /* everyone logged on */
255 #define F_PIPE 7 /* pipe to program */
256 #define F_CHECKTTY 8 /* think it's a tty, so check */
258 const char *TypeNames
[9] = {
259 "UNUSED", "FILE", "TTY", "CONSOLE",
260 "FORW", "USERS", "WALL", "PIPE",
264 static struct filed
*Files
= NULL
; /* Log files that we write to */
265 static struct filed consfile
; /* Console */
267 static int Debug
= 0; /* debug flag */
268 static int resolve
= 1; /* resolve hostname */
269 static char LocalHostName
[MAXHOSTNAMELEN
]; /* our hostname */
270 static char *LocalDomain
= NULL
; /* our local domain name */
271 static int *finet
= NULL
; /* Internet datagram socket */
272 static int fklog
= -1; /* /dev/klog */
273 static int Initialized
= 0; /* set when we have initialized ourselves */
274 static int MarkInterval
= 20 * 60; /* interval between marks in seconds */
275 static int MarkSeq
= 0; /* mark sequence number */
277 static int RcvSockBufSize
= 49152; /* Our default receive socket buffer size 3301629*/
279 static int SecureMode
= 0; /* when true, receive only unix domain socks */
281 static int family
= PF_UNSPEC
; /* protocol family (IPv4, IPv6 or both) */
283 static int family
= PF_INET
; /* protocol family (IPv4 only) */
285 static int send_to_all
= 0; /* send message to all IPv4/IPv6 addresses */
286 static int use_bootfile
= 0; /* log entire bootfile for every kern msg */
287 static int no_compress
= 0; /* don't compress messages (1=pipes, 2=all) */
289 static char bootfile
[MAXLINE
+1]; /* booted kernel file */
291 struct allowedpeer
*AllowedPeers
= NULL
; /* List of allowed peers */
292 static int NumAllowed
= 0; /* Number of entries in AllowedPeers */
294 static int UniquePriority
= 0; /* Only log specified priority? */
295 static int LogFacPri
= 0; /* Put facility and priority in log message: */
296 /* 0=no, 1=numeric, 2=names */
297 static int KeepKernFac
= 0; /* Keep remotely logged kernel facility */
298 static int create_files
= 0;
300 volatile sig_atomic_t MarkSet
= 0, WantDie
= 0;
302 static int allowaddr(char *);
303 static void cfline(const char *, struct filed
*,
304 const char *, const char *);
305 static const char *cvthname(struct sockaddr
*);
306 static void deadq_enter(pid_t
, const char *);
307 static int deadq_remove(pid_t
);
308 static int decode(const char *, CODE
*);
309 static void die(int);
310 static void dodie(int);
311 static void domark(int);
312 static void fprintlog(struct filed
*, int, const char *);
313 static int *socksetup(int, const char *);
314 static void init(int);
315 static void logerror(const char *);
316 static void logmsg(int, const char *, const char *, int);
317 static void log_deadchild(pid_t
, int, const char *);
318 static void markit(void);
319 static int skip_message(const char *, const char *);
320 static void printline(const char *, char *);
321 static void printsys(char *);
322 static int p_open(const char *, pid_t
*);
323 static void readklog(void);
324 static void reapchild(int);
325 static void usage(void);
326 static int validate(struct sockaddr
*, const char *);
327 static void unmapped(struct sockaddr
*);
328 static void wallmsg(struct filed
*, struct iovec
*);
329 static int waitdaemon(int, int, int);
330 static void timedout(int);
333 main(int argc
, char *argv
[])
335 int ch
, i
, fdsrmax
= 0, l
;
336 struct sockaddr_un sunx
, fromunix
;
337 struct sockaddr_storage frominet
;
340 char line
[MAXLINE
+ 1];
341 const char *bindhostname
, *hname
;
342 struct timeval tv
, *tvp
;
343 struct sigaction sact
;
350 while ((ch
= getopt(argc
, argv
, "46ACa:b:cdf:kl:m:nop:P:suv")) != -1)
366 case 'a': /* allow specific network addresses only */
367 if (allowaddr(optarg
) == -1)
371 bindhostname
= optarg
;
376 case 'd': /* debug */
379 case 'f': /* configuration file */
382 case 'k': /* keep remote kern fac */
386 if (nfunix
< MAXFUNIX
)
387 funixn
[nfunix
++] = optarg
;
389 warnx("out of descriptors, ignoring %s",
392 case 'm': /* mark interval */
393 MarkInterval
= atoi(optarg
) * 60;
404 case 'P': /* path for alt. PID */
407 case 's': /* no network mode */
410 case 'u': /* only log specified priority */
413 case 'v': /* log facility and priority */
420 if ((argc
-= optind
) != 0)
424 ppid
= waitdaemon(0, 0, 30);
426 err(1, "could not become daemon");
434 consfile
.f_type
= F_CONSOLE
;
435 (void)strlcpy(consfile
.f_un
.f_fname
, ctty
+ sizeof _PATH_DEV
- 1,
436 sizeof(consfile
.f_un
.f_fname
));
438 /* We lack getbootfile() 3187949 and 3187947 */
439 (void)strlcpy(bootfile
, "/mach_kernel", sizeof("/mach_kernel"));
441 (void)strlcpy(bootfile
, getbootfile(), sizeof(bootfile
));
443 (void)signal(SIGTERM
, dodie
);
444 (void)signal(SIGINT
, Debug
? dodie
: SIG_IGN
);
445 (void)signal(SIGQUIT
, Debug
? dodie
: SIG_IGN
);
447 * We don't want the SIGCHLD and SIGHUP handlers to interfere
448 * with each other; they are likely candidates for being called
449 * simultaneously (SIGHUP closes pipe descriptor, process dies,
453 sigaddset(&mask
, SIGHUP
);
454 sact
.sa_handler
= reapchild
;
456 sact
.sa_flags
= SA_RESTART
;
457 (void)sigaction(SIGCHLD
, &sact
, NULL
);
458 (void)signal(SIGALRM
, domark
);
459 (void)signal(SIGPIPE
, SIG_IGN
); /* We'll catch EPIPE instead. */
460 notify_register_signal(NETWORK_CHANGE_NOTIFICATION
, SIGHUP
, &nctoken
);
461 (void)alarm(TIMERINTVL
);
463 TAILQ_INIT(&deadq_head
);
466 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
468 for (i
= 0; i
< nfunix
; i
++) {
469 (void)unlink(funixn
[i
]);
470 memset(&sunx
, 0, sizeof(sunx
));
471 sunx
.sun_family
= AF_UNIX
;
472 (void)strlcpy(sunx
.sun_path
, funixn
[i
], sizeof(sunx
.sun_path
));
473 funix
[i
] = socket(AF_UNIX
, SOCK_DGRAM
, 0);
475 bind(funix
[i
], (struct sockaddr
*)&sunx
,
476 SUN_LEN(&sunx
)) < 0 ||
477 chmod(funixn
[i
], 0666) < 0) {
478 (void)snprintf(line
, sizeof line
,
479 "cannot create %s", funixn
[i
]);
481 dprintf("cannot create %s (%d)\n", funixn
[i
], errno
);
486 if (setsockopt(funix
[i
], SOL_SOCKET
, SO_RCVBUF
, &RcvSockBufSize
, sizeof(int)) < 0)
487 logerror("setsockopt funix");
491 finet
= socksetup(family
, bindhostname
);
495 for (i
= 0; i
< *finet
; i
++) {
496 if (shutdown(finet
[i
+1], SHUT_RD
) < 0) {
497 logerror("shutdown");
503 dprintf("listening on inet and/or inet6 socket\n");
505 dprintf("sending on inet and/or inet6 socket\n");
508 if ((fklog
= open(_PATH_KLOG
, O_RDONLY
, 0)) >= 0)
509 if (fcntl(fklog
, F_SETFL
, O_NONBLOCK
) < 0)
512 dprintf("can't open %s (%d)\n", _PATH_KLOG
, errno
);
514 /* tuck my process id away */
515 fp
= fopen(PidFile
, "w");
517 fprintf(fp
, "%d\n", getpid());
521 dprintf("off & running....\n");
524 /* prevent SIGHUP and SIGCHLD handlers from running in parallel */
526 sigaddset(&mask
, SIGCHLD
);
527 sact
.sa_handler
= init
;
529 sact
.sa_flags
= SA_RESTART
;
530 (void)sigaction(SIGHUP
, &sact
, NULL
);
533 tv
.tv_sec
= tv
.tv_usec
= 0;
535 if (fklog
!= -1 && fklog
> fdsrmax
)
537 if (finet
&& !SecureMode
) {
538 for (i
= 0; i
< *finet
; i
++) {
539 if (finet
[i
+1] != -1 && finet
[i
+1] > fdsrmax
)
540 fdsrmax
= finet
[i
+1];
543 for (i
= 0; i
< nfunix
; i
++) {
544 if (funix
[i
] != -1 && funix
[i
] > fdsrmax
)
548 fdsr
= (fd_set
*)calloc(howmany(fdsrmax
+1, NFDBITS
),
551 errx(1, "calloc fd_set");
559 bzero(fdsr
, howmany(fdsrmax
+1, NFDBITS
) *
564 if (finet
&& !SecureMode
) {
565 for (i
= 0; i
< *finet
; i
++) {
566 if (finet
[i
+1] != -1)
567 FD_SET(finet
[i
+1], fdsr
);
570 for (i
= 0; i
< nfunix
; i
++) {
572 FD_SET(funix
[i
], fdsr
);
575 i
= select(fdsrmax
+1, fdsr
, NULL
, NULL
, tvp
);
589 if (fklog
!= -1 && FD_ISSET(fklog
, fdsr
))
591 if (finet
&& !SecureMode
) {
592 for (i
= 0; i
< *finet
; i
++) {
593 if (FD_ISSET(finet
[i
+1], fdsr
)) {
594 len
= sizeof(frominet
);
595 l
= recvfrom(finet
[i
+1], line
, MAXLINE
,
596 0, (struct sockaddr
*)&frominet
,
600 hname
= cvthname((struct sockaddr
*)&frominet
);
601 unmapped((struct sockaddr
*)&frominet
);
602 if (validate((struct sockaddr
*)&frominet
, hname
))
603 printline(hname
, line
);
604 } else if (l
< 0 && errno
!= EINTR
)
605 logerror("recvfrom inet");
609 for (i
= 0; i
< nfunix
; i
++) {
610 if (funix
[i
] != -1 && FD_ISSET(funix
[i
], fdsr
)) {
611 len
= sizeof(fromunix
);
612 l
= recvfrom(funix
[i
], line
, MAXLINE
, 0,
613 (struct sockaddr
*)&fromunix
, &len
);
616 printline(LocalHostName
, line
);
617 } else if (l
< 0 && errno
!= EINTR
)
618 logerror("recvfrom unix");
627 unmapped(struct sockaddr
*sa
)
629 struct sockaddr_in6
*sin6
;
630 struct sockaddr_in sin4
;
632 if (sa
->sa_family
!= AF_INET6
)
634 if (sa
->sa_len
!= sizeof(struct sockaddr_in6
) ||
635 sizeof(sin4
) > sa
->sa_len
)
637 sin6
= (struct sockaddr_in6
*)sa
;
638 if (!IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
))
641 memset(&sin4
, 0, sizeof(sin4
));
642 sin4
.sin_family
= AF_INET
;
643 sin4
.sin_len
= sizeof(struct sockaddr_in
);
644 memcpy(&sin4
.sin_addr
, &sin6
->sin6_addr
.s6_addr
[12],
645 sizeof(sin4
.sin_addr
));
646 sin4
.sin_port
= sin6
->sin6_port
;
648 memcpy(sa
, &sin4
, sin4
.sin_len
);
655 fprintf(stderr
, "%s\n%s\n%s\n%s\n",
656 "usage: syslogd [-46Acdknosuv] [-a allowed_peer]",
657 " [-b bind address] [-f config_file]",
658 " [-l log_socket] [-m mark_interval]",
659 " [-P pid_file] [-p log_socket]");
664 * Take a raw input line, decode the message, and print the message
665 * on the appropriate log files.
668 printline(const char *hname
, char *msg
)
671 char *p
, *q
, line
[MAXLINE
+ 1];
673 /* test for special codes */
678 while (isdigit(*++p
))
679 pri
= 10 * pri
+ (*p
- '0');
683 if (pri
&~ (LOG_FACMASK
|LOG_PRIMASK
))
686 /* don't allow users to log kernel messages */
687 if (LOG_FAC(pri
) == LOG_KERN
&& !KeepKernFac
)
688 pri
= LOG_MAKEPRI(LOG_USER
, LOG_PRI(pri
));
692 while ((c
= (unsigned char)*p
++) != '\0' &&
693 q
< &line
[sizeof(line
) - 4]) {
695 /* Gross installer hack to be removed 3314128 */
696 if (LOG_FACMASK
&pri
!= LOG_INSTALL
) {
697 if ((c
& 0x80) && c
< 0xA0) {
704 if (isascii(c
) && iscntrl(c
)) {
707 } else if (c
== '\t') {
719 logmsg(pri
, line
, hname
, 0);
723 * Read /dev/klog while data are available, split into lines.
728 char *p
, *q
, line
[MAXLINE
+ 1];
733 i
= read(fklog
, line
+ len
, MAXLINE
- 1 - len
);
735 line
[i
+ len
] = '\0';
737 if (i
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
) {
744 for (p
= line
; (q
= strchr(p
, '\n')) != NULL
; p
= q
+ 1) {
749 if (len
>= MAXLINE
- 1) {
754 memmove(line
, p
, len
+ 1);
761 * Take a raw input line from /dev/klog, format similar to syslog().
768 flags
= ISKERNEL
| SYNC_FILE
| ADDDATE
; /* fsync after write */
772 while (isdigit(*++p
))
773 pri
= 10 * pri
+ (*p
- '0');
777 if ((pri
& LOG_FACMASK
) == LOG_CONSOLE
)
781 /* kernel printf's come out on console */
784 if (pri
&~ (LOG_FACMASK
|LOG_PRIMASK
))
786 logmsg(pri
, p
, LocalHostName
, flags
);
792 * Match a program or host name against a specification.
793 * Return a non-0 value if the message must be ignored
794 * based on the specification.
797 skip_message(const char *name
, const char *spec
) {
801 /* Behaviour on explicit match */
815 s
= strstr (spec
, name
);
818 prev
= (s
== spec
? ',' : *(s
- 1));
819 next
= *(s
+ strlen (name
));
821 if (prev
== ',' && (next
== '\0' || next
== ','))
822 /* Explicit match: skip iff the spec is an
827 /* No explicit match for this name: skip the message iff
828 the spec is an inclusive one. */
833 * Log a message to the appropriate log files, users, etc. based on
837 logmsg(int pri
, const char *msg
, const char *from
, int flags
)
840 int i
, fac
, msglen
, omask
, prilev
;
841 const char *timestamp
;
842 char prog
[NAME_MAX
+1];
845 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
846 pri
, flags
, from
, msg
);
848 omask
= sigblock(sigmask(SIGHUP
)|sigmask(SIGALRM
));
851 * Check to see if msg looks non-standard.
853 msglen
= strlen(msg
);
854 if (msglen
< 16 || msg
[3] != ' ' || msg
[6] != ' ' ||
855 msg
[9] != ':' || msg
[12] != ':' || msg
[15] != ' ')
859 if (flags
& ADDDATE
) {
860 timestamp
= ctime(&now
) + 4;
867 /* skip leading blanks */
868 while (isspace(*msg
)) {
873 /* extract facility and priority level */
875 fac
= LOG_NFACILITIES
;
878 prilev
= LOG_PRI(pri
);
880 /* extract program name */
881 for (i
= 0; i
< NAME_MAX
; i
++) {
882 if (!isprint(msg
[i
]) || msg
[i
] == ':' || msg
[i
] == '[')
888 /* add kernel prefix for kernel messages */
889 if (flags
& ISKERNEL
) {
890 snprintf(buf
, sizeof(buf
), "%s: %s",
891 use_bootfile
? bootfile
: "kernel", msg
);
893 msglen
= strlen(buf
);
896 /* log the message to the particular outputs */
899 f
->f_file
= open(ctty
, O_WRONLY
, 0);
901 if (f
->f_file
>= 0) {
902 fprintlog(f
, flags
, msg
);
903 (void)close(f
->f_file
);
905 (void)sigsetmask(omask
);
908 for (f
= Files
; f
; f
= f
->f_next
) {
909 /* skip messages that are incorrect priority */
910 if (!(((f
->f_pcmp
[fac
] & PRI_EQ
) && (f
->f_pmask
[fac
] == prilev
))
911 ||((f
->f_pcmp
[fac
] & PRI_LT
) && (f
->f_pmask
[fac
] < prilev
))
912 ||((f
->f_pcmp
[fac
] & PRI_GT
) && (f
->f_pmask
[fac
] > prilev
))
914 || f
->f_pmask
[fac
] == INTERNAL_NOPRI
)
917 /* skip messages with the incorrect hostname */
918 if (skip_message(from
, f
->f_host
))
921 /* skip messages with the incorrect program name */
922 if (skip_message(prog
, f
->f_program
))
925 /* skip message to console if it has already been printed */
926 if (f
->f_type
== F_CONSOLE
&& (flags
& IGN_CONS
))
929 /* don't output marks to recently written files */
930 if ((flags
& MARK
) && (now
- f
->f_time
) < MarkInterval
/ 2)
934 * suppress duplicate lines to this file
936 if (no_compress
- (f
->f_type
!= F_PIPE
) < 1 &&
937 (flags
& MARK
) == 0 && msglen
== f
->f_prevlen
&&
938 !strcmp(msg
, f
->f_prevline
) &&
939 !strcasecmp(from
, f
->f_prevhost
)) {
940 (void)strlcpy(f
->f_lasttime
, timestamp
, 16);
942 dprintf("msg repeated %d times, %ld sec of %d\n",
943 f
->f_prevcount
, (long)(now
- f
->f_time
),
944 repeatinterval
[f
->f_repeatcount
]);
946 * If domark would have logged this by now,
947 * flush it now (so we don't hold isolated messages),
948 * but back off so we'll flush less often
951 if (now
> REPEATTIME(f
)) {
952 fprintlog(f
, flags
, (char *)NULL
);
956 /* new line, save it */
958 fprintlog(f
, 0, (char *)NULL
);
959 f
->f_repeatcount
= 0;
961 (void)strlcpy(f
->f_lasttime
, timestamp
, 16);
962 (void)strlcpy(f
->f_prevhost
, from
,
963 sizeof(f
->f_prevhost
));
964 if (msglen
< MAXSVLINE
) {
965 f
->f_prevlen
= msglen
;
966 (void)strlcpy(f
->f_prevline
, msg
, sizeof(f
->f_prevline
));
967 fprintlog(f
, flags
, (char *)NULL
);
969 f
->f_prevline
[0] = 0;
971 fprintlog(f
, flags
, msg
);
975 (void)sigsetmask(omask
);
979 fprintlog(struct filed
*f
, int flags
, const char *msg
)
985 char line
[MAXLINE
+ 1], repbuf
[80], greetings
[200], *wmsg
= NULL
;
989 if (f
->f_type
== F_WALL
) {
990 v
->iov_base
= greetings
;
991 v
->iov_len
= snprintf(greetings
, sizeof greetings
,
992 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
993 f
->f_prevhost
, ctime(&now
));
1000 v
->iov_base
= f
->f_lasttime
;
1009 static char fp_buf
[30]; /* Hollow laugh */
1010 int fac
= f
->f_prevpri
& LOG_FACMASK
;
1011 int pri
= LOG_PRI(f
->f_prevpri
);
1012 const char *f_s
= NULL
;
1013 char f_n
[5]; /* Hollow laugh */
1014 const char *p_s
= NULL
;
1015 char p_n
[5]; /* Hollow laugh */
1017 if (LogFacPri
> 1) {
1020 for (c
= facilitynames
; c
->c_name
; c
++) {
1021 if (c
->c_val
== fac
) {
1026 for (c
= prioritynames
; c
->c_name
; c
++) {
1027 if (c
->c_val
== pri
) {
1034 snprintf(f_n
, sizeof f_n
, "%d", LOG_FAC(fac
));
1038 snprintf(p_n
, sizeof p_n
, "%d", pri
);
1041 snprintf(fp_buf
, sizeof fp_buf
, "<%s.%s> ", f_s
, p_s
);
1042 v
->iov_base
= fp_buf
;
1043 v
->iov_len
= strlen(fp_buf
);
1050 v
->iov_base
= f
->f_prevhost
;
1051 v
->iov_len
= strlen(v
->iov_base
);
1058 wmsg
= strdup(msg
); /* XXX iov_base needs a `const' sibling. */
1064 v
->iov_len
= strlen(msg
);
1065 } else if (f
->f_prevcount
> 1) {
1066 v
->iov_base
= repbuf
;
1067 v
->iov_len
= snprintf(repbuf
, sizeof repbuf
,
1068 "last message repeated %d times", f
->f_prevcount
);
1070 v
->iov_base
= f
->f_prevline
;
1071 v
->iov_len
= f
->f_prevlen
;
1075 if (f
->f_file
== -1) {
1076 int oflags
= O_WRONLY
|O_APPEND
;
1082 if( stat(f
->f_un
.f_fname
, &sb
) == 0 ) {
1086 if (create_files
&& !exists
)
1088 if ((f
->f_file
= open(f
->f_un
.f_fname
, oflags
, mode
)) < 0) {
1089 f
->f_type
= F_UNUSED
;
1090 /* We can no longer log this error, since calling
1091 * logerror() could bring us back here again.
1092 * Instead, call dprintf(), which will aid in
1093 * debugging, but not cause the looping.
1095 dprintf("Error openning %s", f
->f_un
.f_fname
);
1096 if (msg
) free(wmsg
);
1099 /* Only chown the file if we created it. If it already
1100 * existed, leave whatever was there.
1103 gr
= getgrnam("admin");
1105 fchown(f
->f_file
, 0, gr
->gr_gid
);
1107 if (f
->f_type
== F_CHECKTTY
) {
1108 if (isatty(f
->f_file
)) {
1109 if (strcmp(f
->f_un
.f_fname
, ctty
) == 0)
1110 f
->f_type
= F_CONSOLE
;
1117 dprintf("Logging to %s", TypeNames
[f
->f_type
]);
1120 switch (f
->f_type
) {
1126 dprintf(" %s\n", f
->f_un
.f_forw
.f_hname
);
1127 /* check for local vs remote messages */
1128 if (strcasecmp(f
->f_prevhost
, LocalHostName
))
1129 l
= snprintf(line
, sizeof line
- 1,
1130 "<%d>%.15s Forwarded from %s: %s",
1131 f
->f_prevpri
, iov
[0].iov_base
, f
->f_prevhost
,
1134 l
= snprintf(line
, sizeof line
- 1, "<%d>%.15s %s",
1135 f
->f_prevpri
, iov
[0].iov_base
, iov
[5].iov_base
);
1138 else if (l
> MAXLINE
)
1142 for (r
= f
->f_un
.f_forw
.f_addr
; r
; r
= r
->ai_next
) {
1143 for (i
= 0; i
< *finet
; i
++) {
1146 * should we check AF first, or just
1147 * trial and error? FWD
1150 address_family_of(finet
[i
+1]))
1152 lsent
= sendto(finet
[i
+1], line
, l
, 0,
1153 r
->ai_addr
, r
->ai_addrlen
);
1157 if (lsent
== l
&& !send_to_all
)
1160 dprintf("lsent/l: %d/%d\n", lsent
, l
);
1171 /* case ENOTSOCK: */
1173 /* case EMSGSIZE: */
1176 /* case ECONNREFUSED: */
1178 dprintf("removing entry\n");
1179 (void)close(f
->f_file
);
1180 f
->f_type
= F_UNUSED
;
1188 dprintf(" %s\n", f
->f_un
.f_fname
);
1191 if (writev(f
->f_file
, iov
, 7) < 0) {
1193 (void)close(f
->f_file
);
1194 f
->f_type
= F_UNUSED
;
1196 logerror(f
->f_un
.f_fname
);
1197 } else if (flags
& SYNC_FILE
)
1198 (void)fsync(f
->f_file
);
1202 dprintf(" %s\n", f
->f_un
.f_pipe
.f_pname
);
1205 if (f
->f_un
.f_pipe
.f_pid
== 0) {
1206 if ((f
->f_file
= p_open(f
->f_un
.f_pipe
.f_pname
,
1207 &f
->f_un
.f_pipe
.f_pid
)) < 0) {
1208 f
->f_type
= F_UNUSED
;
1209 logerror(f
->f_un
.f_pipe
.f_pname
);
1213 if (writev(f
->f_file
, iov
, 7) < 0) {
1215 (void)close(f
->f_file
);
1216 if (f
->f_un
.f_pipe
.f_pid
> 0)
1217 deadq_enter(f
->f_un
.f_pipe
.f_pid
,
1218 f
->f_un
.f_pipe
.f_pname
);
1219 f
->f_un
.f_pipe
.f_pid
= 0;
1221 logerror(f
->f_un
.f_pipe
.f_pname
);
1226 if (flags
& IGN_CONS
) {
1227 dprintf(" (ignored)\n");
1233 dprintf(" %s%s\n", _PATH_DEV
, f
->f_un
.f_fname
);
1234 v
->iov_base
= "\r\n";
1237 errno
= 0; /* ttymsg() only sometimes returns an errno */
1238 if ((msgret
= ttymsg(iov
, 7, f
->f_un
.f_fname
, 10))) {
1239 f
->f_type
= F_UNUSED
;
1247 v
->iov_base
= "\r\n";
1258 * WALLMSG -- Write a message to the world at large
1260 * Write the specified message to either the entire
1261 * world, or a list of approved users.
1264 wallmsg(struct filed
*f
, struct iovec
*iov
)
1266 static int reenter
; /* avoid calling ourselves */
1271 char line
[sizeof(ut
.ut_line
) + 1];
1275 if ((uf
= fopen(_PATH_UTMP
, "r")) == NULL
) {
1276 logerror(_PATH_UTMP
);
1281 while (fread((char *)&ut
, sizeof(ut
), 1, uf
) == 1) {
1282 if (ut
.ut_name
[0] == '\0')
1284 (void)strlcpy(line
, ut
.ut_line
, sizeof(line
));
1285 if (f
->f_type
== F_WALL
) {
1286 if ((p
= ttymsg(iov
, 7, line
, TTYMSGTIME
)) != NULL
) {
1287 errno
= 0; /* already in msg */
1292 /* should we send the message to this user? */
1293 for (i
= 0; i
< MAXUNAMES
; i
++) {
1294 if (!f
->f_un
.f_uname
[i
][0])
1296 if (!strncmp(f
->f_un
.f_uname
[i
], ut
.ut_name
,
1298 if ((p
= ttymsg(iov
, 7, line
, TTYMSGTIME
))
1300 errno
= 0; /* already in msg */
1312 reapchild(int signo
)
1318 while ((pid
= wait3(&status
, WNOHANG
, (struct rusage
*)NULL
)) > 0) {
1320 /* Don't tell while we are initting. */
1323 /* First, look if it's a process from the dead queue. */
1324 if (deadq_remove(pid
))
1327 /* Now, look in list of active processes. */
1328 for (f
= Files
; f
; f
= f
->f_next
)
1329 if (f
->f_type
== F_PIPE
&&
1330 f
->f_un
.f_pipe
.f_pid
== pid
) {
1331 (void)close(f
->f_file
);
1332 f
->f_un
.f_pipe
.f_pid
= 0;
1333 log_deadchild(pid
, status
,
1334 f
->f_un
.f_pipe
.f_pname
);
1343 * Return a printable representation of a host address.
1346 cvthname(struct sockaddr
*f
)
1349 sigset_t omask
, nmask
;
1351 static char hname
[NI_MAXHOST
], ip
[NI_MAXHOST
];
1353 error
= getnameinfo((struct sockaddr
*)f
,
1354 ((struct sockaddr
*)f
)->sa_len
,
1355 ip
, sizeof ip
, NULL
, 0,
1356 NI_NUMERICHOST
| withscopeid
);
1357 dprintf("cvthname(%s)\n", ip
);
1360 dprintf("Malformed from address %s\n", gai_strerror(error
));
1366 sigemptyset(&nmask
);
1367 sigaddset(&nmask
, SIGHUP
);
1368 sigprocmask(SIG_BLOCK
, &nmask
, &omask
);
1369 error
= getnameinfo((struct sockaddr
*)f
,
1370 ((struct sockaddr
*)f
)->sa_len
,
1371 hname
, sizeof hname
, NULL
, 0,
1372 NI_NAMEREQD
| withscopeid
);
1373 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
1375 dprintf("Host name for your address (%s) unknown\n", ip
);
1378 /* XXX Not quite correct, but close enough for government work. */
1379 if ((p
= strchr(hname
, '.')) && strcasecmp(p
+ 1, LocalDomain
) == 0)
1399 * Print syslogd errors some place.
1402 logerror(const char *type
)
1408 sizeof buf
, "syslogd: %s: %s", type
, strerror(errno
));
1410 (void)snprintf(buf
, sizeof buf
, "syslogd: %s", type
);
1412 dprintf("%s\n", buf
);
1413 logmsg(LOG_SYSLOG
|LOG_ERR
, buf
, LocalHostName
, ADDDATE
);
1420 int was_initialized
;
1424 was_initialized
= Initialized
;
1425 Initialized
= 0; /* Don't log SIGCHLDs. */
1426 for (f
= Files
; f
!= NULL
; f
= f
->f_next
) {
1427 /* flush any pending output */
1429 fprintlog(f
, 0, (char *)NULL
);
1430 if (f
->f_type
== F_PIPE
)
1431 (void)close(f
->f_file
);
1433 Initialized
= was_initialized
;
1435 dprintf("syslogd: exiting on signal %d\n", signo
);
1436 (void)snprintf(buf
, sizeof(buf
), "exiting on signal %d", signo
);
1440 for (i
= 0; i
< nfunix
; i
++)
1441 if (funixn
[i
] && funix
[i
] != -1)
1442 (void)unlink(funixn
[i
]);
1447 * INIT -- Initialize syslogd from configuration table
1454 struct filed
*f
, *next
, **nextp
;
1456 char cline
[LINE_MAX
];
1457 char prog
[NAME_MAX
+1];
1458 char host
[MAXHOSTNAMELEN
];
1459 char oldLocalHostName
[MAXHOSTNAMELEN
];
1460 char hostMsg
[2*MAXHOSTNAMELEN
+40];
1461 char bootfileMsg
[LINE_MAX
];
1466 * Load hostname (may have changed).
1469 (void)strlcpy(oldLocalHostName
, LocalHostName
,
1470 sizeof(oldLocalHostName
));
1471 if (gethostname(LocalHostName
, sizeof(LocalHostName
)))
1472 err(EX_OSERR
, "gethostname() failed");
1473 if ((p
= strchr(LocalHostName
, '.')) != NULL
) {
1481 * Close all open log files.
1484 for (f
= Files
; f
!= NULL
; f
= next
) {
1485 /* flush any pending output */
1487 fprintlog(f
, 0, (char *)NULL
);
1489 switch (f
->f_type
) {
1494 (void)close(f
->f_file
);
1497 (void)close(f
->f_file
);
1498 if (f
->f_un
.f_pipe
.f_pid
> 0)
1499 deadq_enter(f
->f_un
.f_pipe
.f_pid
,
1500 f
->f_un
.f_pipe
.f_pname
);
1501 f
->f_un
.f_pipe
.f_pid
= 0;
1505 if (f
->f_program
) free(f
->f_program
);
1506 if (f
->f_host
) free(f
->f_host
);
1512 /* open the configuration file */
1513 if ((cf
= fopen(ConfFile
, "r")) == NULL
) {
1514 dprintf("cannot open %s\n", ConfFile
);
1515 *nextp
= (struct filed
*)calloc(1, sizeof(*f
));
1516 if (*nextp
== NULL
) {
1520 cfline("*.ERR\t/dev/console", *nextp
, "*", "*");
1521 (*nextp
)->f_next
= (struct filed
*)calloc(1, sizeof(*f
));
1522 if ((*nextp
)->f_next
== NULL
) {
1526 cfline("*.PANIC\t*", (*nextp
)->f_next
, "*", "*");
1532 * Foreach line in the conf table, open that file.
1535 (void)strlcpy(host
, "*", sizeof(host
));
1536 (void)strlcpy(prog
, "*", sizeof(prog
));
1537 while (fgets(cline
, sizeof(cline
), cf
) != NULL
) {
1539 * check for end-of-section, comments, strip off trailing
1540 * spaces and newline character. #!prog is treated specially:
1541 * following lines apply only to that program.
1543 for (p
= cline
; isspace(*p
); ++p
)
1549 if (*p
!= '!' && *p
!= '+' && *p
!= '-')
1552 if (*p
== '+' || *p
== '-') {
1556 if ((!*p
) || (*p
== '*')) {
1557 (void)strlcpy(host
, "*", sizeof(host
));
1562 for (i
= 1; i
< MAXHOSTNAMELEN
- 1; i
++) {
1563 if (!isalnum(*p
) && *p
!= '.' && *p
!= '-'
1573 while (isspace(*p
)) p
++;
1574 if ((!*p
) || (*p
== '*')) {
1575 (void)strlcpy(prog
, "*", sizeof(prog
));
1578 for (i
= 0; i
< NAME_MAX
; i
++) {
1586 for (p
= strchr(cline
, '\0'); isspace(*--p
);)
1589 f
= (struct filed
*)calloc(1, sizeof(*f
));
1596 cfline(cline
, f
, prog
, host
);
1599 /* close the configuration file */
1605 for (f
= Files
; f
; f
= f
->f_next
) {
1606 for (i
= 0; i
<= LOG_NFACILITIES
; i
++)
1607 if (f
->f_pmask
[i
] == INTERNAL_NOPRI
)
1610 printf("%d ", f
->f_pmask
[i
]);
1611 printf("%s: ", TypeNames
[f
->f_type
]);
1612 switch (f
->f_type
) {
1614 printf("%s", f
->f_un
.f_fname
);
1619 printf("%s%s", _PATH_DEV
, f
->f_un
.f_fname
);
1623 printf("%s", f
->f_un
.f_forw
.f_hname
);
1627 printf("%s", f
->f_un
.f_pipe
.f_pname
);
1631 for (i
= 0; i
< MAXUNAMES
&& *f
->f_un
.f_uname
[i
]; i
++)
1632 printf("%s, ", f
->f_un
.f_uname
[i
]);
1636 printf(" (%s)", f
->f_program
);
1641 logmsg(LOG_SYSLOG
|LOG_INFO
, "syslogd: restart", LocalHostName
, ADDDATE
);
1642 dprintf("syslogd: restarted\n");
1644 * Log a change in hostname, but only on a restart.
1646 if (signo
!= 0 && strcmp(oldLocalHostName
, LocalHostName
) != 0) {
1647 (void)snprintf(hostMsg
, sizeof(hostMsg
),
1648 "syslogd: hostname changed, \"%s\" to \"%s\"",
1649 oldLocalHostName
, LocalHostName
);
1650 logmsg(LOG_SYSLOG
|LOG_INFO
, hostMsg
, LocalHostName
, ADDDATE
);
1651 dprintf("%s\n", hostMsg
);
1654 * Log the kernel boot file if we aren't going to use it as
1655 * the prefix, and if this is *not* a restart.
1657 if (signo
== 0 && !use_bootfile
) {
1658 (void)snprintf(bootfileMsg
, sizeof(bootfileMsg
),
1659 "syslogd: kernel boot file is %s", bootfile
);
1660 logmsg(LOG_KERN
|LOG_INFO
, bootfileMsg
, LocalHostName
, ADDDATE
);
1661 dprintf("%s\n", bootfileMsg
);
1666 * Crack a configuration file line
1669 cfline(const char *line
, struct filed
*f
, const char *prog
, const char *host
)
1671 struct addrinfo hints
, *res
;
1675 char buf
[MAXLINE
], ebuf
[100];
1677 dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line
, prog
, host
);
1679 errno
= 0; /* keep strerror() stuff out of logerror messages */
1681 /* clear out file entry */
1682 memset(f
, 0, sizeof(*f
));
1683 for (i
= 0; i
<= LOG_NFACILITIES
; i
++)
1684 f
->f_pmask
[i
] = INTERNAL_NOPRI
;
1686 /* save hostname if any */
1687 if (host
&& *host
== '*')
1692 f
->f_host
= strdup(host
);
1693 if (f
->f_host
== NULL
) {
1697 hl
= strlen(f
->f_host
);
1698 if (f
->f_host
[hl
-1] == '.')
1699 f
->f_host
[--hl
] = '\0';
1700 dl
= strlen(LocalDomain
) + 1;
1701 if (hl
> dl
&& f
->f_host
[hl
-dl
] == '.' &&
1702 strcasecmp(f
->f_host
+ hl
- dl
+ 1, LocalDomain
) == 0)
1703 f
->f_host
[hl
-dl
] = '\0';
1706 /* save program name if any */
1707 if (prog
&& *prog
== '*')
1710 f
->f_program
= strdup(prog
);
1711 if (f
->f_program
== NULL
) {
1717 /* scan through the list of selectors */
1718 for (p
= line
; *p
&& *p
!= '\t' && *p
!= ' ';) {
1723 /* find the end of this facility name list */
1724 for (q
= p
; *q
&& *q
!= '\t' && *q
!= ' ' && *q
++ != '.'; )
1727 /* get the priority comparison */
1755 /* collect priority name */
1756 for (bp
= buf
; *q
&& !strchr("\t,; ", *q
); )
1761 while (strchr(",;", *q
))
1764 /* decode priority name */
1766 pri
= LOG_PRIMASK
+ 1;
1767 pri_cmp
= PRI_LT
| PRI_EQ
| PRI_GT
;
1769 pri
= decode(buf
, prioritynames
);
1771 (void)snprintf(ebuf
, sizeof ebuf
,
1772 "unknown priority name \"%s\"", buf
);
1778 pri_cmp
= (UniquePriority
)
1783 pri_cmp
^= PRI_LT
| PRI_EQ
| PRI_GT
;
1785 /* scan facilities */
1786 while (*p
&& !strchr("\t.; ", *p
)) {
1787 for (bp
= buf
; *p
&& !strchr("\t,;. ", *p
); )
1792 for (i
= 0; i
< LOG_NFACILITIES
; i
++) {
1793 f
->f_pmask
[i
] = pri
;
1794 f
->f_pcmp
[i
] = pri_cmp
;
1797 i
= decode(buf
, facilitynames
);
1799 (void)snprintf(ebuf
, sizeof ebuf
,
1800 "unknown facility name \"%s\"",
1805 f
->f_pmask
[i
>> 3] = pri
;
1806 f
->f_pcmp
[i
>> 3] = pri_cmp
;
1808 while (*p
== ',' || *p
== ' ')
1815 /* skip to action part */
1816 while (*p
== '\t' || *p
== ' ')
1822 p
= strsep(&port
, ":");
1823 (void)strlcpy(f
->f_un
.f_forw
.f_hname
, ++p
,
1824 sizeof(f
->f_un
.f_forw
.f_hname
));
1825 memset(&hints
, 0, sizeof(hints
));
1826 hints
.ai_family
= family
;
1827 hints
.ai_socktype
= SOCK_DGRAM
;
1828 error
= getaddrinfo(f
->f_un
.f_forw
.f_hname
, port
? port
: "syslog", &hints
,
1831 logerror(gai_strerror(error
));
1834 f
->f_un
.f_forw
.f_addr
= res
;
1839 /* Delay opening files until we're ready to log to them */
1841 if (strncmp(p
, _PATH_DEV
, sizeof(_PATH_DEV
)-1) == 0)
1842 f
->f_type
= F_CHECKTTY
;
1845 (void)strlcpy(f
->f_un
.f_fname
, p
, sizeof(f
->f_un
.f_fname
));
1849 f
->f_un
.f_pipe
.f_pid
= 0;
1850 (void)strlcpy(f
->f_un
.f_fname
, p
+ 1, sizeof(f
->f_un
.f_fname
));
1859 for (i
= 0; i
< MAXUNAMES
&& *p
; i
++) {
1860 for (q
= p
; *q
&& *q
!= ','; )
1862 (void)strncpy(f
->f_un
.f_uname
[i
], p
, UT_NAMESIZE
);
1863 if ((q
- p
) > UT_NAMESIZE
)
1864 f
->f_un
.f_uname
[i
][UT_NAMESIZE
] = '\0';
1866 f
->f_un
.f_uname
[i
][q
- p
] = '\0';
1867 while (*q
== ',' || *q
== ' ')
1871 f
->f_type
= F_USERS
;
1878 * Decode a symbolic name to a numeric value
1881 decode(const char *name
, CODE
*codetab
)
1887 return (atoi(name
));
1889 for (p
= buf
; *name
&& p
< &buf
[sizeof(buf
) - 1]; p
++, name
++) {
1891 *p
= tolower(*name
);
1896 for (c
= codetab
; c
->c_name
; c
++)
1897 if (!strcmp(buf
, c
->c_name
))
1909 now
= time((time_t *)NULL
);
1910 MarkSeq
+= TIMERINTVL
;
1911 if (MarkInterval
&& (MarkSeq
>= MarkInterval
)) {
1912 logmsg(LOG_INFO
, "-- MARK --",
1913 LocalHostName
, ADDDATE
|MARK
);
1917 for (f
= Files
; f
; f
= f
->f_next
) {
1918 if (f
->f_prevcount
&& now
>= REPEATTIME(f
)) {
1919 dprintf("flush %s: repeated %d times, %d sec.\n",
1920 TypeNames
[f
->f_type
], f
->f_prevcount
,
1921 repeatinterval
[f
->f_repeatcount
]);
1922 fprintlog(f
, 0, (char *)NULL
);
1927 /* Walk the dead queue, and see if we should signal somebody. */
1928 for (q
= TAILQ_FIRST(&deadq_head
); q
!= NULL
; q
= next
) {
1929 next
= TAILQ_NEXT(q
, dq_entries
);
1931 switch (q
->dq_timeout
) {
1933 /* Already signalled once, try harder now. */
1934 if (kill(q
->dq_pid
, SIGKILL
) != 0)
1935 (void)deadq_remove(q
->dq_pid
);
1940 * Timed out on dead queue, send terminate
1941 * signal. Note that we leave the removal
1942 * from the dead queue to reapchild(), which
1943 * will also log the event (unless the process
1944 * didn't even really exist, in case we simply
1945 * drop it from the dead queue).
1947 if (kill(q
->dq_pid
, SIGTERM
) != 0)
1948 (void)deadq_remove(q
->dq_pid
);
1956 (void)alarm(TIMERINTVL
);
1960 * fork off and become a daemon, but wait for the child to come online
1961 * before returing to the parent, or we get disk thrashing at boot etc.
1962 * Set a timer so we don't hang forever if it wedges.
1965 waitdaemon(int nochdir
, int noclose
, int maxwait
)
1969 pid_t pid
, childpid
;
1971 switch (childpid
= fork()) {
1977 signal(SIGALRM
, timedout
);
1979 while ((pid
= wait3(&status
, 0, NULL
)) != -1) {
1980 if (WIFEXITED(status
))
1981 errx(1, "child pid %d exited with return code %d",
1982 pid
, WEXITSTATUS(status
));
1983 if (WIFSIGNALED(status
))
1984 errx(1, "child pid %d exited on signal %d%s",
1985 pid
, WTERMSIG(status
),
1986 WCOREDUMP(status
) ? " (core dumped)" :
1988 if (pid
== childpid
) /* it's gone... */
2000 if (!noclose
&& (fd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) != -1) {
2001 (void)dup2(fd
, STDIN_FILENO
);
2002 (void)dup2(fd
, STDOUT_FILENO
);
2003 (void)dup2(fd
, STDERR_FILENO
);
2011 * We get a SIGALRM from the child when it's running and finished doing it's
2012 * fsync()'s or O_SYNC writes for all the boot messages.
2014 * We also get a signal from the kernel if the timer expires, so check to
2015 * see what happened.
2022 signal(SIGALRM
, SIG_DFL
);
2024 errx(1, "timed out waiting for child");
2030 * Add `s' to the list of allowable peer addresses to accept messages
2033 * `s' is a string in the form:
2035 * [*]domainname[:{servicename|portnumber|*}]
2039 * netaddr/maskbits[:{servicename|portnumber|*}]
2041 * Returns -1 on error, 0 if the argument was valid.
2047 struct allowedpeer ap
;
2049 int masklen
= -1, i
;
2050 struct addrinfo hints
, *res
;
2051 struct in_addr
*addrp
, *maskp
;
2052 u_int32_t
*addr6p
, *mask6p
;
2053 char ip
[NI_MAXHOST
];
2056 if (*s
!= '[' || (cp1
= strchr(s
+ 1, ']')) == NULL
)
2059 if ((cp1
= strrchr(cp1
, ':'))) {
2060 /* service/port provided */
2062 if (strlen(cp1
) == 1 && *cp1
== '*')
2063 /* any port allowed */
2065 else if ((se
= getservbyname(cp1
, "udp"))) {
2066 ap
.port
= ntohs(se
->s_port
);
2068 ap
.port
= strtol(cp1
, &cp2
, 0);
2070 return (-1); /* port not numeric */
2073 if ((se
= getservbyname("syslog", "udp")))
2074 ap
.port
= ntohs(se
->s_port
);
2076 /* sanity, should not happen */
2080 if ((cp1
= strchr(s
, '/')) != NULL
&&
2081 strspn(cp1
+ 1, "0123456789") == strlen(cp1
+ 1)) {
2083 if ((masklen
= atoi(cp1
+ 1)) < 0)
2088 cp2
= s
+ strlen(s
) - 1;
2099 memset(&hints
, 0, sizeof(hints
));
2100 hints
.ai_family
= PF_UNSPEC
;
2101 hints
.ai_socktype
= SOCK_DGRAM
;
2102 hints
.ai_flags
= AI_PASSIVE
| AI_NUMERICHOST
;
2103 if (getaddrinfo(s
, NULL
, &hints
, &res
) == 0) {
2105 memcpy(&ap
.a_addr
, res
->ai_addr
, res
->ai_addrlen
);
2106 memset(&ap
.a_mask
, 0, sizeof(ap
.a_mask
));
2107 ap
.a_mask
.ss_family
= res
->ai_family
;
2108 if (res
->ai_family
== AF_INET
) {
2109 ap
.a_mask
.ss_len
= sizeof(struct sockaddr_in
);
2110 maskp
= &((struct sockaddr_in
*)&ap
.a_mask
)->sin_addr
;
2111 addrp
= &((struct sockaddr_in
*)&ap
.a_addr
)->sin_addr
;
2113 /* use default netmask */
2114 if (IN_CLASSA(ntohl(addrp
->s_addr
)))
2115 maskp
->s_addr
= htonl(IN_CLASSA_NET
);
2116 else if (IN_CLASSB(ntohl(addrp
->s_addr
)))
2117 maskp
->s_addr
= htonl(IN_CLASSB_NET
);
2119 maskp
->s_addr
= htonl(IN_CLASSC_NET
);
2120 } else if (masklen
<= 32) {
2121 /* convert masklen to netmask */
2125 maskp
->s_addr
= htonl(~((1 << (32 - masklen
)) - 1));
2130 /* Lose any host bits in the network number. */
2131 addrp
->s_addr
&= maskp
->s_addr
;
2134 else if (res
->ai_family
== AF_INET6
&& masklen
<= 128) {
2135 ap
.a_mask
.ss_len
= sizeof(struct sockaddr_in6
);
2138 mask6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_mask
)->sin6_addr
;
2139 /* convert masklen to netmask */
2140 while (masklen
> 0) {
2142 *mask6p
= htonl(~(0xffffffff >> masklen
));
2145 *mask6p
++ = 0xffffffff;
2148 /* Lose any host bits in the network number. */
2149 mask6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_mask
)->sin6_addr
;
2150 addr6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_addr
)->sin6_addr
;
2151 for (i
= 0; i
< 4; i
++)
2152 addr6p
[i
] &= mask6p
[i
];
2161 /* arg `s' is domain name */
2175 printf("allowaddr: rule %d: ", NumAllowed
);
2177 printf("numeric, ");
2178 getnameinfo((struct sockaddr
*)&ap
.a_addr
,
2179 ((struct sockaddr
*)&ap
.a_addr
)->sa_len
,
2180 ip
, sizeof ip
, NULL
, 0,
2181 NI_NUMERICHOST
| withscopeid
);
2182 printf("addr = %s, ", ip
);
2183 getnameinfo((struct sockaddr
*)&ap
.a_mask
,
2184 ((struct sockaddr
*)&ap
.a_mask
)->sa_len
,
2185 ip
, sizeof ip
, NULL
, 0,
2186 NI_NUMERICHOST
| withscopeid
);
2187 printf("mask = %s; ", ip
);
2189 printf("domainname = %s; ", ap
.a_name
);
2191 printf("port = %d\n", ap
.port
);
2194 if ((AllowedPeers
= realloc(AllowedPeers
,
2195 ++NumAllowed
* sizeof(struct allowedpeer
)))
2197 logerror("realloc");
2200 memcpy(&AllowedPeers
[NumAllowed
- 1], &ap
, sizeof(struct allowedpeer
));
2205 * Validate that the remote peer has permission to log to us.
2208 validate(struct sockaddr
*sa
, const char *hname
)
2212 char *cp
, name
[NI_MAXHOST
], ip
[NI_MAXHOST
], port
[NI_MAXSERV
];
2213 struct allowedpeer
*ap
;
2214 struct sockaddr_in
*sin4
, *a4p
= NULL
, *m4p
= NULL
;
2215 struct sockaddr_in6
*sin6
, *a6p
= NULL
, *m6p
= NULL
;
2216 struct addrinfo hints
, *res
;
2219 if (NumAllowed
== 0)
2220 /* traditional behaviour, allow everything */
2223 (void)strlcpy(name
, hname
, sizeof(name
));
2224 memset(&hints
, 0, sizeof(hints
));
2225 hints
.ai_family
= PF_UNSPEC
;
2226 hints
.ai_socktype
= SOCK_DGRAM
;
2227 hints
.ai_flags
= AI_PASSIVE
| AI_NUMERICHOST
;
2228 if (getaddrinfo(name
, NULL
, &hints
, &res
) == 0)
2230 else if (strchr(name
, '.') == NULL
) {
2231 strlcat(name
, ".", sizeof name
);
2232 strlcat(name
, LocalDomain
, sizeof name
);
2234 if (getnameinfo(sa
, sa
->sa_len
, ip
, sizeof ip
, port
, sizeof port
,
2235 NI_NUMERICHOST
| withscopeid
| NI_NUMERICSERV
) != 0)
2236 return (0); /* for safety, should not occur */
2237 dprintf("validate: dgram from IP %s, port %s, name %s;\n",
2241 /* now, walk down the list */
2242 for (i
= 0, ap
= AllowedPeers
; i
< NumAllowed
; i
++, ap
++) {
2243 if (ap
->port
!= 0 && ap
->port
!= sport
) {
2244 dprintf("rejected in rule %d due to port mismatch.\n", i
);
2248 if (ap
->isnumeric
) {
2249 if (ap
->a_addr
.ss_family
!= sa
->sa_family
) {
2250 dprintf("rejected in rule %d due to address family mismatch.\n", i
);
2253 if (ap
->a_addr
.ss_family
== AF_INET
) {
2254 sin4
= (struct sockaddr_in
*)sa
;
2255 a4p
= (struct sockaddr_in
*)&ap
->a_addr
;
2256 m4p
= (struct sockaddr_in
*)&ap
->a_mask
;
2257 if ((sin4
->sin_addr
.s_addr
& m4p
->sin_addr
.s_addr
)
2258 != a4p
->sin_addr
.s_addr
) {
2259 dprintf("rejected in rule %d due to IP mismatch.\n", i
);
2264 else if (ap
->a_addr
.ss_family
== AF_INET6
) {
2265 sin6
= (struct sockaddr_in6
*)sa
;
2266 a6p
= (struct sockaddr_in6
*)&ap
->a_addr
;
2267 m6p
= (struct sockaddr_in6
*)&ap
->a_mask
;
2268 #ifdef NI_WITHSCOPEID
2269 if (a6p
->sin6_scope_id
!= 0 &&
2270 sin6
->sin6_scope_id
!= a6p
->sin6_scope_id
) {
2271 dprintf("rejected in rule %d due to scope mismatch.\n", i
);
2276 for (j
= 0; j
< 16; j
+= 4) {
2277 if ((*(u_int32_t
*)&sin6
->sin6_addr
.s6_addr
[j
] & *(u_int32_t
*)&m6p
->sin6_addr
.s6_addr
[j
])
2278 != *(u_int32_t
*)&a6p
->sin6_addr
.s6_addr
[j
]) {
2284 dprintf("rejected in rule %d due to IP mismatch.\n", i
);
2295 /* allow wildmatch */
2298 if (l2
> l1
|| memcmp(cp
, &name
[l1
- l2
], l2
) != 0) {
2299 dprintf("rejected in rule %d due to name mismatch.\n", i
);
2305 if (l2
!= l1
|| memcmp(cp
, name
, l1
) != 0) {
2306 dprintf("rejected in rule %d due to name mismatch.\n", i
);
2311 dprintf("accepted in rule %d.\n", i
);
2312 return (1); /* hooray! */
2318 * Fairly similar to popen(3), but returns an open descriptor, as
2319 * opposed to a FILE *.
2322 p_open(const char *prog
, pid_t
*pid
)
2324 int pfd
[2], nulldesc
, i
;
2325 sigset_t omask
, mask
;
2326 char *argv
[4]; /* sh -c cmd NULL */
2329 if (pipe(pfd
) == -1)
2331 if ((nulldesc
= open(_PATH_DEVNULL
, O_RDWR
)) == -1)
2332 /* we are royally screwed anyway */
2336 sigaddset(&mask
, SIGALRM
);
2337 sigaddset(&mask
, SIGHUP
);
2338 sigprocmask(SIG_BLOCK
, &mask
, &omask
);
2339 switch ((*pid
= fork())) {
2341 sigprocmask(SIG_SETMASK
, &omask
, 0);
2346 /* XXX should check for NULL return */
2347 argv
[0] = strdup("sh");
2348 argv
[1] = strdup("-c");
2349 argv
[2] = strdup(prog
);
2351 if (argv
[0] == NULL
|| argv
[1] == NULL
|| argv
[2] == NULL
) {
2357 (void)setsid(); /* Avoid catching SIGHUPs. */
2360 * Throw away pending signals, and reset signal
2361 * behaviour to standard values.
2363 signal(SIGALRM
, SIG_IGN
);
2364 signal(SIGHUP
, SIG_IGN
);
2365 sigprocmask(SIG_SETMASK
, &omask
, 0);
2366 signal(SIGPIPE
, SIG_DFL
);
2367 signal(SIGQUIT
, SIG_DFL
);
2368 signal(SIGALRM
, SIG_DFL
);
2369 signal(SIGHUP
, SIG_DFL
);
2371 dup2(pfd
[0], STDIN_FILENO
);
2372 dup2(nulldesc
, STDOUT_FILENO
);
2373 dup2(nulldesc
, STDERR_FILENO
);
2374 for (i
= getdtablesize(); i
> 2; i
--)
2377 (void)execvp(_PATH_BSHELL
, argv
);
2381 sigprocmask(SIG_SETMASK
, &omask
, 0);
2385 * Avoid blocking on a hung pipe. With O_NONBLOCK, we are
2386 * supposed to get an EWOULDBLOCK on writev(2), which is
2387 * caught by the logic above anyway, which will in turn close
2388 * the pipe, and fork a new logging subprocess if necessary.
2389 * The stale subprocess will be killed some time later unless
2390 * it terminated itself due to closing its input pipe (so we
2391 * get rid of really dead puppies).
2393 if (fcntl(pfd
[1], F_SETFL
, O_NONBLOCK
) == -1) {
2395 (void)snprintf(errmsg
, sizeof errmsg
,
2396 "Warning: cannot change pipe to PID %d to "
2397 "non-blocking behaviour.",
2405 deadq_enter(pid_t pid
, const char *name
)
2411 * Be paranoid, if we can't signal the process, don't enter it
2412 * into the dead queue (perhaps it's already dead). If possible,
2413 * we try to fetch and log the child's status.
2415 if (kill(pid
, 0) != 0) {
2416 if (waitpid(pid
, &status
, WNOHANG
) > 0)
2417 log_deadchild(pid
, status
, name
);
2421 p
= malloc(sizeof(struct deadq_entry
));
2428 p
->dq_timeout
= DQ_TIMO_INIT
;
2429 TAILQ_INSERT_TAIL(&deadq_head
, p
, dq_entries
);
2433 deadq_remove(pid_t pid
)
2437 TAILQ_FOREACH(q
, &deadq_head
, dq_entries
) {
2438 if (q
->dq_pid
== pid
) {
2439 TAILQ_REMOVE(&deadq_head
, q
, dq_entries
);
2449 log_deadchild(pid_t pid
, int status
, const char *name
)
2455 errno
= 0; /* Keep strerror() stuff out of logerror messages. */
2456 if (WIFSIGNALED(status
)) {
2457 reason
= "due to signal";
2458 code
= WTERMSIG(status
);
2460 reason
= "with status";
2461 code
= WEXITSTATUS(status
);
2465 (void)snprintf(buf
, sizeof buf
,
2466 "Logging subprocess %d (%s) exited %s %d.",
2467 pid
, name
, reason
, code
);
2472 socksetup(int af
, const char *bindhostname
)
2474 struct addrinfo hints
, *res
, *r
;
2475 int error
, maxs
, *s
, *socks
;
2477 memset(&hints
, 0, sizeof(hints
));
2478 hints
.ai_flags
= AI_PASSIVE
;
2479 hints
.ai_family
= af
;
2480 hints
.ai_socktype
= SOCK_DGRAM
;
2481 error
= getaddrinfo(bindhostname
, "syslog", &hints
, &res
);
2483 logerror(gai_strerror(error
));
2488 /* Count max number of sockets we may open */
2489 for (maxs
= 0, r
= res
; r
; r
= r
->ai_next
, maxs
++);
2490 socks
= malloc((maxs
+1) * sizeof(int));
2491 if (socks
== NULL
) {
2492 logerror("couldn't allocate memory for sockets");
2496 *socks
= 0; /* num of sockets counter at start of array */
2498 for (r
= res
; r
; r
= r
->ai_next
) {
2499 *s
= socket(r
->ai_family
, r
->ai_socktype
, r
->ai_protocol
);
2504 if (r
->ai_family
== AF_INET6
) {
2506 if (setsockopt(*s
, IPPROTO_IPV6
, IPV6_V6ONLY
,
2507 (char *)&on
, sizeof (on
)) < 0) {
2508 logerror("setsockopt");
2513 if (bind(*s
, r
->ai_addr
, r
->ai_addrlen
) < 0) {