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
33 * @(#) Copyright (c) 1983, 1988, 1993, 1994 The Regents of the University of California. All rights reserved.
34 * @(#)syslogd.c 8.3 (Berkeley) 4/4/94
35 * $FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.130 2004/07/04 19:52:48 cperciva Exp $
36 * $DragonFly: src/usr.sbin/syslogd/syslogd.c,v 1.5 2004/12/18 23:48:14 swildner Exp $
40 * syslogd -- log system messages
42 * This program implements a system log. It takes a series of lines.
43 * Each line may have a priority, signified as "<n>" as
44 * the first characters of the line. If this is
45 * not present, a default priority is used.
47 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
48 * cause it to reread its configuration file.
52 * MAXLINE -- the maximum line length that can be handled.
53 * DEFUPRI -- the default priority for user messages
54 * DEFSPRI -- the default priority for kernel messages
57 * extensive changes by Ralph Campbell
58 * more extensive changes by Eric Allman (again)
59 * Extension to log by program name as well as facility and priority
61 * -u and -v by Harlan Stenn.
62 * Priority comparison code by Harlan Stenn.
63 * Ring buffer code by Jeff Wheelhouse.
66 #define MAXLINE 1024 /* maximum line length */
67 #define MAXSVLINE 120 /* maximum saved line length */
68 #define DEFUPRI (LOG_USER|LOG_NOTICE)
69 #define DEFSPRI (LOG_KERN|LOG_CRIT)
70 #define TIMERINTVL 30 /* interval for checking flush, mark */
71 #define TTYMSGTIME 1 /* timeout passed to ttymsg */
73 #include <sys/param.h>
74 #include <sys/ioctl.h>
77 #include <sys/socket.h>
78 #include <sys/queue.h>
82 #include <sys/resource.h>
83 #include <sys/syslimits.h>
85 #include <sys/types.h>
87 #include <netinet/in.h>
89 #include <arpa/inet.h>
102 #include <sysexits.h>
106 #include "pathnames.h"
108 #include "../clog/clog.h"
111 #include <sys/syslog.h>
113 #ifdef NI_WITHSCOPEID
114 static const int withscopeid
= NI_WITHSCOPEID
;
116 static const int withscopeid
;
119 const char *ConfFile
= _PATH_LOGCONF
;
120 const char *PidFile
= _PATH_LOGPID
;
121 const char ctty
[] = _PATH_CONSOLE
;
122 const char ring_magic
[] = "CLOG";
124 #define dprintf if (Debug) printf
126 #define MAXUNAMES 20 /* maximum number of user names */
131 const char *funixn
[MAXFUNIX
] = { _PATH_LOG
};
138 #define IGN_CONS 0x001 /* don't print on console */
139 #define SYNC_FILE 0x002 /* do fsync on file after printing */
140 #define ADDDATE 0x004 /* add a date to the message */
141 #define MARK 0x008 /* this message is a mark */
142 #define ISKERNEL 0x010 /* kernel generated message */
145 * This structure represents the files that will have log
147 * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
148 * or if f_type if F_PIPE and f_pid > 0.
152 struct filed
*f_next
; /* next in linked list */
153 short f_type
; /* entry type, see below */
154 short f_file
; /* file descriptor */
155 time_t f_time
; /* time this was last written */
156 char *f_host
; /* host from which to recd. */
157 u_char f_pmask
[LOG_NFACILITIES
+1]; /* priority mask */
158 u_char f_pcmp
[LOG_NFACILITIES
+1]; /* compare priority */
162 char *f_program
; /* program this applies to */
164 char f_uname
[MAXUNAMES
][UT_NAMESIZE
+1];
166 char f_hname
[MAXHOSTNAMELEN
];
167 struct addrinfo
*f_addr
;
169 } f_forw
; /* forwarding address */
170 char f_fname
[MAXPATHLEN
];
172 char f_pname
[MAXPATHLEN
];
176 char f_rname
[MAXPATHLEN
];
177 struct clog_footer
*f_footer
;
181 char f_prevline
[MAXSVLINE
]; /* last message logged */
182 char f_lasttime
[16]; /* time of last occurrence */
183 char f_prevhost
[MAXHOSTNAMELEN
]; /* host from which recd. */
184 int f_prevpri
; /* pri of f_prevline */
185 int f_prevlen
; /* length of f_prevline */
186 int f_prevcount
; /* repetition cnt of prevline */
187 u_int f_repeatcount
; /* number of "repeated" msgs */
188 int f_flags
; /* file-specific flags */
189 #define FFLAG_SYNC 0x01
190 #define FFLAG_NEEDSYNC 0x02
194 * Queue of about-to-be dead processes we should watch out for.
197 TAILQ_HEAD(stailhead
, deadq_entry
) deadq_head
;
198 struct stailhead
*deadq_headp
;
203 TAILQ_ENTRY(deadq_entry
) dq_entries
;
207 * The timeout to apply to processes waiting on the dead queue. Unit
208 * of measure is `mark intervals', i.e. 20 minutes by default.
209 * Processes on the dead queue will be terminated after that time.
212 #define DQ_TIMO_INIT 2
214 typedef struct deadq_entry
*dq_t
;
218 * Struct to hold records of network addresses that are allowed to log
226 struct sockaddr_storage addr
;
227 struct sockaddr_storage mask
;
231 #define a_addr u.numeric.addr
232 #define a_mask u.numeric.mask
233 #define a_name u.name
238 * Intervals at which we flush out "message repeated" messages,
239 * in seconds after previous message is logged. After each flush,
240 * we move to the next interval until we reach the largest.
242 int repeatinterval
[] = { 30, 120, 600 }; /* # of secs before flush */
243 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
244 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
245 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
246 (f)->f_repeatcount = MAXREPEAT; \
249 /* values for f_type */
250 #define F_UNUSED 0 /* unused entry */
251 #define F_FILE 1 /* regular file */
252 #define F_TTY 2 /* terminal */
253 #define F_CONSOLE 3 /* console terminal */
254 #define F_FORW 4 /* remote machine */
255 #define F_USERS 5 /* list of users */
256 #define F_WALL 6 /* everyone logged on */
257 #define F_PIPE 7 /* pipe to program */
258 #define F_RING 8 /* ring buffer (circular log) */
260 const char *TypeNames
[] = {
261 "UNUSED", "FILE", "TTY", "CONSOLE",
262 "FORW", "USERS", "WALL", "PIPE",
266 static struct filed
*Files
; /* Log files that we write to */
267 static struct filed consfile
; /* Console */
269 static int Debug
; /* debug flag */
270 static int resolve
= 1; /* resolve hostname */
271 static char LocalHostName
[MAXHOSTNAMELEN
]; /* our hostname */
272 static const char *LocalDomain
; /* our local domain name */
273 static int *finet
; /* Internet datagram socket */
274 static int fklog
= -1; /* /dev/klog */
275 static int Initialized
; /* set when we have initialized ourselves */
276 static int MarkInterval
= 20 * 60; /* interval between marks in seconds */
277 static int MarkSeq
; /* mark sequence number */
278 static int SecureMode
; /* when true, receive only unix domain socks */
280 static int family
= PF_UNSPEC
; /* protocol family (IPv4, IPv6 or both) */
282 static int family
= PF_INET
; /* protocol family (IPv4 only) */
284 static int send_to_all
; /* send message to all IPv4/IPv6 addresses */
285 static int use_bootfile
; /* log entire bootfile for every kern msg */
286 static int no_compress
; /* don't compress messages (1=pipes, 2=all) */
288 static char bootfile
[MAXLINE
+1]; /* booted kernel file */
290 struct allowedpeer
*AllowedPeers
; /* List of allowed peers */
291 static int NumAllowed
; /* Number of entries in AllowedPeers */
293 static int UniquePriority
; /* Only log specified priority? */
294 static int LogFacPri
; /* Put facility and priority in log message: */
295 /* 0=no, 1=numeric, 2=names */
296 static int KeepKernFac
; /* Keep remotely logged kernel facility */
297 static int needdofsync
= 0; /* Are any file(s) waiting to be fsynced? */
299 volatile sig_atomic_t MarkSet
, WantDie
;
301 static int allowaddr(char *);
302 static void cfline(const char *, struct filed
*,
303 const char *, const char *);
304 static const char *cvthname(struct sockaddr
*);
305 static void deadq_enter(pid_t
, const char *);
306 static int deadq_remove(pid_t
);
307 static int decode(const char *, CODE
*);
308 static void die(int);
309 static void dodie(int);
310 static void dofsync(void);
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 *, int);
320 static void printline(const char *, char *);
321 static void printsys(char *);
322 static int p_open(const char *, pid_t
*);
323 ssize_t
rbwrite(struct filed
*, char *, size_t);
324 ssize_t
rbwritev(struct filed
*, struct iovec
*, int);
325 static void readklog(void);
326 static void reapchild(int);
327 static void usage(void);
328 static int validate(struct sockaddr
*, const char *);
329 static void unmapped(struct sockaddr
*);
330 static void wallmsg(struct filed
*, struct iovec
*);
331 static int waitdaemon(int, int, int);
332 static void timedout(int);
335 main(int argc
, char *argv
[])
337 int ch
, i
, fdsrmax
= 0, l
;
338 struct sockaddr_un sunx
, fromunix
;
339 struct sockaddr_storage frominet
;
342 char line
[MAXLINE
+ 1];
343 const char *bindhostname
, *hname
;
344 struct timeval tv
, *tvp
;
345 struct sigaction sact
;
351 while ((ch
= getopt(argc
, argv
, "46Aa:b:cdf:kl:m:nop:P:suv")) != -1)
364 case 'a': /* allow specific network addresses only */
365 if (allowaddr(optarg
) == -1)
369 bindhostname
= optarg
;
374 case 'd': /* debug */
377 case 'f': /* configuration file */
380 case 'k': /* keep remote kern fac */
384 if (strlen(optarg
) >= sizeof(sunx
.sun_path
))
385 errx(1, "%s path too long, exiting", optarg
);
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;
402 if (strlen(optarg
) >= sizeof(sunx
.sun_path
))
403 errx(1, "%s path too long, exiting", optarg
);
406 case 'P': /* path for alt. PID */
409 case 's': /* no network mode */
412 case 'u': /* only log specified priority */
415 case 'v': /* log facility and priority */
421 if ((argc
-= optind
) != 0)
425 ppid
= waitdaemon(0, 0, 30);
427 err(1, "could not become daemon");
435 consfile
.f_type
= F_CONSOLE
;
436 strlcpy(consfile
.f_un
.f_fname
, ctty
+ sizeof _PATH_DEV
- 1,
437 sizeof(consfile
.f_un
.f_fname
));
438 strlcpy(bootfile
, getbootfile(), sizeof(bootfile
));
439 signal(SIGTERM
, dodie
);
440 signal(SIGINT
, Debug
? dodie
: SIG_IGN
);
441 signal(SIGQUIT
, Debug
? dodie
: SIG_IGN
);
443 * We don't want the SIGCHLD and SIGHUP handlers to interfere
444 * with each other; they are likely candidates for being called
445 * simultaneously (SIGHUP closes pipe descriptor, process dies,
449 sigaddset(&mask
, SIGHUP
);
450 sact
.sa_handler
= reapchild
;
452 sact
.sa_flags
= SA_RESTART
;
453 sigaction(SIGCHLD
, &sact
, NULL
);
454 signal(SIGALRM
, domark
);
455 signal(SIGPIPE
, SIG_IGN
); /* We'll catch EPIPE instead. */
458 TAILQ_INIT(&deadq_head
);
461 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
463 for (i
= 0; i
< nfunix
; i
++) {
465 memset(&sunx
, 0, sizeof(sunx
));
466 sunx
.sun_family
= AF_UNIX
;
467 strlcpy(sunx
.sun_path
, funixn
[i
], sizeof(sunx
.sun_path
));
468 funix
[i
] = socket(AF_UNIX
, SOCK_DGRAM
, 0);
470 bind(funix
[i
], (struct sockaddr
*)&sunx
,
471 SUN_LEN(&sunx
)) < 0 ||
472 chmod(funixn
[i
], 0666) < 0) {
473 snprintf(line
, sizeof line
,
474 "cannot create %s", funixn
[i
]);
476 dprintf("cannot create %s (%d)\n", funixn
[i
], errno
);
482 finet
= socksetup(family
, bindhostname
);
486 for (i
= 0; i
< *finet
; i
++) {
487 if (shutdown(finet
[i
+1], SHUT_RD
) < 0) {
488 logerror("shutdown");
494 dprintf("listening on inet and/or inet6 socket\n");
496 dprintf("sending on inet and/or inet6 socket\n");
499 if ((fklog
= open(_PATH_KLOG
, O_RDONLY
, 0)) >= 0)
500 if (fcntl(fklog
, F_SETFL
, O_NONBLOCK
) < 0)
503 dprintf("can't open %s (%d)\n", _PATH_KLOG
, errno
);
505 /* tuck my process id away */
506 fp
= fopen(PidFile
, "w");
508 fprintf(fp
, "%d\n", getpid());
512 dprintf("off & running....\n");
515 /* prevent SIGHUP and SIGCHLD handlers from running in parallel */
517 sigaddset(&mask
, SIGCHLD
);
518 sact
.sa_handler
= init
;
520 sact
.sa_flags
= SA_RESTART
;
521 sigaction(SIGHUP
, &sact
, NULL
);
524 tv
.tv_sec
= tv
.tv_usec
= 0;
526 if (fklog
!= -1 && fklog
> fdsrmax
)
528 if (finet
&& !SecureMode
) {
529 for (i
= 0; i
< *finet
; i
++) {
530 if (finet
[i
+1] != -1 && finet
[i
+1] > fdsrmax
)
531 fdsrmax
= finet
[i
+1];
534 for (i
= 0; i
< nfunix
; i
++) {
535 if (funix
[i
] != -1 && funix
[i
] > fdsrmax
)
539 fdsr
= (fd_set
*)calloc(howmany(fdsrmax
+1, NFDBITS
),
542 errx(1, "calloc fd_set");
550 bzero(fdsr
, howmany(fdsrmax
+1, NFDBITS
) *
555 if (finet
&& !SecureMode
) {
556 for (i
= 0; i
< *finet
; i
++) {
557 if (finet
[i
+1] != -1)
558 FD_SET(finet
[i
+1], fdsr
);
561 for (i
= 0; i
< nfunix
; i
++) {
563 FD_SET(funix
[i
], fdsr
);
566 i
= select(fdsrmax
+1, fdsr
, NULL
, NULL
,
567 needdofsync
? &tv
: tvp
);
583 if (fklog
!= -1 && FD_ISSET(fklog
, fdsr
))
585 if (finet
&& !SecureMode
) {
586 for (i
= 0; i
< *finet
; i
++) {
587 if (FD_ISSET(finet
[i
+1], fdsr
)) {
588 len
= sizeof(frominet
);
589 l
= recvfrom(finet
[i
+1], line
, MAXLINE
,
590 0, (struct sockaddr
*)&frominet
,
594 hname
= cvthname((struct sockaddr
*)&frominet
);
595 unmapped((struct sockaddr
*)&frominet
);
596 if (validate((struct sockaddr
*)&frominet
, hname
))
597 printline(hname
, line
);
598 } else if (l
< 0 && errno
!= EINTR
)
599 logerror("recvfrom inet");
603 for (i
= 0; i
< nfunix
; i
++) {
604 if (funix
[i
] != -1 && FD_ISSET(funix
[i
], fdsr
)) {
605 len
= sizeof(fromunix
);
606 l
= recvfrom(funix
[i
], line
, MAXLINE
, 0,
607 (struct sockaddr
*)&fromunix
, &len
);
610 printline(LocalHostName
, line
);
611 } else if (l
< 0 && errno
!= EINTR
)
612 logerror("recvfrom unix");
621 unmapped(struct sockaddr
*sa
)
623 struct sockaddr_in6
*sin6
;
624 struct sockaddr_in sin4
;
626 if (sa
->sa_family
!= AF_INET6
)
628 if (sa
->sa_len
!= sizeof(struct sockaddr_in6
) ||
629 sizeof(sin4
) > sa
->sa_len
)
631 sin6
= (struct sockaddr_in6
*)sa
;
632 if (!IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
))
635 memset(&sin4
, 0, sizeof(sin4
));
636 sin4
.sin_family
= AF_INET
;
637 sin4
.sin_len
= sizeof(struct sockaddr_in
);
638 memcpy(&sin4
.sin_addr
, &sin6
->sin6_addr
.s6_addr
[12],
639 sizeof(sin4
.sin_addr
));
640 sin4
.sin_port
= sin6
->sin6_port
;
642 memcpy(sa
, &sin4
, sin4
.sin_len
);
649 fprintf(stderr
, "%s\n%s\n%s\n%s\n",
650 "usage: syslogd [-46Acdknosuv] [-a allowed_peer]",
651 " [-b bind address] [-f config_file]",
652 " [-l log_socket] [-m mark_interval]",
653 " [-P pid_file] [-p log_socket]");
658 * Take a raw input line, decode the message, and print the message
659 * on the appropriate log files.
662 printline(const char *hname
, char *msg
)
667 char line
[MAXLINE
+ 1];
669 /* test for special codes */
674 n
= strtol(p
+ 1, &q
, 10);
675 if (*q
== '>' && n
>= 0 && n
< INT_MAX
&& errno
== 0) {
680 if (pri
&~ (LOG_FACMASK
|LOG_PRIMASK
))
684 * Don't allow users to log kernel messages.
685 * NOTE: since LOG_KERN == 0 this will also match
686 * messages with no facility specified.
688 if ((pri
& LOG_FACMASK
) == LOG_KERN
&& !KeepKernFac
)
689 pri
= LOG_MAKEPRI(LOG_USER
, LOG_PRI(pri
));
693 while ((c
= (unsigned char)*p
++) != '\0' &&
694 q
< &line
[sizeof(line
) - 4]) {
695 if ((c
& 0x80) && c
< 0xA0) {
700 if (isascii(c
) && iscntrl(c
)) {
703 } else if (c
== '\t') {
715 logmsg(pri
, line
, hname
, 0);
719 * Read /dev/klog while data are available, split into lines.
724 char *p
, *q
, line
[MAXLINE
+ 1];
729 i
= read(fklog
, line
+ len
, MAXLINE
- 1 - len
);
731 line
[i
+ len
] = '\0';
733 if (i
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
) {
740 for (p
= line
; (q
= strchr(p
, '\n')) != NULL
; p
= q
+ 1) {
745 if (len
>= MAXLINE
- 1) {
750 memmove(line
, p
, len
+ 1);
757 * Take a raw input line from /dev/klog, format similar to syslog().
764 int flags
, isprintf
, pri
;
766 flags
= ISKERNEL
| SYNC_FILE
| ADDDATE
; /* fsync after write */
772 n
= strtol(p
+ 1, &q
, 10);
773 if (*q
== '>' && n
>= 0 && n
< INT_MAX
&& errno
== 0) {
780 * Kernel printf's and LOG_CONSOLE messages have been displayed
781 * on the console already.
783 if (isprintf
|| (pri
& LOG_FACMASK
) == LOG_CONSOLE
)
785 if (pri
&~ (LOG_FACMASK
|LOG_PRIMASK
))
787 logmsg(pri
, p
, LocalHostName
, flags
);
793 * Match a program or host name against a specification.
794 * Return a non-0 value if the message must be ignored
795 * based on the specification.
798 skip_message(const char *name
, const char *spec
, int checkcase
) {
802 /* Behaviour on explicit match */
817 s
= strstr (spec
, name
);
819 s
= strcasestr (spec
, name
);
822 prev
= (s
== spec
? ',' : *(s
- 1));
823 next
= *(s
+ strlen (name
));
825 if (prev
== ',' && (next
== '\0' || next
== ','))
826 /* Explicit match: skip iff the spec is an
831 /* No explicit match for this name: skip the message iff
832 the spec is an inclusive one. */
837 * Log a message to the appropriate log files, users, etc. based on
841 logmsg(int pri
, const char *msg
, const char *from
, int flags
)
844 int i
, fac
, msglen
, omask
, prilev
;
845 const char *timestamp
;
846 char prog
[NAME_MAX
+1];
849 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
850 pri
, flags
, from
, msg
);
852 omask
= sigblock(sigmask(SIGHUP
)|sigmask(SIGALRM
));
855 * Check to see if msg looks non-standard.
857 msglen
= strlen(msg
);
858 if (msglen
< 16 || msg
[3] != ' ' || msg
[6] != ' ' ||
859 msg
[9] != ':' || msg
[12] != ':' || msg
[15] != ' ')
863 if (flags
& ADDDATE
) {
864 timestamp
= ctime(&now
) + 4;
871 /* skip leading blanks */
872 while (isspace(*msg
)) {
877 /* extract facility and priority level */
879 fac
= LOG_NFACILITIES
;
882 prilev
= LOG_PRI(pri
);
884 /* extract program name */
885 for (i
= 0; i
< NAME_MAX
; i
++) {
886 if (!isprint(msg
[i
]) || msg
[i
] == ':' || msg
[i
] == '[' ||
893 /* add kernel prefix for kernel messages */
894 if (flags
& ISKERNEL
) {
895 snprintf(buf
, sizeof(buf
), "%s: %s",
896 use_bootfile
? bootfile
: "kernel", msg
);
898 msglen
= strlen(buf
);
901 /* log the message to the particular outputs */
904 f
->f_file
= open(ctty
, O_WRONLY
, 0);
906 if (f
->f_file
>= 0) {
907 strlcpy(f
->f_lasttime
, timestamp
,
908 sizeof(f
->f_lasttime
));
909 fprintlog(f
, flags
, msg
);
915 for (f
= Files
; f
; f
= f
->f_next
) {
916 /* skip messages that are incorrect priority */
917 if (!(((f
->f_pcmp
[fac
] & PRI_EQ
) && (f
->f_pmask
[fac
] == prilev
))
918 ||((f
->f_pcmp
[fac
] & PRI_LT
) && (f
->f_pmask
[fac
] < prilev
))
919 ||((f
->f_pcmp
[fac
] & PRI_GT
) && (f
->f_pmask
[fac
] > prilev
))
921 || f
->f_pmask
[fac
] == INTERNAL_NOPRI
)
924 /* skip messages with the incorrect hostname */
925 if (skip_message(from
, f
->f_host
, 0))
928 /* skip messages with the incorrect program name */
929 if (skip_message(prog
, f
->f_program
, 1))
932 /* skip message to console if it has already been printed */
933 if (f
->f_type
== F_CONSOLE
&& (flags
& IGN_CONS
))
936 /* don't output marks to recently written files */
937 if ((flags
& MARK
) && (now
- f
->f_time
) < MarkInterval
/ 2)
941 * suppress duplicate lines to this file
943 if (no_compress
- (f
->f_type
!= F_PIPE
) < 1 &&
944 (flags
& MARK
) == 0 && msglen
== f
->f_prevlen
&&
945 !strcmp(msg
, f
->f_prevline
) &&
946 !strcasecmp(from
, f
->f_prevhost
)) {
947 strlcpy(f
->f_lasttime
, timestamp
,
948 sizeof(f
->f_lasttime
));
950 dprintf("msg repeated %d times, %ld sec of %d\n",
951 f
->f_prevcount
, (long)(now
- f
->f_time
),
952 repeatinterval
[f
->f_repeatcount
]);
954 * If domark would have logged this by now,
955 * flush it now (so we don't hold isolated messages),
956 * but back off so we'll flush less often
959 if (now
> REPEATTIME(f
)) {
960 fprintlog(f
, flags
, (char *)NULL
);
964 /* new line, save it */
966 fprintlog(f
, 0, (char *)NULL
);
967 f
->f_repeatcount
= 0;
969 strlcpy(f
->f_lasttime
, timestamp
,
970 sizeof(f
->f_lasttime
));
971 strlcpy(f
->f_prevhost
, from
,
972 sizeof(f
->f_prevhost
));
973 if (msglen
< MAXSVLINE
) {
974 f
->f_prevlen
= msglen
;
975 strlcpy(f
->f_prevline
, msg
, sizeof(f
->f_prevline
));
976 fprintlog(f
, flags
, (char *)NULL
);
978 f
->f_prevline
[0] = 0;
980 fprintlog(f
, flags
, msg
);
992 for (f
= Files
; f
; f
= f
->f_next
) {
993 if ((f
->f_type
== F_FILE
) &&
994 (f
->f_flags
& FFLAG_NEEDSYNC
)) {
995 f
->f_flags
&= ~FFLAG_NEEDSYNC
;
1002 fprintlog(struct filed
*f
, int flags
, const char *msg
)
1004 struct iovec iov
[7];
1007 int i
, l
, lsent
= 0;
1008 char line
[MAXLINE
+ 1], repbuf
[80], greetings
[200], *wmsg
= NULL
;
1009 char nul
[] = "", space
[] = " ", lf
[] = "\n", crlf
[] = "\r\n";
1013 if (f
->f_type
== F_WALL
) {
1014 v
->iov_base
= greetings
;
1015 v
->iov_len
= snprintf(greetings
, sizeof greetings
,
1016 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
1017 f
->f_prevhost
, ctime(&now
));
1024 v
->iov_base
= f
->f_lasttime
;
1027 v
->iov_base
= space
;
1033 static char fp_buf
[30]; /* Hollow laugh */
1034 int fac
= f
->f_prevpri
& LOG_FACMASK
;
1035 int pri
= LOG_PRI(f
->f_prevpri
);
1036 const char *f_s
= NULL
;
1037 char f_n
[5]; /* Hollow laugh */
1038 const char *p_s
= NULL
;
1039 char p_n
[5]; /* Hollow laugh */
1041 if (LogFacPri
> 1) {
1044 for (c
= facilitynames
; c
->c_name
; c
++) {
1045 if (c
->c_val
== fac
) {
1050 for (c
= prioritynames
; c
->c_name
; c
++) {
1051 if (c
->c_val
== pri
) {
1058 snprintf(f_n
, sizeof f_n
, "%d", LOG_FAC(fac
));
1062 snprintf(p_n
, sizeof p_n
, "%d", pri
);
1065 snprintf(fp_buf
, sizeof fp_buf
, "<%s.%s> ", f_s
, p_s
);
1066 v
->iov_base
= fp_buf
;
1067 v
->iov_len
= strlen(fp_buf
);
1074 v
->iov_base
= f
->f_prevhost
;
1075 v
->iov_len
= strlen(v
->iov_base
);
1077 v
->iov_base
= space
;
1082 wmsg
= strdup(msg
); /* XXX iov_base needs a `const' sibling. */
1088 v
->iov_len
= strlen(msg
);
1089 } else if (f
->f_prevcount
> 1) {
1090 v
->iov_base
= repbuf
;
1091 v
->iov_len
= snprintf(repbuf
, sizeof repbuf
,
1092 "last message repeated %d times", f
->f_prevcount
);
1094 v
->iov_base
= f
->f_prevline
;
1095 v
->iov_len
= f
->f_prevlen
;
1099 dprintf("Logging to %s", TypeNames
[f
->f_type
]);
1102 switch (f
->f_type
) {
1108 dprintf(" %s\n", f
->f_un
.f_forw
.f_hname
);
1109 /* check for local vs remote messages */
1110 if (strcasecmp(f
->f_prevhost
, LocalHostName
))
1111 l
= snprintf(line
, sizeof line
- 1,
1112 "<%d>%.15s Forwarded from %s: %s",
1113 f
->f_prevpri
, (char *)iov
[0].iov_base
,
1114 f
->f_prevhost
, (char *)iov
[5].iov_base
);
1116 l
= snprintf(line
, sizeof line
- 1, "<%d>%.15s %s",
1117 f
->f_prevpri
, (char *)iov
[0].iov_base
,
1118 (char *)iov
[5].iov_base
);
1121 else if (l
> MAXLINE
)
1125 for (r
= f
->f_un
.f_forw
.f_addr
; r
; r
= r
->ai_next
) {
1126 for (i
= 0; i
< *finet
; i
++) {
1129 * should we check AF first, or just
1130 * trial and error? FWD
1133 address_family_of(finet
[i
+1]))
1135 lsent
= sendto(finet
[i
+1], line
, l
, 0,
1136 r
->ai_addr
, r
->ai_addrlen
);
1140 if (lsent
== l
&& !send_to_all
)
1143 dprintf("lsent/l: %d/%d\n", lsent
, l
);
1154 /* case ENOTSOCK: */
1156 /* case EMSGSIZE: */
1159 /* case ECONNREFUSED: */
1161 dprintf("removing entry\n");
1162 f
->f_type
= F_UNUSED
;
1170 dprintf(" %s\n", f
->f_un
.f_fname
);
1173 if (writev(f
->f_file
, iov
, 7) < 0) {
1176 f
->f_type
= F_UNUSED
;
1178 logerror(f
->f_un
.f_fname
);
1179 } else if ((flags
& SYNC_FILE
) && (f
->f_flags
& FFLAG_SYNC
)) {
1180 f
->f_flags
|= FFLAG_NEEDSYNC
;
1186 dprintf(" %s\n", f
->f_un
.f_ring
.f_rname
);
1189 if (rbwritev(f
, iov
, 7) == -1) {
1191 munmap(f
->f_un
.f_ring
.f_footer
,
1192 sizeof(struct clog_footer
));
1194 f
->f_type
= F_UNUSED
;
1196 logerror(f
->f_un
.f_fname
);
1201 dprintf(" %s\n", f
->f_un
.f_pipe
.f_pname
);
1204 if (f
->f_un
.f_pipe
.f_pid
== 0) {
1205 if ((f
->f_file
= p_open(f
->f_un
.f_pipe
.f_pname
,
1206 &f
->f_un
.f_pipe
.f_pid
)) < 0) {
1207 f
->f_type
= F_UNUSED
;
1208 logerror(f
->f_un
.f_pipe
.f_pname
);
1212 if (writev(f
->f_file
, iov
, 7) < 0) {
1215 if (f
->f_un
.f_pipe
.f_pid
> 0)
1216 deadq_enter(f
->f_un
.f_pipe
.f_pid
,
1217 f
->f_un
.f_pipe
.f_pname
);
1218 f
->f_un
.f_pipe
.f_pid
= 0;
1220 logerror(f
->f_un
.f_pipe
.f_pname
);
1225 if (flags
& IGN_CONS
) {
1226 dprintf(" (ignored)\n");
1232 dprintf(" %s%s\n", _PATH_DEV
, f
->f_un
.f_fname
);
1236 errno
= 0; /* ttymsg() only sometimes returns an errno */
1237 if ((msgret
= ttymsg(iov
, 7, f
->f_un
.f_fname
, 10))) {
1238 f
->f_type
= F_UNUSED
;
1257 * WALLMSG -- Write a message to the world at large
1259 * Write the specified message to either the entire
1260 * world, or a list of approved users.
1263 wallmsg(struct filed
*f
, struct iovec
*iov
)
1265 static int reenter
; /* avoid calling ourselves */
1270 char line
[sizeof(ut
.ut_line
) + 1];
1274 if ((uf
= fopen(_PATH_UTMP
, "r")) == NULL
) {
1275 logerror(_PATH_UTMP
);
1280 while (fread((char *)&ut
, sizeof(ut
), 1, uf
) == 1) {
1281 if (ut
.ut_name
[0] == '\0')
1283 /* We must use strncpy since ut_* may not be NUL terminated. */
1284 strncpy(line
, ut
.ut_line
, sizeof(line
) - 1);
1285 line
[sizeof(line
) - 1] = '\0';
1286 if (f
->f_type
== F_WALL
) {
1287 if ((p
= ttymsg(iov
, 7, line
, TTYMSGTIME
)) != NULL
) {
1288 errno
= 0; /* already in msg */
1293 /* should we send the message to this user? */
1294 for (i
= 0; i
< MAXUNAMES
; i
++) {
1295 if (!f
->f_un
.f_uname
[i
][0])
1297 if (!strncmp(f
->f_un
.f_uname
[i
], ut
.ut_name
,
1299 if ((p
= ttymsg(iov
, 7, line
, TTYMSGTIME
))
1301 errno
= 0; /* already in msg */
1313 reapchild(int signo __unused
)
1319 while ((pid
= wait3(&status
, WNOHANG
, (struct rusage
*)NULL
)) > 0) {
1321 /* Don't tell while we are initting. */
1324 /* First, look if it's a process from the dead queue. */
1325 if (deadq_remove(pid
))
1328 /* Now, look in list of active processes. */
1329 for (f
= Files
; f
; f
= f
->f_next
)
1330 if (f
->f_type
== F_PIPE
&&
1331 f
->f_un
.f_pipe
.f_pid
== pid
) {
1333 f
->f_un
.f_pipe
.f_pid
= 0;
1334 log_deadchild(pid
, status
,
1335 f
->f_un
.f_pipe
.f_pname
);
1344 * Return a printable representation of a host address.
1347 cvthname(struct sockaddr
*f
)
1350 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
);
1379 if (hl
> 0 && hname
[hl
-1] == '.')
1381 trimdomain(hname
, hl
);
1393 domark(int signo __unused
)
1400 * Print syslogd errors some place.
1403 logerror(const char *type
)
1406 static int recursed
= 0;
1408 /* If there's an error while trying to log an error, give up. */
1414 sizeof buf
, "syslogd: %s: %s", type
, strerror(errno
));
1416 snprintf(buf
, sizeof buf
, "syslogd: %s", type
);
1418 dprintf("%s\n", buf
);
1419 logmsg(LOG_SYSLOG
|LOG_ERR
, buf
, LocalHostName
, ADDDATE
);
1427 int was_initialized
;
1431 was_initialized
= Initialized
;
1432 Initialized
= 0; /* Don't log SIGCHLDs. */
1433 for (f
= Files
; f
!= NULL
; f
= f
->f_next
) {
1434 /* flush any pending output */
1436 fprintlog(f
, 0, (char *)NULL
);
1437 if (f
->f_type
== F_PIPE
&& f
->f_un
.f_pipe
.f_pid
> 0) {
1439 f
->f_un
.f_pipe
.f_pid
= 0;
1442 Initialized
= was_initialized
;
1444 dprintf("syslogd: exiting on signal %d\n", signo
);
1445 snprintf(buf
, sizeof(buf
), "exiting on signal %d", signo
);
1449 for (i
= 0; i
< nfunix
; i
++)
1450 if (funixn
[i
] && funix
[i
] != -1)
1456 * INIT -- Initialize syslogd from configuration table
1463 struct filed
*f
, *next
, **nextp
;
1465 char cline
[LINE_MAX
];
1466 char prog
[NAME_MAX
+1];
1467 char host
[MAXHOSTNAMELEN
];
1468 char oldLocalHostName
[MAXHOSTNAMELEN
];
1469 char hostMsg
[2*MAXHOSTNAMELEN
+40];
1470 char bootfileMsg
[LINE_MAX
];
1475 * Load hostname (may have changed).
1478 strlcpy(oldLocalHostName
, LocalHostName
,
1479 sizeof(oldLocalHostName
));
1480 if (gethostname(LocalHostName
, sizeof(LocalHostName
)))
1481 err(EX_OSERR
, "gethostname() failed");
1482 if ((p
= strchr(LocalHostName
, '.')) != NULL
) {
1490 * Close all open log files.
1493 for (f
= Files
; f
!= NULL
; f
= next
) {
1494 /* flush any pending output */
1496 fprintlog(f
, 0, (char *)NULL
);
1498 switch (f
->f_type
) {
1506 if (f
->f_un
.f_pipe
.f_pid
> 0) {
1508 deadq_enter(f
->f_un
.f_pipe
.f_pid
,
1509 f
->f_un
.f_pipe
.f_pname
);
1511 f
->f_un
.f_pipe
.f_pid
= 0;
1514 munmap(f
->f_un
.f_ring
.f_footer
,
1515 sizeof(struct clog_footer
));
1520 if (f
->f_program
) free(f
->f_program
);
1521 if (f
->f_host
) free(f
->f_host
);
1527 /* open the configuration file */
1528 if ((cf
= fopen(ConfFile
, "r")) == NULL
) {
1529 dprintf("cannot open %s\n", ConfFile
);
1530 *nextp
= (struct filed
*)calloc(1, sizeof(*f
));
1531 if (*nextp
== NULL
) {
1535 cfline("*.ERR\t/dev/console", *nextp
, "*", "*");
1536 (*nextp
)->f_next
= (struct filed
*)calloc(1, sizeof(*f
));
1537 if ((*nextp
)->f_next
== NULL
) {
1541 cfline("*.PANIC\t*", (*nextp
)->f_next
, "*", "*");
1547 * Foreach line in the conf table, open that file.
1550 strlcpy(host
, "*", sizeof(host
));
1551 strlcpy(prog
, "*", sizeof(prog
));
1552 while (fgets(cline
, sizeof(cline
), cf
) != NULL
) {
1554 * check for end-of-section, comments, strip off trailing
1555 * spaces and newline character. #!prog is treated specially:
1556 * following lines apply only to that program.
1558 for (p
= cline
; isspace(*p
); ++p
)
1564 if (*p
!= '!' && *p
!= '+' && *p
!= '-')
1567 if (*p
== '+' || *p
== '-') {
1571 if ((!*p
) || (*p
== '*')) {
1572 strlcpy(host
, "*", sizeof(host
));
1577 for (i
= 1; i
< MAXHOSTNAMELEN
- 1; i
++) {
1578 if (!isalnum(*p
) && *p
!= '.' && *p
!= '-'
1588 while (isspace(*p
)) p
++;
1589 if ((!*p
) || (*p
== '*')) {
1590 strlcpy(prog
, "*", sizeof(prog
));
1593 for (i
= 0; i
< NAME_MAX
; i
++) {
1601 for (i
= strlen(cline
) - 1; i
>= 0 && isspace(cline
[i
]); i
--)
1603 f
= (struct filed
*)calloc(1, sizeof(*f
));
1610 cfline(cline
, f
, prog
, host
);
1613 /* close the configuration file */
1619 for (f
= Files
; f
; f
= f
->f_next
) {
1620 for (i
= 0; i
<= LOG_NFACILITIES
; i
++)
1621 if (f
->f_pmask
[i
] == INTERNAL_NOPRI
)
1624 printf("%d ", f
->f_pmask
[i
]);
1625 printf("%s: ", TypeNames
[f
->f_type
]);
1626 switch (f
->f_type
) {
1628 printf("%s", f
->f_un
.f_fname
);
1633 printf("%s%s", _PATH_DEV
, f
->f_un
.f_fname
);
1637 printf("%s", f
->f_un
.f_forw
.f_hname
);
1641 printf("%s", f
->f_un
.f_ring
.f_rname
);
1645 printf("%s", f
->f_un
.f_pipe
.f_pname
);
1649 for (i
= 0; i
< MAXUNAMES
&& *f
->f_un
.f_uname
[i
]; i
++)
1650 printf("%s, ", f
->f_un
.f_uname
[i
]);
1654 printf(" (%s)", f
->f_program
);
1659 logmsg(LOG_SYSLOG
|LOG_INFO
, "syslogd: restart", LocalHostName
, ADDDATE
);
1660 dprintf("syslogd: restarted\n");
1662 * Log a change in hostname, but only on a restart.
1664 if (signo
!= 0 && strcmp(oldLocalHostName
, LocalHostName
) != 0) {
1665 snprintf(hostMsg
, sizeof(hostMsg
),
1666 "syslogd: hostname changed, \"%s\" to \"%s\"",
1667 oldLocalHostName
, LocalHostName
);
1668 logmsg(LOG_SYSLOG
|LOG_INFO
, hostMsg
, LocalHostName
, ADDDATE
);
1669 dprintf("%s\n", hostMsg
);
1672 * Log the kernel boot file if we aren't going to use it as
1673 * the prefix, and if this is *not* a restart.
1675 if (signo
== 0 && !use_bootfile
) {
1676 snprintf(bootfileMsg
, sizeof(bootfileMsg
),
1677 "syslogd: kernel boot file is %s", bootfile
);
1678 logmsg(LOG_KERN
|LOG_INFO
, bootfileMsg
, LocalHostName
, ADDDATE
);
1679 dprintf("%s\n", bootfileMsg
);
1684 * Crack a configuration file line
1687 cfline(const char *line
, struct filed
*f
, const char *prog
, const char *host
)
1689 struct addrinfo hints
, *res
;
1690 int error
, i
, pri
, syncfile
;
1693 char buf
[MAXLINE
], ebuf
[100];
1696 dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line
, prog
, host
);
1698 errno
= 0; /* keep strerror() stuff out of logerror messages */
1700 /* clear out file entry */
1701 memset(f
, 0, sizeof(*f
));
1702 for (i
= 0; i
<= LOG_NFACILITIES
; i
++)
1703 f
->f_pmask
[i
] = INTERNAL_NOPRI
;
1705 /* save hostname if any */
1706 if (host
&& *host
== '*')
1711 f
->f_host
= strdup(host
);
1712 if (f
->f_host
== NULL
) {
1716 hl
= strlen(f
->f_host
);
1717 if (hl
> 0 && f
->f_host
[hl
-1] == '.')
1718 f
->f_host
[--hl
] = '\0';
1719 trimdomain(f
->f_host
, hl
);
1722 /* save program name if any */
1723 if (prog
&& *prog
== '*')
1726 f
->f_program
= strdup(prog
);
1727 if (f
->f_program
== NULL
) {
1733 /* scan through the list of selectors */
1734 for (p
= line
; *p
&& *p
!= '\t' && *p
!= ' ';) {
1739 /* find the end of this facility name list */
1740 for (q
= p
; *q
&& *q
!= '\t' && *q
!= ' ' && *q
++ != '.'; )
1743 /* get the priority comparison */
1771 /* collect priority name */
1772 for (bp
= buf
; *q
&& !strchr("\t,; ", *q
); )
1777 while (strchr(",;", *q
))
1780 /* decode priority name */
1782 pri
= LOG_PRIMASK
+ 1;
1783 pri_cmp
= PRI_LT
| PRI_EQ
| PRI_GT
;
1785 /* Ignore trailing spaces. */
1786 for (i
= strlen(buf
) - 1; i
>= 0 && buf
[i
] == ' '; i
--)
1789 pri
= decode(buf
, prioritynames
);
1791 snprintf(ebuf
, sizeof ebuf
,
1792 "unknown priority name \"%s\"", buf
);
1798 pri_cmp
= (UniquePriority
)
1803 pri_cmp
^= PRI_LT
| PRI_EQ
| PRI_GT
;
1805 /* scan facilities */
1806 while (*p
&& !strchr("\t.; ", *p
)) {
1807 for (bp
= buf
; *p
&& !strchr("\t,;. ", *p
); )
1812 for (i
= 0; i
< LOG_NFACILITIES
; i
++) {
1813 f
->f_pmask
[i
] = pri
;
1814 f
->f_pcmp
[i
] = pri_cmp
;
1817 i
= decode(buf
, facilitynames
);
1819 snprintf(ebuf
, sizeof ebuf
,
1820 "unknown facility name \"%s\"",
1825 f
->f_pmask
[i
>> 3] = pri
;
1826 f
->f_pcmp
[i
>> 3] = pri_cmp
;
1828 while (*p
== ',' || *p
== ' ')
1835 /* skip to action part */
1836 while (*p
== '\t' || *p
== ' ')
1847 strlcpy(f
->f_un
.f_forw
.f_hname
, ++p
,
1848 sizeof(f
->f_un
.f_forw
.f_hname
));
1849 memset(&hints
, 0, sizeof(hints
));
1850 hints
.ai_family
= family
;
1851 hints
.ai_socktype
= SOCK_DGRAM
;
1852 error
= getaddrinfo(f
->f_un
.f_forw
.f_hname
, "syslog", &hints
,
1855 logerror(gai_strerror(error
));
1858 f
->f_un
.f_forw
.f_addr
= res
;
1863 if ((f
->f_file
= open(p
, O_WRONLY
|O_APPEND
, 0)) < 0) {
1864 f
->f_type
= F_UNUSED
;
1869 f
->f_flags
|= FFLAG_SYNC
;
1870 if (isatty(f
->f_file
)) {
1871 if (strcmp(p
, ctty
) == 0)
1872 f
->f_type
= F_CONSOLE
;
1875 strlcpy(f
->f_un
.f_fname
, p
+ sizeof(_PATH_DEV
) - 1,
1876 sizeof(f
->f_un
.f_fname
));
1878 strlcpy(f
->f_un
.f_fname
, p
, sizeof(f
->f_un
.f_fname
));
1884 if ((f
->f_file
= open(p
+ 1, O_RDWR
, 0 )) < 0) {
1885 f
->f_type
= F_UNUSED
;
1889 if (fstat(f
->f_file
,&sb
) < 0) {
1891 f
->f_type
= F_UNUSED
;
1895 f
->f_un
.f_ring
.f_footer
=
1896 mmap(NULL
, sizeof(struct clog_footer
),
1897 PROT_READ
|PROT_WRITE
, MAP_SHARED
,
1898 f
->f_file
, sb
.st_size
-sizeof(struct clog_footer
));
1899 if (f
->f_un
.f_ring
.f_footer
== NULL
) {
1901 f
->f_type
= F_UNUSED
;
1905 if (memcmp(&(f
->f_un
.f_ring
.f_footer
->cf_magic
), MAGIC_CONST
, 4) != 0) {
1906 munmap(f
->f_un
.f_ring
.f_footer
,
1907 sizeof(struct clog_footer
));
1909 f
->f_type
= F_UNUSED
;
1914 f
->f_un
.f_ring
.f_size
= sb
.st_size
;
1915 strcpy(f
->f_un
.f_ring
.f_rname
, p
+ 1);
1920 f
->f_un
.f_pipe
.f_pid
= 0;
1921 strlcpy(f
->f_un
.f_fname
, p
+ 1, sizeof(f
->f_un
.f_fname
));
1930 for (i
= 0; i
< MAXUNAMES
&& *p
; i
++) {
1931 for (q
= p
; *q
&& *q
!= ','; )
1933 strncpy(f
->f_un
.f_uname
[i
], p
, UT_NAMESIZE
);
1934 if ((q
- p
) > UT_NAMESIZE
)
1935 f
->f_un
.f_uname
[i
][UT_NAMESIZE
] = '\0';
1937 f
->f_un
.f_uname
[i
][q
- p
] = '\0';
1938 while (*q
== ',' || *q
== ' ')
1942 f
->f_type
= F_USERS
;
1949 * Decode a symbolic name to a numeric value
1952 decode(const char *name
, CODE
*codetab
)
1958 return (atoi(name
));
1960 for (p
= buf
; *name
&& p
< &buf
[sizeof(buf
) - 1]; p
++, name
++) {
1962 *p
= tolower(*name
);
1967 for (c
= codetab
; c
->c_name
; c
++)
1968 if (!strcmp(buf
, c
->c_name
))
1980 now
= time((time_t *)NULL
);
1981 MarkSeq
+= TIMERINTVL
;
1982 if (MarkSeq
>= MarkInterval
) {
1983 logmsg(LOG_INFO
, "-- MARK --",
1984 LocalHostName
, ADDDATE
|MARK
);
1988 for (f
= Files
; f
; f
= f
->f_next
) {
1989 if (f
->f_prevcount
&& now
>= REPEATTIME(f
)) {
1990 dprintf("flush %s: repeated %d times, %d sec.\n",
1991 TypeNames
[f
->f_type
], f
->f_prevcount
,
1992 repeatinterval
[f
->f_repeatcount
]);
1993 fprintlog(f
, 0, (char *)NULL
);
1998 /* Walk the dead queue, and see if we should signal somebody. */
1999 for (q
= TAILQ_FIRST(&deadq_head
); q
!= NULL
; q
= next
) {
2000 next
= TAILQ_NEXT(q
, dq_entries
);
2002 switch (q
->dq_timeout
) {
2004 /* Already signalled once, try harder now. */
2005 if (kill(q
->dq_pid
, SIGKILL
) != 0)
2006 deadq_remove(q
->dq_pid
);
2011 * Timed out on dead queue, send terminate
2012 * signal. Note that we leave the removal
2013 * from the dead queue to reapchild(), which
2014 * will also log the event (unless the process
2015 * didn't even really exist, in case we simply
2016 * drop it from the dead queue).
2018 if (kill(q
->dq_pid
, SIGTERM
) != 0)
2019 deadq_remove(q
->dq_pid
);
2031 * fork off and become a daemon, but wait for the child to come online
2032 * before returing to the parent, or we get disk thrashing at boot etc.
2033 * Set a timer so we don't hang forever if it wedges.
2036 waitdaemon(int nochdir
, int noclose
, int maxwait
)
2040 pid_t pid
, childpid
;
2042 switch (childpid
= fork()) {
2048 signal(SIGALRM
, timedout
);
2050 while ((pid
= wait3(&status
, 0, NULL
)) != -1) {
2051 if (WIFEXITED(status
))
2052 errx(1, "child pid %d exited with return code %d",
2053 pid
, WEXITSTATUS(status
));
2054 if (WIFSIGNALED(status
))
2055 errx(1, "child pid %d exited on signal %d%s",
2056 pid
, WTERMSIG(status
),
2057 WCOREDUMP(status
) ? " (core dumped)" :
2059 if (pid
== childpid
) /* it's gone... */
2071 if (!noclose
&& (fd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) != -1) {
2072 dup2(fd
, STDIN_FILENO
);
2073 dup2(fd
, STDOUT_FILENO
);
2074 dup2(fd
, STDERR_FILENO
);
2082 * We get a SIGALRM from the child when it's running and finished doing it's
2083 * fsync()'s or O_SYNC writes for all the boot messages.
2085 * We also get a signal from the kernel if the timer expires, so check to
2086 * see what happened.
2089 timedout(int sig __unused
)
2093 signal(SIGALRM
, SIG_DFL
);
2095 errx(1, "timed out waiting for child");
2101 * Add `s' to the list of allowable peer addresses to accept messages
2104 * `s' is a string in the form:
2106 * [*]domainname[:{servicename|portnumber|*}]
2110 * netaddr/maskbits[:{servicename|portnumber|*}]
2112 * Returns -1 on error, 0 if the argument was valid.
2118 struct allowedpeer ap
;
2120 int masklen
= -1, i
;
2121 struct addrinfo hints
, *res
;
2122 struct in_addr
*addrp
, *maskp
;
2123 u_int32_t
*addr6p
, *mask6p
;
2124 char ip
[NI_MAXHOST
];
2127 if (*s
!= '[' || (cp1
= strchr(s
+ 1, ']')) == NULL
)
2130 if ((cp1
= strrchr(cp1
, ':'))) {
2131 /* service/port provided */
2133 if (strlen(cp1
) == 1 && *cp1
== '*')
2134 /* any port allowed */
2136 else if ((se
= getservbyname(cp1
, "udp"))) {
2137 ap
.port
= ntohs(se
->s_port
);
2139 ap
.port
= strtol(cp1
, &cp2
, 0);
2141 return (-1); /* port not numeric */
2144 if ((se
= getservbyname("syslog", "udp")))
2145 ap
.port
= ntohs(se
->s_port
);
2147 /* sanity, should not happen */
2151 if ((cp1
= strchr(s
, '/')) != NULL
&&
2152 strspn(cp1
+ 1, "0123456789") == strlen(cp1
+ 1)) {
2154 if ((masklen
= atoi(cp1
+ 1)) < 0)
2159 cp2
= s
+ strlen(s
) - 1;
2170 memset(&hints
, 0, sizeof(hints
));
2171 hints
.ai_family
= PF_UNSPEC
;
2172 hints
.ai_socktype
= SOCK_DGRAM
;
2173 hints
.ai_flags
= AI_PASSIVE
| AI_NUMERICHOST
;
2174 if (getaddrinfo(s
, NULL
, &hints
, &res
) == 0) {
2176 memcpy(&ap
.a_addr
, res
->ai_addr
, res
->ai_addrlen
);
2177 memset(&ap
.a_mask
, 0, sizeof(ap
.a_mask
));
2178 ap
.a_mask
.ss_family
= res
->ai_family
;
2179 if (res
->ai_family
== AF_INET
) {
2180 ap
.a_mask
.ss_len
= sizeof(struct sockaddr_in
);
2181 maskp
= &((struct sockaddr_in
*)&ap
.a_mask
)->sin_addr
;
2182 addrp
= &((struct sockaddr_in
*)&ap
.a_addr
)->sin_addr
;
2184 /* use default netmask */
2185 if (IN_CLASSA(ntohl(addrp
->s_addr
)))
2186 maskp
->s_addr
= htonl(IN_CLASSA_NET
);
2187 else if (IN_CLASSB(ntohl(addrp
->s_addr
)))
2188 maskp
->s_addr
= htonl(IN_CLASSB_NET
);
2190 maskp
->s_addr
= htonl(IN_CLASSC_NET
);
2191 } else if (masklen
<= 32) {
2192 /* convert masklen to netmask */
2196 maskp
->s_addr
= htonl(~((1 << (32 - masklen
)) - 1));
2201 /* Lose any host bits in the network number. */
2202 addrp
->s_addr
&= maskp
->s_addr
;
2205 else if (res
->ai_family
== AF_INET6
&& masklen
<= 128) {
2206 ap
.a_mask
.ss_len
= sizeof(struct sockaddr_in6
);
2209 mask6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_mask
)->sin6_addr
;
2210 /* convert masklen to netmask */
2211 while (masklen
> 0) {
2213 *mask6p
= htonl(~(0xffffffff >> masklen
));
2216 *mask6p
++ = 0xffffffff;
2219 /* Lose any host bits in the network number. */
2220 mask6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_mask
)->sin6_addr
;
2221 addr6p
= (u_int32_t
*)&((struct sockaddr_in6
*)&ap
.a_addr
)->sin6_addr
;
2222 for (i
= 0; i
< 4; i
++)
2223 addr6p
[i
] &= mask6p
[i
];
2232 /* arg `s' is domain name */
2246 printf("allowaddr: rule %d: ", NumAllowed
);
2248 printf("numeric, ");
2249 getnameinfo((struct sockaddr
*)&ap
.a_addr
,
2250 ((struct sockaddr
*)&ap
.a_addr
)->sa_len
,
2251 ip
, sizeof ip
, NULL
, 0,
2252 NI_NUMERICHOST
| withscopeid
);
2253 printf("addr = %s, ", ip
);
2254 getnameinfo((struct sockaddr
*)&ap
.a_mask
,
2255 ((struct sockaddr
*)&ap
.a_mask
)->sa_len
,
2256 ip
, sizeof ip
, NULL
, 0,
2257 NI_NUMERICHOST
| withscopeid
);
2258 printf("mask = %s; ", ip
);
2260 printf("domainname = %s; ", ap
.a_name
);
2262 printf("port = %d\n", ap
.port
);
2265 if ((AllowedPeers
= realloc(AllowedPeers
,
2266 ++NumAllowed
* sizeof(struct allowedpeer
)))
2268 logerror("realloc");
2271 memcpy(&AllowedPeers
[NumAllowed
- 1], &ap
, sizeof(struct allowedpeer
));
2276 * Validate that the remote peer has permission to log to us.
2279 validate(struct sockaddr
*sa
, const char *hname
)
2283 char *cp
, name
[NI_MAXHOST
], ip
[NI_MAXHOST
], port
[NI_MAXSERV
];
2284 struct allowedpeer
*ap
;
2285 struct sockaddr_in
*sin4
, *a4p
= NULL
, *m4p
= NULL
;
2286 struct sockaddr_in6
*sin6
, *a6p
= NULL
, *m6p
= NULL
;
2287 struct addrinfo hints
, *res
;
2290 if (NumAllowed
== 0)
2291 /* traditional behaviour, allow everything */
2294 strlcpy(name
, hname
, sizeof(name
));
2295 memset(&hints
, 0, sizeof(hints
));
2296 hints
.ai_family
= PF_UNSPEC
;
2297 hints
.ai_socktype
= SOCK_DGRAM
;
2298 hints
.ai_flags
= AI_PASSIVE
| AI_NUMERICHOST
;
2299 if (getaddrinfo(name
, NULL
, &hints
, &res
) == 0)
2301 else if (strchr(name
, '.') == NULL
) {
2302 strlcat(name
, ".", sizeof name
);
2303 strlcat(name
, LocalDomain
, sizeof name
);
2305 if (getnameinfo(sa
, sa
->sa_len
, ip
, sizeof ip
, port
, sizeof port
,
2306 NI_NUMERICHOST
| withscopeid
| NI_NUMERICSERV
) != 0)
2307 return (0); /* for safety, should not occur */
2308 dprintf("validate: dgram from IP %s, port %s, name %s;\n",
2312 /* now, walk down the list */
2313 for (i
= 0, ap
= AllowedPeers
; i
< NumAllowed
; i
++, ap
++) {
2314 if (ap
->port
!= 0 && ap
->port
!= sport
) {
2315 dprintf("rejected in rule %d due to port mismatch.\n", i
);
2319 if (ap
->isnumeric
) {
2320 if (ap
->a_addr
.ss_family
!= sa
->sa_family
) {
2321 dprintf("rejected in rule %d due to address family mismatch.\n", i
);
2324 if (ap
->a_addr
.ss_family
== AF_INET
) {
2325 sin4
= (struct sockaddr_in
*)sa
;
2326 a4p
= (struct sockaddr_in
*)&ap
->a_addr
;
2327 m4p
= (struct sockaddr_in
*)&ap
->a_mask
;
2328 if ((sin4
->sin_addr
.s_addr
& m4p
->sin_addr
.s_addr
)
2329 != a4p
->sin_addr
.s_addr
) {
2330 dprintf("rejected in rule %d due to IP mismatch.\n", i
);
2335 else if (ap
->a_addr
.ss_family
== AF_INET6
) {
2336 sin6
= (struct sockaddr_in6
*)sa
;
2337 a6p
= (struct sockaddr_in6
*)&ap
->a_addr
;
2338 m6p
= (struct sockaddr_in6
*)&ap
->a_mask
;
2339 #ifdef NI_WITHSCOPEID
2340 if (a6p
->sin6_scope_id
!= 0 &&
2341 sin6
->sin6_scope_id
!= a6p
->sin6_scope_id
) {
2342 dprintf("rejected in rule %d due to scope mismatch.\n", i
);
2347 for (j
= 0; j
< 16; j
+= 4) {
2348 if ((*(u_int32_t
*)&sin6
->sin6_addr
.s6_addr
[j
] & *(u_int32_t
*)&m6p
->sin6_addr
.s6_addr
[j
])
2349 != *(u_int32_t
*)&a6p
->sin6_addr
.s6_addr
[j
]) {
2355 dprintf("rejected in rule %d due to IP mismatch.\n", i
);
2366 /* allow wildmatch */
2369 if (l2
> l1
|| memcmp(cp
, &name
[l1
- l2
], l2
) != 0) {
2370 dprintf("rejected in rule %d due to name mismatch.\n", i
);
2376 if (l2
!= l1
|| memcmp(cp
, name
, l1
) != 0) {
2377 dprintf("rejected in rule %d due to name mismatch.\n", i
);
2382 dprintf("accepted in rule %d.\n", i
);
2383 return (1); /* hooray! */
2389 * Fairly similar to popen(3), but returns an open descriptor, as
2390 * opposed to a FILE *.
2393 p_open(const char *prog
, pid_t
*rpid
)
2395 int pfd
[2], nulldesc
, i
;
2397 sigset_t omask
, mask
;
2398 char *argv
[4]; /* sh -c cmd NULL */
2401 if (pipe(pfd
) == -1)
2403 if ((nulldesc
= open(_PATH_DEVNULL
, O_RDWR
)) == -1)
2404 /* we are royally screwed anyway */
2408 sigaddset(&mask
, SIGALRM
);
2409 sigaddset(&mask
, SIGHUP
);
2410 sigprocmask(SIG_BLOCK
, &mask
, &omask
);
2411 switch ((pid
= fork())) {
2413 sigprocmask(SIG_SETMASK
, &omask
, 0);
2418 argv
[0] = strdup("sh");
2419 argv
[1] = strdup("-c");
2420 argv
[2] = strdup(prog
);
2422 if (argv
[0] == NULL
|| argv
[1] == NULL
|| argv
[2] == NULL
) {
2428 setsid(); /* Avoid catching SIGHUPs. */
2431 * Throw away pending signals, and reset signal
2432 * behaviour to standard values.
2434 signal(SIGALRM
, SIG_IGN
);
2435 signal(SIGHUP
, SIG_IGN
);
2436 sigprocmask(SIG_SETMASK
, &omask
, 0);
2437 signal(SIGPIPE
, SIG_DFL
);
2438 signal(SIGQUIT
, SIG_DFL
);
2439 signal(SIGALRM
, SIG_DFL
);
2440 signal(SIGHUP
, SIG_DFL
);
2442 dup2(pfd
[0], STDIN_FILENO
);
2443 dup2(nulldesc
, STDOUT_FILENO
);
2444 dup2(nulldesc
, STDERR_FILENO
);
2445 for (i
= getdtablesize(); i
> 2; i
--)
2448 execvp(_PATH_BSHELL
, argv
);
2452 sigprocmask(SIG_SETMASK
, &omask
, 0);
2456 * Avoid blocking on a hung pipe. With O_NONBLOCK, we are
2457 * supposed to get an EWOULDBLOCK on writev(2), which is
2458 * caught by the logic above anyway, which will in turn close
2459 * the pipe, and fork a new logging subprocess if necessary.
2460 * The stale subprocess will be killed some time later unless
2461 * it terminated itself due to closing its input pipe (so we
2462 * get rid of really dead puppies).
2464 if (fcntl(pfd
[1], F_SETFL
, O_NONBLOCK
) == -1) {
2466 snprintf(errmsg
, sizeof errmsg
,
2467 "Warning: cannot change pipe to PID %d to "
2468 "non-blocking behaviour.",
2477 deadq_enter(pid_t pid
, const char *name
)
2483 * Be paranoid, if we can't signal the process, don't enter it
2484 * into the dead queue (perhaps it's already dead). If possible,
2485 * we try to fetch and log the child's status.
2487 if (kill(pid
, 0) != 0) {
2488 if (waitpid(pid
, &status
, WNOHANG
) > 0)
2489 log_deadchild(pid
, status
, name
);
2493 p
= malloc(sizeof(struct deadq_entry
));
2500 p
->dq_timeout
= DQ_TIMO_INIT
;
2501 TAILQ_INSERT_TAIL(&deadq_head
, p
, dq_entries
);
2505 deadq_remove(pid_t pid
)
2509 TAILQ_FOREACH(q
, &deadq_head
, dq_entries
) {
2510 if (q
->dq_pid
== pid
) {
2511 TAILQ_REMOVE(&deadq_head
, q
, dq_entries
);
2521 log_deadchild(pid_t pid
, int status
, const char *name
)
2527 errno
= 0; /* Keep strerror() stuff out of logerror messages. */
2528 if (WIFSIGNALED(status
)) {
2529 reason
= "due to signal";
2530 code
= WTERMSIG(status
);
2532 reason
= "with status";
2533 code
= WEXITSTATUS(status
);
2537 snprintf(buf
, sizeof buf
,
2538 "Logging subprocess %d (%s) exited %s %d.",
2539 pid
, name
, reason
, code
);
2544 socksetup(int af
, const char *bindhostname
)
2546 struct addrinfo hints
, *res
, *r
;
2547 int error
, maxs
, *s
, *socks
;
2549 memset(&hints
, 0, sizeof(hints
));
2550 hints
.ai_flags
= AI_PASSIVE
;
2551 hints
.ai_family
= af
;
2552 hints
.ai_socktype
= SOCK_DGRAM
;
2553 error
= getaddrinfo(bindhostname
, "syslog", &hints
, &res
);
2555 logerror(gai_strerror(error
));
2560 /* Count max number of sockets we may open */
2561 for (maxs
= 0, r
= res
; r
; r
= r
->ai_next
, maxs
++);
2562 socks
= malloc((maxs
+1) * sizeof(int));
2563 if (socks
== NULL
) {
2564 logerror("couldn't allocate memory for sockets");
2568 *socks
= 0; /* num of sockets counter at start of array */
2570 for (r
= res
; r
; r
= r
->ai_next
) {
2571 *s
= socket(r
->ai_family
, r
->ai_socktype
, r
->ai_protocol
);
2576 if (r
->ai_family
== AF_INET6
) {
2578 if (setsockopt(*s
, IPPROTO_IPV6
, IPV6_V6ONLY
,
2579 (char *)&on
, sizeof (on
)) < 0) {
2580 logerror("setsockopt");
2585 if (bind(*s
, r
->ai_addr
, r
->ai_addrlen
) < 0) {
2609 rbwritev(struct filed
*f
, struct iovec
*iov
, int iovcnt
)
2615 for (i
= 0; i
< iovcnt
; i
++) {
2616 error
= rbwrite(f
, iov
[i
].iov_base
, iov
[i
].iov_len
);
2626 rbwrite(struct filed
*f
, char *buf
, size_t nbytes
)
2632 maxwrite
= f
->f_un
.f_ring
.f_footer
->cf_max
-
2633 f
->f_un
.f_ring
.f_footer
->cf_next
;
2636 f
->f_un
.f_ring
.f_footer
->cf_lock
= 1;
2637 while (nbytes
> 0) {
2638 maxwrite
= f
->f_un
.f_ring
.f_footer
->cf_max
-
2639 f
->f_un
.f_ring
.f_footer
->cf_next
;
2640 if (maxwrite
> nbytes
)
2642 error
= pwrite(f
->f_file
, buf
, maxwrite
,
2643 f
->f_un
.f_ring
.f_footer
->cf_next
);
2645 f
->f_un
.f_ring
.f_footer
->cf_lock
= 0;
2651 f
->f_un
.f_ring
.f_footer
->cf_next
+= error
;
2652 if (f
->f_un
.f_ring
.f_footer
->cf_next
==
2653 f
->f_un
.f_ring
.f_footer
->cf_max
) {
2654 f
->f_un
.f_ring
.f_footer
->cf_next
= 0;
2655 f
->f_un
.f_ring
.f_footer
->cf_wrap
= 1;
2660 f
->f_un
.f_ring
.f_footer
->cf_lock
= 0;