4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright (c) 2013 Gary Mills
29 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
34 * University Copyright- Copyright (c) 1982, 1986, 1988
35 * The Regents of the University of California
38 * University Acknowledgment- Portions of this document are derived from
39 * software developed by the University of California, Berkeley, and its
44 * syslogd -- log system messages
46 * This program implements a system log. It takes a series of lines.
47 * Each line may have a priority, signified as "<n>" as
48 * the first characters of the line. If this is
49 * not present, a default priority is used.
51 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
52 * cause it to reconfigure.
56 * MAXLINE -- the maximimum line length that can be handled.
57 * DEFUPRI -- the default priority for user messages.
58 * DEFSPRI -- the default priority for kernel messages.
65 #include <sys/types.h>
67 #include <stdio_ext.h>
74 #include <netconfig.h>
77 #include <sys/socket.h>
85 #include <sys/statvfs.h>
87 #include <sys/param.h>
88 #include <sys/sysmacros.h>
89 #include <sys/syslog.h>
90 #include <sys/strlog.h>
93 #include <sys/utsname.h>
96 #include <sys/resource.h>
109 #define DOORFILE "/var/run/syslog_door"
110 #define RELATIVE_DOORFILE "../var/run/syslog_door"
111 #define OLD_DOORFILE "/etc/.syslog_door"
113 #define PIDFILE "/var/run/syslog.pid"
114 #define RELATIVE_PIDFILE "../var/run/syslog.pid"
115 #define OLD_PIDFILE "/etc/syslog.pid"
117 static char *LogName
= "/dev/log";
118 static char *ConfFile
= "/etc/syslog.conf";
119 static char ctty
[] = "/dev/console";
120 static char sysmsg
[] = "/dev/sysmsg";
121 static int DoorFd
= -1;
122 static int DoorCreated
= 0;
123 static int PidfileCreated
= 0;
124 static char *DoorFileName
= DOORFILE
;
125 static char *PidFileName
= PIDFILE
;
128 * configuration file directives
131 static struct code PriNames
[] = {
139 "warning", LOG_WARNING
,
140 "notice", LOG_NOTICE
,
147 static struct code FacNames
[] = {
151 "daemon", LOG_DAEMON
,
153 "security", LOG_AUTH
,
155 "syslog", LOG_SYSLOG
,
159 "altcron", LOG_ALTCRON
,
160 "authpriv", LOG_AUTHPRIV
,
164 "console", LOG_CONSOLE
,
166 "local0", LOG_LOCAL0
,
167 "local1", LOG_LOCAL1
,
168 "local2", LOG_LOCAL2
,
169 "local3", LOG_LOCAL3
,
170 "local4", LOG_LOCAL4
,
171 "local5", LOG_LOCAL5
,
172 "local6", LOG_LOCAL6
,
173 "local7", LOG_LOCAL7
,
177 static char *TypeNames
[7] = {
178 "UNUSED", "FILE", "TTY", "CONSOLE",
179 "FORW", "USERS", "WALL"
183 * we allocate our own thread stacks so we can create them
184 * without the MAP_NORESERVE option. We need to be sure
185 * we have stack space even if the machine runs out of swap
188 #define DEFAULT_STACKSIZE (100 * 1024) /* 100 k stack */
189 #define DEFAULT_REDZONESIZE (8 * 1024) /* 8k redzone */
191 static pthread_mutex_t wmp
= PTHREAD_MUTEX_INITIALIZER
; /* wallmsg lock */
193 static pthread_mutex_t cft
= PTHREAD_MUTEX_INITIALIZER
;
194 static int conf_threads
= 0;
196 static pthread_mutex_t hup_lock
= PTHREAD_MUTEX_INITIALIZER
;
197 static pthread_cond_t hup_done
= PTHREAD_COND_INITIALIZER
;
199 static pthread_mutex_t logerror_lock
= PTHREAD_MUTEX_INITIALIZER
;
201 #define HUP_ACCEPTABLE 0x0000 /* can start SIGHUP process */
202 #define HUP_INPROGRESS 0x0001 /* SIGHUP process in progress */
203 #define HUP_COMPLETED 0x0002 /* SIGHUP process completed */
204 #define HUP_SUSP_LOGMSG_REQD 0x1000 /* request to suspend */
205 #define HUP_LOGMSG_SUSPENDED 0x2000 /* logmsg is suspended */
206 static int hup_state
= HUP_ACCEPTABLE
;
208 static size_t stacksize
; /* thread stack size */
209 static size_t redzonesize
; /* thread stack redzone size */
210 static char *stack_ptr
; /* ptr to allocated stacks */
211 static char *cstack_ptr
; /* ptr to conf_thr stacks */
213 static time_t start_time
;
215 static pthread_t sys_thread
; /* queues messages from us */
216 static pthread_t net_thread
; /* queues messages from the net */
217 static pthread_t log_thread
; /* message processing thread */
218 static pthread_t hnl_thread
; /* hostname lookup thread */
220 static dataq_t inputq
; /* the input queue */
221 static dataq_t tmpq
; /* temporary queue for err msg */
222 static dataq_t hnlq
; /* hostname lookup queue */
224 static struct filed fallback
[2];
225 static struct filed
*Files
;
227 static int Debug
; /* debug flag */
228 static host_list_t LocalHostName
; /* our hostname */
229 static host_list_t NullHostName
; /* in case of lookup failure */
230 static int debuglev
= 1; /* debug print level */
231 static int interrorlog
; /* internal error logging */
233 static int MarkInterval
= 20; /* interval between marks (mins) */
234 static int Marking
= 0; /* non-zero if marking some file */
235 static int Ninputs
= 0; /* number of network inputs */
236 static int curalarm
= 0; /* current timeout value (secs) */
237 static int sys_msg_count
= 0; /* total msgs rcvd from local log */
238 static int sys_init_msg_count
= 0; /* initially received */
239 static int net_msg_count
= 0; /* total msgs rcvd from net */
241 static struct pollfd Pfd
; /* Pollfd for local the log device */
242 static struct pollfd
*Nfd
; /* Array of pollfds for udp ports */
243 static struct netconfig
*Ncf
;
244 static struct netbuf
**Myaddrs
;
245 static struct t_unitdata
**Udp
;
246 static struct t_uderr
**Errp
;
247 static int turnoff
= 0;
248 static int shutting_down
;
250 /* for managing door server threads */
251 static pthread_mutex_t door_server_cnt_lock
= PTHREAD_MUTEX_INITIALIZER
;
252 static uint_t door_server_cnt
= 0;
253 static pthread_attr_t door_thr_attr
;
255 static struct hostname_cache
**hnc_cache
;
256 static pthread_mutex_t hnc_mutex
= PTHREAD_MUTEX_INITIALIZER
;
257 static size_t hnc_size
= DEF_HNC_SIZE
;
258 static unsigned int hnc_ttl
= DEF_HNC_TTL
;
260 #define DPRINT0(d, m) if ((Debug) && debuglev >= (d)) \
261 (void) fprintf(stderr, m)
262 #define DPRINT1(d, m, a) if ((Debug) && debuglev >= (d)) \
263 (void) fprintf(stderr, m, a)
264 #define DPRINT2(d, m, a, b) if ((Debug) && debuglev >= (d)) \
265 (void) fprintf(stderr, m, a, b)
266 #define DPRINT3(d, m, a, b, c) if ((Debug) && debuglev >= (d)) \
267 (void) fprintf(stderr, m, a, b, c)
268 #define DPRINT4(d, m, a, b, c, e) if ((Debug) && debuglev >= (d)) \
269 (void) fprintf(stderr, m, a, b, c, e)
270 #define MALLOC_FAIL(x) \
271 logerror("malloc failed: " x)
272 #define MALLOC_FAIL_EXIT \
273 logerror("malloc failed - fatal"); \
277 #define MAILCMD "mailx -s \"syslogd shut down\" root"
280 * Number of seconds to wait before giving up on threads that won't
281 * shutdown: (that's right, 10 minutes!)
283 #define LOOP_MAX (10 * 60)
286 * Interval(sec) to check the status of output queue while processing
289 #define LOOP_INTERVAL (15)
292 main(int argc
, char **argv
)
297 int tflag
= 0, Tflag
= 0;
298 sigset_t sigs
, allsigs
;
302 struct sigaction act
;
303 pthread_t mythreadno
= 0;
308 #define DEBUGDIR "/var/tmp"
310 DPRINT2(1, "main(%u): Unable to cd to %s\n", mythreadno
,
314 (void) setlocale(LC_ALL
, "");
316 if ((debugstr
= getenv("SYSLOGD_DEBUG")) != NULL
)
317 if ((debuglev
= atoi(debugstr
)) == 0)
320 #if ! defined(TEXT_DOMAIN) /* should be defined by cc -D */
321 #define TEXT_DOMAIN "SYS_TEST"
323 (void) textdomain(TEXT_DOMAIN
);
325 (void) time(&start_time
);
327 if (lstat("/var/run", &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
328 DoorFileName
= OLD_DOORFILE
;
329 PidFileName
= OLD_PIDFILE
;
334 while ((i
= getopt(argc
, argv
, "df:p:m:tT")) != EOF
) {
336 case 'f': /* configuration file */
340 case 'd': /* debug */
348 case 'm': /* mark interval */
349 for (pstr
= optarg
; *pstr
; pstr
++) {
350 if (! (isdigit(*pstr
))) {
351 (void) fprintf(stderr
,
352 "Illegal interval\n");
356 MarkInterval
= atoi(optarg
);
357 if (MarkInterval
< 1 || MarkInterval
> INT_MAX
) {
358 (void) fprintf(stderr
,
359 "Interval must be between 1 and %d\n",
364 case 't': /* turn off remote reception */
368 case 'T': /* turn on remote reception */
380 if (tflag
&& Tflag
) {
381 (void) fprintf(stderr
, "specify only one of -t and -T\n");
386 * close all fd's except 0-2
395 (void) open("/", O_RDONLY
);
402 mythreadno
= pthread_self();
406 * DO NOT call logerror() until tmpq is initialized.
411 * ensure that file descriptor limit is "high enough"
413 (void) getrlimit(RLIMIT_NOFILE
, &rlim
);
414 if (rlim
.rlim_cur
< rlim
.rlim_max
)
415 rlim
.rlim_cur
= rlim
.rlim_max
;
416 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
417 logerror("Unable to increase file descriptor limit.");
418 (void) enable_extended_FILE_stdio(-1, -1);
420 /* block all signals from all threads initially */
421 (void) sigfillset(&allsigs
);
422 (void) pthread_sigmask(SIG_BLOCK
, &allsigs
, NULL
);
424 DPRINT2(1, "main(%u): Started at time %s", mythreadno
,
425 ctime_r(&start_time
, cbuf
));
427 init(); /* read configuration, start threads */
429 DPRINT1(1, "main(%u): off & running....\n", mythreadno
);
431 /* now set up to catch signals we care about */
433 (void) sigemptyset(&sigs
);
434 (void) sigaddset(&sigs
, SIGHUP
); /* reconfigure */
435 (void) sigaddset(&sigs
, SIGALRM
); /* mark & flush timer */
436 (void) sigaddset(&sigs
, SIGTERM
); /* exit */
437 (void) sigaddset(&sigs
, SIGINT
); /* exit if debugging */
438 (void) sigaddset(&sigs
, SIGQUIT
); /* exit if debugging */
439 (void) sigaddset(&sigs
, SIGPIPE
); /* catch & discard */
440 (void) sigaddset(&sigs
, SIGUSR1
); /* dump debug stats */
443 * We must set up to catch these signals, even though sigwait
444 * will get them before the isr does. Setting SA_SIGINFO ensures
445 * that signals will be enqueued.
448 act
.sa_flags
= SA_SIGINFO
;
449 act
.sa_sigaction
= signull
;
451 (void) sigaction(SIGHUP
, &act
, NULL
);
452 (void) sigaction(SIGALRM
, &act
, NULL
);
453 (void) sigaction(SIGTERM
, &act
, NULL
);
454 (void) sigaction(SIGINT
, &act
, NULL
);
455 (void) sigaction(SIGQUIT
, &act
, NULL
);
456 (void) sigaction(SIGPIPE
, &act
, NULL
);
457 (void) sigaction(SIGUSR1
, &act
, NULL
);
459 /* we now turn into the signal handling thread */
461 DPRINT1(2, "main(%u): now handling signals\n", mythreadno
);
463 (void) sigwait(&sigs
, &sig
);
464 DPRINT2(2, "main(%u): received signal %d\n", mythreadno
, sig
);
467 DPRINT1(1, "main(%u): Got SIGALRM\n",
470 if (Marking
&& (++mcount
% MARKCOUNT
== 0)) {
471 if (logmymsg(LOG_INFO
, "-- MARK --",
472 ADDDATE
|MARK
|NOCOPY
, 0) == -1) {
474 "dropping MARK message");
479 curalarm
= MarkInterval
* 60 / MARKCOUNT
;
480 (void) alarm((unsigned)curalarm
);
481 DPRINT2(2, "main(%u): Next alarm in %d "
482 "seconds\n", mythreadno
, curalarm
);
485 DPRINT1(1, "main(%u): got SIGHUP - "
486 "reconfiguring\n", mythreadno
);
490 DPRINT1(1, "main(%u): done processing SIGHUP\n",
496 /* allow these signals if debugging */
501 DPRINT2(1, "main(%u): going down on signal %d\n",
507 logerror("going down on signal %d", sig
);
508 disable_errorlog(); /* force msg to console */
509 (void) shutdown_msg(); /* stop threads */
514 case SIGUSR1
: /* secret debug dump mode */
515 /* if in debug mode, use stdout */
518 dumpstats(STDOUT_FILENO
);
521 /* otherwise dump to a debug file */
522 if ((fd
= open(DEBUGFILE
,
523 (O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
),
530 DPRINT2(2, "main(%u): unexpected signal %d\n",
538 * Attempts to open the local log device
539 * and return a file descriptor.
542 openklog(char *name
, int mode
)
546 pthread_t mythreadno
;
549 mythreadno
= pthread_self();
552 if ((fd
= open(name
, mode
)) < 0) {
553 logerror("cannot open %s", name
);
554 DPRINT3(1, "openklog(%u): cannot create %s (%d)\n",
555 mythreadno
, name
, errno
);
558 str
.ic_cmd
= I_CONSLOG
;
562 if (ioctl(fd
, I_STR
, &str
) < 0) {
563 logerror("cannot register to log console messages");
564 DPRINT2(1, "openklog(%u): cannot register to log "
565 "console messages (%d)\n", mythreadno
, errno
);
573 * Open the log device, and pull up all pending messages.
580 if ((funix
= openklog(LogName
, O_RDONLY
)) < 0) {
581 logerror("can't open kernel log device - fatal");
589 nfds
= poll(&Pfd
, 1, 0);
591 if (sys_init_msg_count
> 0)
596 if (Pfd
.revents
& POLLIN
) {
598 } else if (Pfd
.revents
& (POLLNVAL
|POLLHUP
|POLLERR
)) {
599 logerror("kernel log driver poll error");
607 * this thread listens to the local stream log driver for log messages
608 * generated by this host, formats them, and queues them to the logger
616 static int klogerrs
= 0;
617 pthread_t mythreadno
;
620 mythreadno
= pthread_self();
623 DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno
);
626 * Process messages, blocking on poll because timeout is set
627 * to INFTIM. When poll returns with a message, call getkmsg
628 * to pull up one message from the log driver and enqueue it
629 * with the sync flag set.
632 sys_init_msg_count
= 0;
638 nfds
= poll(&Pfd
, 1, INFTIM
);
648 if (Pfd
.revents
& POLLIN
) {
654 if (Pfd
.revents
& (POLLNVAL
|POLLHUP
|POLLERR
)) {
655 logerror("kernel log driver poll error");
656 (void) close(Pfd
.fd
);
661 while (Pfd
.fd
== -1 && klogerrs
++ < 10) {
662 Pfd
.fd
= openklog(LogName
, O_RDONLY
);
664 if (klogerrs
>= 10) {
665 logerror("can't reopen kernel log device - fatal");
674 * Pull up one message from log driver.
681 struct strbuf ctl
, dat
;
686 char tmpbuf
[MAXLINE
+1];
687 pthread_t mythreadno
;
690 mythreadno
= pthread_self();
693 dat
.maxlen
= MAXLINE
;
695 ctl
.maxlen
= sizeof (struct log_ctl
);
696 ctl
.buf
= (caddr_t
)&hdr
;
698 while ((i
= getmsg(Pfd
.fd
, &ctl
, &dat
, &flags
)) == MOREDATA
) {
699 lastline
= &dat
.buf
[dat
.len
];
702 DPRINT2(5, "getkmsg:(%u): getmsg: dat.len = %d\n",
703 mythreadno
, dat
.len
);
704 buflen
= strlen(buf
);
705 len
= findnl_bkwd(buf
, buflen
);
707 (void) memcpy(tmpbuf
, buf
, len
);
711 * Format sys will enqueue the log message.
712 * Set the sync flag if timeout != 0, which
713 * means that we're done handling all the
714 * initial messages ready during startup.
717 formatsys(&hdr
, tmpbuf
, 0);
718 sys_init_msg_count
++;
720 formatsys(&hdr
, tmpbuf
, 1);
725 /* If anything remains in buf */
728 if (buf
[len
] == '\n') {
734 * Move the remaining bytes to
735 * the beginnning of buf.
738 remlen
= buflen
- len
;
739 (void) memcpy(buf
, &buf
[len
], remlen
);
740 dat
.maxlen
= MAXLINE
- remlen
;
741 dat
.buf
= &buf
[remlen
];
743 dat
.maxlen
= MAXLINE
;
748 if (i
== 0 && dat
.len
> 0) {
749 dat
.buf
[dat
.len
] = '\0';
751 * Format sys will enqueue the log message.
752 * Set the sync flag if timeout != 0, which
753 * means that we're done handling all the
754 * initial messages ready during startup.
756 DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n",
757 mythreadno
, dat
.maxlen
);
758 DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n",
759 mythreadno
, dat
.len
);
760 DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n",
761 mythreadno
, strlen(dat
.buf
));
762 DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n",
763 mythreadno
, dat
.buf
);
764 DPRINT2(5, "getkmsg(%u): buf len = %d\n",
765 mythreadno
, strlen(buf
));
767 formatsys(&hdr
, buf
, 0);
768 sys_init_msg_count
++;
770 formatsys(&hdr
, buf
, 1);
773 } else if (i
< 0 && errno
!= EINTR
) {
774 if (!shutting_down
) {
775 logerror("kernel log driver read error");
777 (void) close(Pfd
.fd
);
783 * this thread polls all the network interfaces for syslog messages
784 * forwarded to us, tags them with the hostname they are received
785 * from, and queues them to the logger thread.
793 struct t_unitdata
*udp
;
794 struct t_uderr
*errp
;
799 pthread_t mythreadno
;
802 mythreadno
= pthread_self();
805 DPRINT1(1, "net_poll(%u): net_thread started\n", mythreadno
);
807 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
))
812 nfds
= poll(Nfd
, Ninputs
, -1);
821 for (i
= 0; nfds
> 0 && i
< Ninputs
; i
++) {
822 if ((Nfd
[i
].revents
& POLLIN
) == 0) {
827 (POLLNVAL
|POLLHUP
|POLLERR
)) {
828 logerror("POLLNVAL|POLLHUP|POLLERR");
829 (void) t_close(Nfd
[i
].fd
);
837 udp
->udata
.buf
= buf
;
838 udp
->udata
.maxlen
= MAXLINE
;
841 if (t_rcvudata(Nfd
[i
].fd
, udp
, &flags
) < 0) {
843 if (t_errno
== TLOOK
) {
844 if (t_rcvuderr(Nfd
[i
].fd
, errp
) < 0) {
845 if (!shutting_down
) {
846 logerror("t_rcvuderr");
848 (void) t_close(Nfd
[i
].fd
);
852 if (!shutting_down
) {
853 logerror("t_rcvudata");
855 (void) t_close(Nfd
[i
].fd
);
866 if (udp
->udata
.len
== 0) {
869 if (udp
->addr
.len
> 0) {
870 uap
= taddr2uaddr(&Ncf
[i
],
873 DPRINT2(1, "net_poll(%u):"
874 " received empty packet"
875 " from %s\n", mythreadno
,
876 uap
? uap
: "<unknown>");
879 continue; /* No data */
881 if (udp
->addr
.len
== 0) {
883 * The previous message was larger than
884 * MAXLINE, and T_MORE should have been set.
885 * Further data needs to be discarded as
886 * we've already received MAXLINE.
888 DPRINT1(1, "net_poll(%u): discarding packet "
889 "exceeds max line size\n", mythreadno
);
895 if ((mp
= new_msg()) == NULL
) {
896 MALLOC_FAIL("dropping message from "
901 buf
[udp
->udata
.len
] = '\0';
902 formatnet(&udp
->udata
, mp
);
905 uap
= taddr2uaddr(&Ncf
[i
], &udp
->addr
);
906 DPRINT2(1, "net_poll(%u): received message"
907 " from %s\n", mythreadno
,
908 uap
? uap
: "<unknown>");
911 if ((hinfo
= malloc(sizeof (*hinfo
))) == NULL
||
913 malloc(udp
->addr
.len
)) == NULL
) {
914 MALLOC_FAIL("dropping message from "
923 hinfo
->ncp
= &Ncf
[i
];
924 hinfo
->addr
.len
= udp
->addr
.len
;
925 (void) memcpy(hinfo
->addr
.buf
, udp
->addr
.buf
,
928 if (dataq_enqueue(&hnlq
, (void *)mp
) == -1) {
929 MALLOC_FAIL("dropping message from "
932 free(hinfo
->addr
.buf
);
936 DPRINT3(5, "net_poll(%u): enqueued msg %p "
937 "on queue %p\n", mythreadno
, (void *)mp
,
948 (void) fprintf(stderr
,
949 "usage: syslogd [-d] [-t|-T] [-mmarkinterval] [-ppath]"
962 * generate a log message internally. The original version of syslogd
963 * simply called logmsg directly, but because everything is now based
964 * on message passing, we need an internal way to generate and queue
965 * log messages from within syslogd itself.
968 logmymsg(int pri
, char *msg
, int flags
, int pending
)
971 pthread_t mythreadno
;
975 mythreadno
= pthread_self();
978 if ((mp
= new_msg()) == NULL
) {
982 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
))
984 mp
->hlp
= &LocalHostName
;
985 (void) strlcpy(mp
->msg
, msg
, MAXLINE
+1);
987 (void) time(&mp
->ts
);
989 qptr
= pending
? &tmpq
: &inputq
;
990 if (dataq_enqueue(qptr
, (void *)mp
) == -1) {
995 DPRINT3(5, "logmymsg(%u): enqueued msg %p on queue %p\n",
996 mythreadno
, (void *)mp
, (void *)qptr
);
997 DPRINT2(5, "logmymsg(%u): Message content: %s\n", mythreadno
, msg
);
1002 * Generate an internal shutdown message
1007 pthread_t mythreadno
;
1011 mythreadno
= pthread_self();
1014 if ((mp
= new_msg()) == NULL
) {
1018 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
));
1019 mp
->flags
= SHUTDOWN
;
1020 mp
->hlp
= &LocalHostName
;
1022 if (dataq_enqueue(&inputq
, (void *)mp
) == -1) {
1027 DPRINT3(5, "shutdown_msg(%u): enqueued msg %p on queue %p\n",
1028 mythreadno
, (void *)mp
, (void *)&inputq
);
1033 * Generate an internal flush message
1039 pthread_t mythreadno
;
1042 mythreadno
= pthread_self();
1045 if ((mp
= new_msg()) == NULL
) {
1046 MALLOC_FAIL("dropping flush msg");
1050 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
));
1051 mp
->flags
= FLUSHMSG
| flags
;
1052 mp
->hlp
= &LocalHostName
;
1054 if (dataq_enqueue(&inputq
, (void *)mp
) == -1) {
1056 MALLOC_FAIL("dropping flush msg");
1060 DPRINT4(5, "flush_msg(%u): enqueued msg %p on queue %p, flags "
1061 "0x%x\n", mythreadno
, (void *)mp
, (void *)&inputq
, flags
);
1065 * Do some processing on messages received from the net
1068 formatnet(struct netbuf
*nbp
, log_message_t
*mp
)
1072 pthread_t mythreadno
;
1075 mythreadno
= pthread_self();
1078 DPRINT2(5, "formatnet(%u): called for msg %p\n", mythreadno
,
1081 mp
->flags
= NETWORK
;
1082 (void) time(&mp
->ts
);
1084 /* test for special codes */
1087 DPRINT2(9, "formatnet(%u): Message content:\n>%s<\n", mythreadno
,
1089 if (*p
== '<' && isdigit(*(p
+1))) {
1091 while (isdigit(*++p
))
1092 pri
= 10 * pri
+ (*p
- '0');
1095 if (pri
<= 0 || pri
>= (LOG_NFACILITIES
<< 3))
1100 (void) strlcpy(mp
->msg
, p
, MAXLINE
+1);
1104 * Do some processing on messages generated by this host
1105 * and then enqueue the log message.
1108 formatsys(struct log_ctl
*lp
, char *msg
, int sync
)
1111 char line
[MAXLINE
+ 1];
1115 pthread_t mythreadno
;
1118 mythreadno
= pthread_self();
1121 DPRINT3(3, "formatsys(%u): log_ctl.mid = %d, log_ctl.sid = %d\n",
1122 mythreadno
, lp
->mid
, lp
->sid
);
1123 DPRINT2(9, "formatsys(%u): Message Content:\n>%s<\n", mythreadno
,
1126 /* msglen includes the null termination */
1127 msglen
= strlen(msg
) + 1;
1129 for (p
= msg
; *p
!= '\0'; ) {
1134 * Allocate a log_message_t structure.
1135 * We should do it here since a single message (msg)
1136 * could be composed of many lines.
1138 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
));
1140 if ((mp
= new_msg()) == NULL
) {
1141 MALLOC_FAIL("dropping message");
1143 * Should bail out from the loop.
1148 mp
->flags
&= ~NETWORK
;
1149 mp
->hlp
= &LocalHostName
;
1151 if (lp
->flags
& SL_LOGONLY
)
1152 mp
->flags
|= IGN_CONS
;
1153 if (lp
->flags
& SL_CONSONLY
)
1154 mp
->flags
|= IGN_FILE
;
1156 /* extract facility */
1157 if ((lp
->pri
& LOG_FACMASK
) == LOG_KERN
) {
1158 (void) sprintf(line
, "%.15s ",
1159 ctime_r(&mp
->ts
, cbuf
) + 4);
1161 (void) sprintf(line
, "");
1164 linelen
= strlen(line
);
1167 DPRINT2(5, "formatsys(%u): msglen = %d\n", mythreadno
, msglen
);
1168 len
= copynl_frwd(q
, MAXLINE
+ 1 - linelen
, p
, msglen
);
1169 DPRINT2(5, "formatsys(%u): len (copynl_frwd) = %d\n",
1180 if (sync
&& ((lp
->pri
& LOG_FACMASK
) == LOG_KERN
))
1181 mp
->flags
|= SYNC_FILE
; /* fsync file after write */
1184 (void) strlcpy(mp
->msg
, line
, MAXLINE
+1);
1187 if (dataq_enqueue(&inputq
, (void *)mp
) == -1) {
1189 MALLOC_FAIL("dropping message");
1193 DPRINT3(5, "formatsys(%u): sys_thread enqueued msg "
1194 "%p on queue %p\n", mythreadno
, (void *)mp
,
1202 * Log a message to the appropriate log files, users, etc. based on
1210 int fac
, prilev
, flags
, refcnt
;
1211 int fake_shutdown
, skip_shutdown
;
1212 log_message_t
*mp
, *save_mp
;
1213 pthread_t mythreadno
;
1216 mythreadno
= pthread_self();
1219 DPRINT1(1, "logmsg(%u): msg dispatcher started\n", mythreadno
);
1221 fake_shutdown
= skip_shutdown
= 0;
1226 * If we have set aside a message in order to fake a
1227 * SHUTDOWN, use that message before picking from the
1233 (void) dataq_dequeue(&inputq
, (void **)&mp
, 0);
1235 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp
))
1236 DPRINT3(5, "logmsg(%u): msg dispatcher dequeued %p from "
1237 "queue %p\n", mythreadno
, (void *)mp
,
1241 * In most cases, if the message traffic is low, logmsg() wakes
1242 * up when it receives the SHUTDOWN msg, and will sleep until
1243 * HUP process is complete. However, if the inputq is too
1244 * long, logmsg() may not receive SHUTDOWN before reconfigure()
1245 * releases the logger fds, filed and logit threads. That, in
1246 * turn, will cause logmsg to refer to invalid fileds.
1248 * logmsg() needs to respond to the SHUTDOWN message within
1249 * LOOP_INTERVAL seconds when reconfigure() enqueues it. It
1250 * does so in most cases. When it does not respond in time,
1251 * logmsg() needs to be in suspended state immediately, since
1252 * filed may have been invalidated. reconfigure() will set the
1253 * HUP_SUSP_LOGMSG_REQD bit in hup_state and wait another
1254 * LOOP_INTERVAL seconds before proceeding.
1256 * When HUP_SUSP_LOGMSG_REQD is set, we will create a fake
1257 * SHUTDOWN message, and dispatch it to the various logit
1258 * threads, and logmsg() itself will suspend. In order to
1259 * ignore the real SHUTDOWN which will arrive later, we keep a
1260 * counter (skip_shutdown) and decrement it when the SHUTDOWN
1263 if ((hup_state
& HUP_SUSP_LOGMSG_REQD
) &&
1264 (mp
->flags
& SHUTDOWN
) == 0) {
1265 DPRINT1(3, "logmsg(%u): suspend request\n",
1270 /* create a fake SHUTDOWN msg */
1271 if ((mp
= new_msg()) == NULL
) {
1272 MALLOC_FAIL("dropping message");
1273 if (mp
->flags
& SHUTDOWN
) {
1274 (void) logerror_to_console(1,
1275 "unable to shutdown "
1280 mp
->flags
= SHUTDOWN
;
1281 mp
->hlp
= &LocalHostName
;
1284 DPRINT2(3, "logmsg(%u): pending SHUTDOWN %d\n",
1285 mythreadno
, skip_shutdown
);
1289 * is it a shutdown or flush message ?
1291 if ((mp
->flags
& SHUTDOWN
) || (mp
->flags
& FLUSHMSG
)) {
1292 (void) pthread_mutex_lock(&mp
->msg_mutex
);
1294 if ((mp
->flags
& SHUTDOWN
) &&
1295 !fake_shutdown
&& skip_shutdown
> 0) {
1297 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1299 DPRINT2(3, "logmsg(%u): released late "
1300 "arrived SHUTDOWN. pending %d\n",
1301 mythreadno
, skip_shutdown
);
1305 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
1306 (void) pthread_mutex_lock(&f
->filed_mutex
);
1308 if (f
->f_type
== F_UNUSED
) {
1309 (void) pthread_mutex_unlock(
1317 if (dataq_enqueue(&f
->f_queue
,
1318 (void *)mp
) == -1) {
1321 (void) pthread_mutex_unlock(
1323 MALLOC_FAIL("dropping message");
1325 if (mp
->flags
& SHUTDOWN
) {
1326 (void) logerror_to_console(1,
1327 "unable to shutdown "
1333 DPRINT3(5, "logmsg(%u): enqueued msg %p "
1334 "on queue %p\n", mythreadno
,
1335 (void *)mp
, (void *)&f
->f_queue
);
1336 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1340 * flags value needs to be saved because mp may
1341 * have been freed before SHUTDOWN test below.
1344 refcnt
= mp
->refcnt
;
1346 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1350 if (flags
& SHUTDOWN
) {
1351 (void) pthread_mutex_lock(&hup_lock
);
1352 while (hup_state
!= HUP_COMPLETED
) {
1353 hup_state
|= HUP_LOGMSG_SUSPENDED
;
1354 (void) pthread_cond_wait(&hup_done
,
1356 hup_state
&= ~HUP_LOGMSG_SUSPENDED
;
1358 hup_state
= HUP_ACCEPTABLE
;
1359 (void) pthread_mutex_unlock(&hup_lock
);
1366 * Check to see if msg looks non-standard.
1368 if ((int)strlen(mp
->msg
) < 16 || mp
->msg
[3] != ' ' ||
1369 mp
->msg
[6] != ' ' || mp
->msg
[9] != ':' ||
1370 mp
->msg
[12] != ':' || mp
->msg
[15] != ' ')
1371 mp
->flags
|= ADDDATE
;
1373 /* extract facility and priority level */
1374 fac
= (mp
->pri
& LOG_FACMASK
) >> 3;
1375 if (mp
->flags
& MARK
)
1376 fac
= LOG_NFACILITIES
;
1377 prilev
= mp
->pri
& LOG_PRIMASK
;
1379 DPRINT3(3, "logmsg(%u): fac = %d, pri = %d\n",
1380 mythreadno
, fac
, prilev
);
1383 * Because different devices log at different speeds,
1384 * it's important to hold the mutex for the current
1385 * message until it's been enqueued to all log files,
1386 * so the reference count is accurate before any
1387 * of the log threads can decrement it.
1389 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mp
))
1390 _NOTE(COMPETING_THREADS_NOW
)
1391 (void) pthread_mutex_lock(&mp
->msg_mutex
);
1393 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
1394 /* skip messages that are incorrect priority */
1395 if (f
->f_pmask
[fac
] < (unsigned)prilev
||
1396 f
->f_pmask
[fac
] == NOPRI
)
1398 if (f
->f_queue_count
> Q_HIGHWATER_MARK
) {
1399 DPRINT4(5, "logmsg(%u): Dropping message "
1400 "%p on file %p, count = %d\n",
1401 mythreadno
, (void *)mp
, (void *)f
,
1407 * Need to grab filed_mutex before testing the f_type.
1408 * Otherwise logit() may set F_UNUSED after the test
1409 * below, and start pulling out the pending messages.
1412 (void) pthread_mutex_lock(&f
->filed_mutex
);
1414 if (f
->f_type
== F_UNUSED
||
1415 (f
->f_type
== F_FILE
&& (mp
->flags
& IGN_FILE
)) ||
1416 (f
->f_type
== F_CONSOLE
&&
1417 (mp
->flags
& IGN_CONS
))) {
1418 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1425 if (dataq_enqueue(&f
->f_queue
, (void *)mp
) == -1) {
1428 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1429 MALLOC_FAIL("dropping message");
1433 DPRINT3(5, "logmsg(%u): enqueued msg %p on queue "
1434 "%p\n", mythreadno
, (void *)mp
,
1435 (void *)&f
->f_queue
);
1436 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1438 refcnt
= mp
->refcnt
;
1439 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1448 * function to actually write the log message to the selected file.
1449 * each file has a logger thread that runs this routine. The function
1450 * is called with a pointer to its file structure.
1455 struct filed
*f
= ap
;
1457 int forwardingloop
= 0;
1458 const char *errmsg
= "logit(%u): %s to %s forwarding loop detected\n";
1459 int i
, currofst
, prevofst
, refcnt
;
1464 DPRINT4(5, "logit(%u): logger started for \"%s\" (queue %p, filed "
1465 "%p)\n", f
->f_thread
, f
->f_un
.f_fname
, (void *)&f
->f_queue
,
1467 _NOTE(COMPETING_THREADS_NOW
);
1469 while (f
->f_type
!= F_UNUSED
) {
1470 (void) dataq_dequeue(&f
->f_queue
, (void **)&mp
, 0);
1471 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1472 "%p\n", f
->f_thread
, (void *)mp
, (void *)&f
->f_queue
);
1473 (void) pthread_mutex_lock(&f
->filed_mutex
);
1474 assert(f
->f_queue_count
> 0);
1476 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1477 assert(mp
->refcnt
> 0);
1480 * is it a shutdown message ?
1482 if (mp
->flags
& SHUTDOWN
) {
1483 (void) pthread_mutex_lock(&mp
->msg_mutex
);
1484 refcnt
= --mp
->refcnt
;
1485 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1492 * Is it a logsync message?
1494 if ((mp
->flags
& (FLUSHMSG
| LOGSYNC
)) ==
1495 (FLUSHMSG
| LOGSYNC
)) {
1496 if (f
->f_type
!= F_FILE
)
1497 goto out
; /* nothing to do */
1498 (void) close(f
->f_file
);
1499 f
->f_file
= open64(f
->f_un
.f_fname
,
1500 O_WRONLY
|O_APPEND
|O_NOCTTY
);
1501 if (f
->f_file
< 0) {
1502 f
->f_type
= F_UNUSED
;
1503 logerror(f
->f_un
.f_fname
);
1510 * If the message flags include both flush and sync,
1511 * then just sync the file out to disk if appropriate.
1513 if ((mp
->flags
& (FLUSHMSG
| SYNC_FILE
)) ==
1514 (FLUSHMSG
| SYNC_FILE
)) {
1515 if (f
->f_type
== F_FILE
) {
1516 DPRINT2(5, "logit(%u): got FLUSH|SYNC "
1517 "for filed %p\n", f
->f_thread
,
1519 (void) fsync(f
->f_file
);
1525 * Otherwise if it's a standard flush message, write
1526 * out any saved messages to the file.
1528 if ((mp
->flags
& FLUSHMSG
) && (f
->f_prevcount
> 0)) {
1534 (void) strlcpy(f
->f_current
.msg
, mp
->msg
, MAXLINE
+1);
1535 (void) strlcpy(f
->f_current
.host
, mp
->hlp
->hl_hosts
[0],
1537 f
->f_current
.pri
= mp
->pri
;
1538 f
->f_current
.flags
= mp
->flags
;
1539 f
->f_current
.time
= mp
->ts
;
1540 f
->f_msgflag
&= ~CURRENT_VALID
;
1543 prevofst
= (f
->f_prevmsg
.flags
& ADDDATE
) ? 0 : 16;
1544 currofst
= (f
->f_current
.flags
& ADDDATE
) ? 0 : 16;
1546 if (f
->f_type
== F_FORW
) {
1548 * Should not forward MARK messages, as they are
1549 * not defined outside of the current system.
1552 if (mp
->flags
& MARK
) {
1553 DPRINT1(1, "logit(%u): cannot forward "
1554 "Mark\n", f
->f_thread
);
1559 * can not forward message if we do
1560 * not have a host to forward to
1562 if (hlp
== (host_list_t
*)NULL
)
1565 * a forwarding loop is created on machines
1566 * with multiple interfaces because the
1567 * network address of the sender is different
1568 * to the receiver even though it is the
1569 * same machine. Instead, if the
1570 * hostname the source and target are
1571 * the same the message if thrown away
1574 for (i
= 0; i
< hlp
->hl_cnt
; i
++) {
1575 if (strcmp(hlp
->hl_hosts
[i
],
1576 f
->f_un
.f_forw
.f_hname
) == 0) {
1577 DPRINT3(1, errmsg
, f
->f_thread
,
1578 f
->f_un
.f_forw
.f_hname
,
1585 if (forwardingloop
== 1) {
1586 f
->f_stat
.cantfwd
++;
1591 f
->f_msgflag
|= CURRENT_VALID
;
1593 /* check for dup message */
1594 if (f
->f_type
!= F_FORW
&&
1595 (f
->f_msgflag
& OLD_VALID
) &&
1596 prevofst
== currofst
&&
1597 (strcmp(f
->f_prevmsg
.msg
+ prevofst
,
1598 f
->f_current
.msg
+ currofst
) == 0) &&
1599 (strcmp(f
->f_prevmsg
.host
,
1600 f
->f_current
.host
) == 0)) {
1602 DPRINT2(2, "logit(%u): msg is dup - %p\n",
1603 f
->f_thread
, (void *)mp
);
1604 if (currofst
== 16) {
1605 (void) strncpy(f
->f_prevmsg
.msg
,
1606 f
->f_current
.msg
, 15); /* update time */
1611 f
->f_msgflag
&= ~CURRENT_VALID
;
1613 /* new: mark or prior dups exist */
1614 if (f
->f_current
.flags
& MARK
|| f
->f_prevcount
> 0) {
1615 if (f
->f_prevcount
> 0 && f
->f_type
!= F_FORW
) {
1617 if (f
->f_msgflag
& OLD_VALID
) {
1621 if (f
->f_msgflag
& CURRENT_VALID
)
1622 writemsg(CURRENT
, f
);
1623 if (!(mp
->flags
& NOCOPY
))
1625 if (f
->f_current
.flags
& MARK
) {
1626 DPRINT2(2, "logit(%u): msg is "
1627 "mark - %p)\n", f
->f_thread
,
1629 f
->f_msgflag
&= ~OLD_VALID
;
1631 DPRINT2(2, "logit(%u): saving "
1632 "message - %p\n", f
->f_thread
,
1636 } else { /* new message */
1637 DPRINT2(2, "logit(%u): msg is new "
1638 "- %p\n", f
->f_thread
, (void *)mp
);
1639 writemsg(CURRENT
, f
);
1640 if (!(mp
->flags
& NOCOPY
))
1646 * if message refcnt goes to zero after we decrement
1647 * it here, we are the last consumer of the message,
1648 * and we should free it. We need to hold the lock
1649 * between decrementing the count and checking for
1650 * zero so another thread doesn't beat us to it.
1653 (void) pthread_mutex_lock(&mp
->msg_mutex
);
1654 refcnt
= --mp
->refcnt
;
1655 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1659 /* register our exit */
1662 * Pull out all pending messages, if they exist.
1665 (void) pthread_mutex_lock(&f
->filed_mutex
);
1667 while (f
->f_queue_count
> 0) {
1668 (void) dataq_dequeue(&f
->f_queue
, (void **)&mp
, 0);
1669 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1671 f
->f_thread
, (void *)mp
, (void *)&f
->f_queue
);
1672 (void) pthread_mutex_lock(&mp
->msg_mutex
);
1673 refcnt
= --mp
->refcnt
;
1674 (void) pthread_mutex_unlock(&mp
->msg_mutex
);
1680 (void) pthread_mutex_unlock(&f
->filed_mutex
);
1682 if (f
->f_type
!= F_USERS
&& f
->f_type
!= F_WALL
&&
1683 f
->f_type
!= F_UNUSED
) {
1684 if (f
->f_type
== F_FORW
)
1685 (void) t_close(f
->f_file
);
1687 (void) close(f
->f_file
);
1691 * Since f_type may have been changed before this point, we need
1692 * to test orig_type.
1694 if (f
->f_orig_type
== F_FORW
) {
1695 free(f
->f_un
.f_forw
.f_addr
.buf
);
1698 f
->f_type
= F_UNUSED
;
1699 (void) pthread_mutex_lock(&cft
);
1701 (void) pthread_mutex_unlock(&cft
);
1702 DPRINT1(5, "logit(%u): logging thread exited\n", f
->f_thread
);
1707 * change the previous message to a flush message, stating how
1708 * many repeats occurred since the last flush
1711 set_flush_msg(struct filed
*f
)
1714 int prevofst
= (f
->f_prevmsg
.flags
& ADDDATE
) ? 0 : 16;
1716 if (f
->f_prevcount
== 1)
1717 (void) strncpy(tbuf
, "time", sizeof (tbuf
));
1719 (void) strncpy(tbuf
, "times", sizeof (tbuf
));
1721 (void) snprintf(f
->f_prevmsg
.msg
+prevofst
,
1722 sizeof (f
->f_prevmsg
.msg
) - prevofst
,
1723 "last message repeated %d %s", f
->f_prevcount
, tbuf
);
1725 f
->f_msgflag
|= OLD_VALID
;
1730 * the actual writing of the message is broken into a separate function
1731 * because each file has a current and saved message associated with
1732 * it (for duplicate message detection). It is necessary to be able
1733 * to write either the saved message or the current message.
1736 writemsg(int selection
, struct filed
*f
)
1743 struct t_unitdata ud
;
1744 char *eomp
, *eomp2
, *from
, *text
, *msg
;
1745 char line
[MAXLINE
*2];
1746 char head
[MAXLINE
+1];
1747 char tmpbuf
[MAXLINE
+1];
1750 char *msgid_start
, *msgid_end
;
1751 pthread_t mythreadno
;
1752 size_t hlen
, filter_len
;
1755 mythreadno
= pthread_self();
1758 switch (selection
) {
1760 case CURRENT
: /* print current message */
1761 msg
= f
->f_current
.msg
;
1762 from
= f
->f_current
.host
;
1763 pri
= f
->f_current
.pri
;
1764 flags
= f
->f_current
.flags
;
1765 ts
= f
->f_current
.time
;
1766 f
->f_msgflag
&= ~CURRENT_VALID
;
1768 case SAVED
: /* print saved message */
1769 msg
= f
->f_prevmsg
.msg
;
1770 from
= f
->f_prevmsg
.host
;
1771 pri
= f
->f_prevmsg
.pri
;
1772 flags
= f
->f_prevmsg
.flags
;
1773 ts
= f
->f_prevmsg
.time
;
1774 f
->f_msgflag
&= ~OLD_VALID
;
1783 if (flags
& ADDDATE
)
1784 (void) strncpy(cp
, ctime_r(&ts
, cbuf
) + 4, 15);
1786 (void) strncpy(cp
, msg
, 15);
1789 (void) strcat(cp
, " ");
1790 (void) strcat(cp
, from
);
1791 (void) strcat(cp
, " ");
1792 text
= cp
+ strlen(cp
);
1794 if (flags
& ADDDATE
)
1795 (void) strcat(cp
, msg
);
1797 (void) strcat(cp
, msg
+16);
1798 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno
, text
);
1802 switch (f
->f_type
) {
1804 DPRINT1(1, "writemsg(%u): UNUSED\n", mythreadno
);
1807 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1808 mythreadno
, msg
, TypeNames
[f
->f_type
],
1809 f
->f_un
.f_forw
.f_hname
);
1811 hlen
= snprintf(head
, sizeof (head
),
1812 "<%d>%.15s ", pri
, cp
);
1814 DPRINT2(5, "writemsg(%u): head = \"%s\"\n", mythreadno
, head
);
1815 DPRINT2(5, "writemsg(%u): hlen = %d\n", mythreadno
, hlen
);
1820 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno
, text
);
1821 DPRINT2(5, "writemsg(%u): strlen(text) = %d\n", mythreadno
, l
);
1823 (void) strncpy(tmpbuf
, head
, hlen
);
1828 len
= copy_frwd(tmpbuf
+ hlen
, sizeof (tmpbuf
) - hlen
,
1831 DPRINT2(5, "writemsg(%u): tmpbuf = \"%s\"\n",
1832 mythreadno
, tmpbuf
);
1833 DPRINT2(5, "writemsg(%u): len = %d\n", mythreadno
,
1835 DPRINT2(5, "writemsg(%u): strlen(tmpbuf) = %d\n",
1836 mythreadno
, strlen(tmpbuf
));
1840 ud
.udata
.buf
= tmpbuf
;
1841 ud
.udata
.len
= len
+ hlen
;
1842 ud
.addr
.maxlen
= f
->f_un
.f_forw
.f_addr
.maxlen
;
1843 ud
.addr
.buf
= f
->f_un
.f_forw
.f_addr
.buf
;
1844 ud
.addr
.len
= f
->f_un
.f_forw
.f_addr
.len
;
1845 if (t_sndudata(f
->f_file
, &ud
) < 0) {
1846 if ((hup_state
& HUP_INPROGRESS
) &&
1847 f
->f_type
== F_UNUSED
) {
1850 (void) t_close(f
->f_file
);
1851 f
->f_type
= F_UNUSED
;
1852 logerror("t_sndudata");
1855 * Since it has already failed, it's not worth
1856 * continuing output from the middle of
1870 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1871 mythreadno
, msg
, TypeNames
[f
->f_type
],
1872 ((f
->f_type
== F_USERS
) || (f
->f_type
== F_WALL
)) ?
1873 "" : f
->f_un
.f_fname
);
1875 * filter the string in preparation for writing it
1876 * save the original for possible forwarding.
1877 * In case every byte in cp is a control character,
1878 * allocates large enough buffer for filtered.
1881 filter_len
= strlen(cp
) * 4 + 1;
1882 filtered
= (char *)malloc(filter_len
);
1884 MALLOC_FAIL("dropping message");
1885 /* seems we can just return */
1888 DPRINT3(5, "writemsg(%u): "
1889 "filtered allocated (%p: %d bytes)\n",
1890 mythreadno
, (void *)filtered
, filter_len
);
1891 /* -3 : we may add "\r\n" to ecomp(filtered) later */
1892 filter_string(cp
, filtered
, filter_len
- 3);
1894 DPRINT2(5, "writemsg(%u): strlen(filtered) = %d\n",
1895 mythreadno
, strlen(filtered
));
1897 * If we're writing to the console, strip out the message ID
1898 * to reduce visual clutter.
1900 if ((msgid_start
= strstr(filtered
, "[ID ")) != NULL
&&
1901 (msgid_end
= strstr(msgid_start
, "] ")) != NULL
&&
1902 f
->f_type
== F_CONSOLE
)
1903 (void) strcpy(msgid_start
, msgid_end
+ 2);
1905 eomp
= filtered
+ strlen(filtered
);
1907 if ((f
->f_type
== F_USERS
) || (f
->f_type
== F_WALL
)) {
1909 (void) strcat(eomp
, "\r\n"); /*lint !e669*/
1911 * Since wallmsg messes with utmpx we need
1912 * to guarantee single threadedness...
1914 (void) pthread_mutex_lock(&wmp
);
1915 wallmsg(f
, from
, filtered
);
1916 (void) pthread_mutex_unlock(&wmp
);
1919 * The contents of filtered have been copied
1920 * out to the struct walldev. We should free it here.
1925 /* exiting the switch */
1927 } else if (f
->f_type
!= F_FILE
) {
1929 (void) strncpy(eomp
, "\r\n", 3); /*lint !e669*/
1931 if ((eomp2
= strchr(filtered
, '\r')) != NULL
) {
1932 (void) strncpy(eomp2
, "\n", 2);
1935 (void) strncpy(eomp
, "\n", 2); /*lint !e669*/
1938 if (write(f
->f_file
, filtered
, strlen(filtered
)) < 0) {
1941 if ((hup_state
& HUP_INPROGRESS
) &&
1942 f
->f_type
== F_UNUSED
) {
1946 (void) close(f
->f_file
);
1948 * Check for EBADF on TTY's due
1951 if (e
== EBADF
&& f
->f_type
!= F_FILE
) {
1952 f
->f_file
= open(f
->f_un
.f_fname
,
1953 O_WRONLY
|O_APPEND
|O_NOCTTY
);
1954 if (f
->f_file
< 0) {
1955 f
->f_type
= F_UNUSED
;
1956 logerror(f
->f_un
.f_fname
);
1961 f
->f_type
= F_UNUSED
;
1964 logerror(f
->f_un
.f_fname
);
1966 } else if (flags
& SYNC_FILE
)
1967 if (((pri
& LOG_FACMASK
) >> 3) == LOG_KERN
)
1968 (void) fsync(f
->f_file
);
1970 DPRINT2(5, "writemsg(%u): freeing filtered (%p)\n",
1971 mythreadno
, (void *)filtered
);
1979 * WALLMSG -- Write a message to the world at large
1981 * Write the specified message to either the entire
1982 * world, or a list of approved users.
1985 wallmsg(struct filed
*f
, char *from
, char *msg
)
1992 char line
[512], dev
[100];
1994 struct stat statbuf
;
1997 pthread_t mythreadno
;
2000 mythreadno
= pthread_self();
2003 if (access(UTMPX_FILE
, R_OK
) != 0 || stat(UTMPX_FILE
, &statbuf
) != 0) {
2004 logerror(UTMPX_FILE
);
2006 } else if (statbuf
.st_uid
!= 0 || (statbuf
.st_mode
& 07777) != 0644) {
2007 (void) snprintf(line
, sizeof (line
), "%s %s", UTMPX_FILE
,
2008 "not owned by root or not mode 644.\n"
2009 "This file must be owned by root "
2010 "and not writable by\n"
2011 "anyone other than root. This alert is being "
2012 "dropped because of\n"
2018 if (f
->f_type
== F_WALL
) {
2020 len
= snprintf(line
, sizeof (line
),
2021 "\r\n\7Message from syslogd@%s "
2022 "at %.24s ...\r\n", from
, ctime_r(&now
, cbuf
));
2023 len
+= strlen(msg
+ 16);
2024 buf
= (char *)malloc(len
+ 1);
2026 MALLOC_FAIL("dropping message");
2029 DPRINT3(5, "wallmsg(%u): buf allocated (%p: %d bytes)\n",
2030 mythreadno
, (void *)buf
, len
+ 1);
2031 (void) strcpy(buf
, line
);
2032 (void) strcat(buf
, msg
+ 16);
2033 clen
= copy_frwd(cp
, sizeof (cp
), buf
, len
);
2034 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2036 DPRINT2(5, "wallmsg(%u): freeing buf (%p)\n",
2037 mythreadno
, (void *)buf
);
2040 clen
= copy_frwd(cp
, sizeof (cp
), msg
, strlen(msg
));
2041 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2044 /* scan the user login file */
2046 while ((utxp
= getutxent()) != NULL
) {
2047 /* is this slot used? */
2048 if (utxp
->ut_name
[0] == '\0' ||
2049 utxp
->ut_line
[0] == '\0' ||
2050 utxp
->ut_type
!= USER_PROCESS
)
2052 /* should we send the message to this user? */
2053 if (f
->f_type
== F_USERS
) {
2054 for (i
= 0; i
< MAXUNAMES
; i
++) {
2055 if (!f
->f_un
.f_uname
[i
][0]) {
2059 if (strncmp(f
->f_un
.f_uname
[i
],
2060 utxp
->ut_name
, UNAMESZ
) == 0)
2067 /* compute the device name */
2068 if (utxp
->ut_line
[0] == '/') {
2069 (void) strncpy(dev
, utxp
->ut_line
, UDEVSZ
);
2071 (void) strcpy(dev
, "/dev/");
2072 (void) strncat(dev
, utxp
->ut_line
, UDEVSZ
);
2074 DPRINT2(1, "wallmsg(%u): write to '%s'\n", mythreadno
,
2077 if ((w
= malloc(sizeof (walldev_t
))) != NULL
) {
2079 (void) pthread_attr_init(&w
->thread_attr
);
2080 (void) pthread_attr_setdetachstate(&w
->thread_attr
,
2081 PTHREAD_CREATE_DETACHED
);
2082 (void) strncpy(w
->dev
, dev
, PATH_MAX
);
2083 (void) strncpy(w
->msg
, cp
, MAXLINE
+1);
2084 (void) strncpy(w
->ut_name
, utxp
->ut_name
,
2085 sizeof (w
->ut_name
));
2087 if ((rc
= pthread_create(&w
->thread
, &w
->thread_attr
,
2088 writetodev
, (void *) w
)) != 0) {
2089 DPRINT2(5, "wallmsg(%u): wallmsg thread "
2090 "create failed rc = %d\n",
2096 MALLOC_FAIL("dropping message to user");
2099 /* close the user login file */
2104 * Each time we need to write to a tty device (a potentially expensive
2105 * or long-running operation) this routine gets called as a new
2106 * detached, unbound thread. This allows writes to many devices
2107 * to proceed nearly in parallel, without having to resort to
2108 * asynchronous I/O or forking.
2111 writetodev(void *ap
)
2117 struct passwd pw
, *pwp
;
2118 char pwbuf
[MAXLINE
];
2119 pthread_t mythreadno
;
2122 mythreadno
= pthread_self();
2125 DPRINT1(1, "writetodev(%u): Device writer thread started\n",
2128 len
= strlen(w
->msg
);
2130 ttyf
= open(w
->dev
, O_WRONLY
|O_NOCTTY
|O_NDELAY
);
2132 if (fstat(ttyf
, &statb
) != 0) {
2133 DPRINT2(1, "writetodev(%u): Can't stat '%s'\n",
2134 mythreadno
, w
->dev
);
2136 logerror("Can't stat '%s'", w
->dev
);
2137 } else if (!(statb
.st_mode
& S_IWRITE
)) {
2138 DPRINT2(1, "writetodev(%u): Can't write to "
2139 "'%s'\n", mythreadno
, w
->dev
);
2140 } else if (!isatty(ttyf
)) {
2141 DPRINT2(1, "writetodev(%u): '%s' not a tty\n",
2142 mythreadno
, w
->dev
);
2144 * We might hit dtremote here. Don't generate
2147 } else if (getpwuid_r(statb
.st_uid
, &pw
, pwbuf
,
2148 sizeof (pwbuf
), &pwp
) != 0) {
2149 DPRINT2(1, "writetodev(%u): Can't determine owner "
2150 "of '%s'\n", mythreadno
, w
->dev
);
2152 logerror("Can't determine owner of '%s'", w
->dev
);
2153 } else if (strncmp(pw
.pw_name
, w
->ut_name
, UNAMESZ
) != 0) {
2154 DPRINT2(1, "writetodev(%u): Bad terminal owner '%s'"
2155 "\n", mythreadno
, w
->dev
);
2157 logerror("%s %s owns '%s' %s %.*s",
2158 "Bad terminal owner;", pw
.pw_name
, w
->dev
,
2159 "but utmpx says", UNAMESZ
, w
->ut_name
);
2160 } else if (write(ttyf
, w
->msg
, len
) != len
) {
2161 DPRINT2(1, "writetodev(%u): Write failed to "
2162 "'%s'\n", mythreadno
, w
->dev
);
2164 logerror("Write failed to '%s'", w
->dev
);
2167 DPRINT2(1, "writetodev(%u): write to '%s' succeeded\n",
2168 mythreadno
, w
->dev
);
2172 DPRINT2(1, "writetodev(%u): Can't open '%s'\n",
2173 mythreadno
, w
->dev
);
2176 (void) pthread_attr_destroy(&w
->thread_attr
);
2179 DPRINT1(1, "writetodev(%u): Device writer thread exiting\n",
2188 * Return a printable representation of a host address. If unable to
2189 * look up hostname, format the numeric address for display instead.
2191 * First calls hnc_lookup to see if there is valid cache entry for
2192 * given network address. If it failed, cvthname looks up hostname,
2193 * and push the results into the hostname cache.
2195 static host_list_t
*
2196 cvthname(struct netbuf
*nbp
, struct netconfig
*ncp
, char *failsafe_addr
)
2200 struct nd_hostservlist
*hsp
;
2201 struct nd_hostserv
*hspp
;
2202 pthread_t mythreadno
;
2207 mythreadno
= pthread_self();
2211 uap
= taddr2uaddr(ncp
, nbp
);
2213 DPRINT2(2, "cvthname(%u): looking up hostname for %s\n",
2214 mythreadno
, uap
? uap
: "<unknown>");
2216 if ((h
= hnc_lookup(nbp
, ncp
, &hindex
)) != NULL
) {
2217 DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n",
2218 mythreadno
, (void *)h
, uap
? uap
: "<unknown>",
2222 DPRINT2(2, "cvthname(%u): No cache found for %s\n",
2223 mythreadno
, uap
? uap
: "<unknown>");
2228 if (ncp
->nc_semantics
!= NC_TPI_CLTS
) {
2232 /* memory allocation failure here is fatal */
2233 if ((h
= malloc(sizeof (host_list_t
))) == NULL
) {
2234 MALLOC_FAIL("host name conversion");
2238 if (netdir_getbyaddr(ncp
, &hsp
, nbp
) == 0) {
2239 if (hsp
->h_cnt
<= 0) {
2240 out
: netdir_free((void *)hsp
, ND_HOSTSERVLIST
);
2245 hspp
= hsp
->h_hostservs
;
2246 h
->hl_cnt
= hsp
->h_cnt
;
2247 h
->hl_hosts
= (char **)malloc(sizeof (char *) * (h
->hl_cnt
));
2248 if (h
->hl_hosts
== NULL
) {
2249 MALLOC_FAIL("host name conversion");
2253 DPRINT2(2, "cvthname(%u): Found %d hostnames\n",
2254 mythreadno
, h
->hl_cnt
);
2255 for (i
= 0; i
< h
->hl_cnt
; i
++) {
2256 h
->hl_hosts
[i
] = (char *)
2257 malloc(sizeof (char) * (strlen(hspp
->h_host
) + 1));
2258 if (h
->hl_hosts
[i
] == NULL
) {
2260 for (j
= 0; j
< i
; j
++) {
2261 free(h
->hl_hosts
[j
]);
2264 MALLOC_FAIL("host name conversion");
2267 (void) strcpy(h
->hl_hosts
[i
], hspp
->h_host
);
2270 netdir_free((void *)hsp
, ND_HOSTSERVLIST
);
2271 } else { /* unknown address */
2273 h
->hl_hosts
= (char **)malloc(sizeof (char *));
2274 if (h
->hl_hosts
== NULL
) {
2276 MALLOC_FAIL("host name conversion");
2279 h
->hl_hosts
[0] = (char *)malloc(strlen(failsafe_addr
) + 3);
2280 if (h
->hl_hosts
[0] == NULL
) {
2283 MALLOC_FAIL("host name conversion");
2287 (void) sprintf(h
->hl_hosts
[0], "[%s]", failsafe_addr
);
2288 DPRINT2(1, "cvthname(%u): Hostname lookup failed "
2289 "- using address %s instead\n",
2290 mythreadno
, h
->hl_hosts
[0]);
2294 if (pthread_mutex_init(&h
->hl_mutex
, NULL
) != 0) {
2295 logerror("pthread_mutex_init failed");
2296 /* This host_list won't be shared by the cache. */
2299 hnc_register(nbp
, ncp
, h
, hindex
);
2300 DPRINT3(2, "cvthname(%u): returning %p for %s\n",
2301 mythreadno
, (void *)h
, h
->hl_hosts
[0]);
2306 * Print syslogd errors some place. Need to be careful here, because
2307 * this routine is called at times when we're not initialized and
2308 * ready to log messages...in this case, fall back to using the console.
2311 logerror(const char *type
, ...)
2313 char buf
[MAXLINE
+1];
2314 pthread_t mythreadno
;
2319 mythreadno
= pthread_self();
2323 logerror_format(type
, buf
, ap
);
2325 DPRINT2(1, "logerror(%u): %s\n", mythreadno
, buf
);
2327 (void) pthread_mutex_lock(&logerror_lock
);
2330 if (logerror_to_console(1, buf
) == 0) {
2331 /* has written to the console */
2334 (void) logmymsg(LOG_SYSLOG
|LOG_ERR
, buf
, ADDDATE
|flag
, 1);
2336 if (logmymsg(LOG_SYSLOG
|LOG_ERR
, buf
, ADDDATE
, 0) == -1) {
2337 (void) logerror_to_console(1, buf
);
2340 (void) pthread_mutex_unlock(&logerror_lock
);
2347 logerror_format(const char *type
, char *buf
, va_list ap
)
2349 char tmpbuf
[MAXLINE
+ 1];
2350 pthread_t mythreadno
;
2353 mythreadno
= pthread_self();
2356 (void) vsnprintf(tmpbuf
, MAXLINE
, type
, ap
);
2358 if (t_errno
== 0 || t_errno
== TSYSERR
) {
2362 (void) snprintf(buf
, MAXLINE
, "syslogd: %.*s",
2364 } else if ((errstr
= strerror(errno
)) == NULL
) {
2365 (void) snprintf(buf
, MAXLINE
, "syslogd: %s: error"
2366 " %d", tmpbuf
, errno
);
2368 (void) snprintf(buf
, MAXLINE
, "syslogd: %s: %s",
2372 if (t_errno
> t_nerr
) {
2373 (void) snprintf(buf
, MAXLINE
, "syslogd: %s:"
2374 " t_error %d", tmpbuf
, t_errno
);
2376 (void) snprintf(buf
, MAXLINE
, "syslogd: %s: %s",
2377 tmpbuf
, t_errlist
[t_errno
]);
2381 DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno
, buf
);
2385 logerror_to_console(int nonblock
, const char *buf
)
2388 pthread_t mythreadno
;
2390 char tmpbuf
[MAXLINE
+ 1];
2393 mythreadno
= pthread_self();
2396 DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno
, buf
);
2399 * must use open here instead of fopen, because
2400 * we need the O_NOCTTY behavior - otherwise we
2401 * could hang the console at boot time
2404 modes
= (nonblock
) ?
2405 O_WRONLY
|O_APPEND
|O_NOCTTY
|O_NONBLOCK
:
2406 O_WRONLY
|O_APPEND
|O_NOCTTY
;
2408 if (((cfd
= open(sysmsg
, modes
)) >= 0) ||
2409 ((cfd
= open(ctty
, modes
)) >= 0)) {
2410 (void) snprintf(tmpbuf
, MAXLINE
, "%s\n", buf
);
2411 len
= strlen(tmpbuf
);
2412 if (write(cfd
, tmpbuf
, len
) != len
) {
2420 DPRINT1(1, "logerror_console(%u): can't open console\n",
2427 * copy current message to saved message in filed structure.
2430 copy_msg(struct filed
*f
)
2432 (void) strlcpy(f
->f_prevmsg
.msg
, f
->f_current
.msg
, MAXLINE
+1);
2433 (void) strlcpy(f
->f_prevmsg
.host
, f
->f_current
.host
, SYS_NMLN
);
2434 f
->f_prevmsg
.pri
= f
->f_current
.pri
;
2435 f
->f_prevmsg
.flags
= f
->f_current
.flags
;
2436 f
->f_prevmsg
.time
= f
->f_current
.time
;
2437 f
->f_msgflag
|= OLD_VALID
;
2442 * function to free a host_list_t struct that was allocated
2443 * out of cvthname(). There is a special case where we don't
2444 * free the hostname list in LocalHostName, because that's
2445 * our own addresses, and we just want to have to look it
2446 * up once and save it. Also don't free it if it's
2447 * NullHostName, because that's a special one we use if
2448 * name service lookup fails.
2450 * By having hostname cache, now host_list_t will be shared
2451 * by messages and hostname cache. hl_refcnt is used for
2455 freehl(host_list_t
*h
)
2458 pthread_t mythreadno
;
2461 mythreadno
= pthread_self();
2464 DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno
, (void *)h
);
2466 if (h
== NULL
|| h
== &LocalHostName
|| h
== &NullHostName
) {
2470 (void) pthread_mutex_lock(&h
->hl_mutex
);
2471 refcnt
= --h
->hl_refcnt
;
2472 (void) pthread_mutex_unlock(&h
->hl_mutex
);
2475 DPRINT3(5, "freehl(%u): %p has reference %d\n",
2476 mythreadno
, (void *)h
, refcnt
);
2480 (void) pthread_mutex_destroy(&h
->hl_mutex
);
2482 DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno
, (void *)h
);
2484 for (i
= 0; i
< h
->hl_cnt
; i
++) {
2485 free(h
->hl_hosts
[i
]);
2493 * Create the door file and the pid file in /var/run. If the filesystem
2494 * containing /etc is writable, create symlinks /etc/.syslog_door and
2495 * /etc/syslog.pid to them. On systems that do not support /var/run, create
2496 * /etc/.syslog_door and /etc/syslog.pid directly.
2498 * Note: it is not considered fatal to fail to create the pid file or its
2499 * symlink. Attempts to use them in the usual way will fail, of course, but
2500 * syslogd will function nicely without it (not so for the door file).
2508 char line
[MAXLINE
+1];
2509 pthread_t mythreadno
;
2513 mythreadno
= pthread_self();
2517 * first see if another syslogd is running by trying
2518 * a door call - if it succeeds, there is already
2519 * a syslogd process active
2525 if ((door
= open(DoorFileName
, O_RDONLY
)) >= 0) {
2526 DPRINT2(5, "open_door(%u): %s opened "
2527 "successfully\n", mythreadno
, DoorFileName
);
2529 if (door_info(door
, &info
) >= 0) {
2530 DPRINT2(5, "open_door(%u): "
2531 "door_info:info.di_target = %ld\n",
2532 mythreadno
, info
.di_target
);
2534 if (info
.di_target
> 0) {
2535 (void) sprintf(line
, "syslogd pid %ld"
2536 " already running. Cannot "
2537 "start another syslogd pid %ld",
2538 info
.di_target
, getpid());
2539 DPRINT2(5, "open_door(%u): error: "
2540 "%s\n", mythreadno
, line
);
2549 if (lstat(DoorFileName
, &buf
) < 0) {
2552 DPRINT3(5, "open_door(%u): lstat() of %s "
2553 "failed, errno=%d\n",
2554 mythreadno
, DoorFileName
, err
);
2556 if ((door
= creat(DoorFileName
, 0644)) < 0) {
2558 (void) snprintf(line
, sizeof (line
),
2559 "creat() of %s failed - fatal",
2561 DPRINT3(1, "open_door(%u): error: %s, "
2562 "errno=%d\n", mythreadno
, line
,
2571 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
);
2573 DPRINT2(5, "open_door(%u): creat() of %s "
2574 "succeeded\n", mythreadno
,
2581 if (strcmp(DoorFileName
, DOORFILE
) == 0) {
2582 if (lstat(OLD_DOORFILE
, &buf
) == 0) {
2583 DPRINT2(5, "open_door(%u): lstat() of %s "
2584 "succeeded\n", mythreadno
,
2587 if (S_ISDIR(buf
.st_mode
)) {
2588 (void) snprintf(line
, sizeof (line
),
2589 "%s is a directory - fatal",
2591 DPRINT2(1, "open_door(%u): error: "
2592 "%s\n", mythreadno
, line
);
2599 DPRINT2(5, "open_door(%u): %s is not a "
2601 mythreadno
, OLD_DOORFILE
);
2603 if (unlink(OLD_DOORFILE
) < 0) {
2605 (void) snprintf(line
, sizeof (line
),
2606 "unlink() of %s failed",
2608 DPRINT2(5, "open_door(%u): %s\n",
2612 DPRINT3(1, "open_door(%u): "
2615 mythreadno
, line
, err
);
2616 (void) strcat(line
, " - fatal");
2623 DPRINT1(5, "open_door(%u): unlink "
2624 "failure OK on RO file "
2625 "system\n", mythreadno
);
2628 DPRINT2(5, "open_door(%u): file %s doesn't "
2629 "exist\n", mythreadno
, OLD_DOORFILE
);
2632 if (symlink(RELATIVE_DOORFILE
, OLD_DOORFILE
) < 0) {
2634 (void) snprintf(line
, sizeof (line
),
2635 "symlink %s -> %s failed", OLD_DOORFILE
,
2637 DPRINT2(5, "open_door(%u): %s\n", mythreadno
,
2641 DPRINT3(1, "open_door(%u): error: %s, "
2642 "errno=%d\n", mythreadno
, line
,
2645 (void) strcat(line
, " - fatal");
2651 DPRINT1(5, "open_door(%u): symlink failure OK "
2652 "on RO file system\n", mythreadno
);
2654 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2655 "succeeded\n", mythreadno
,
2656 OLD_DOORFILE
, RELATIVE_DOORFILE
);
2660 if ((DoorFd
= door_create(server
, 0,
2661 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) < 0) {
2663 (void) sprintf(line
, "door_create() failed - fatal");
2664 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n",
2665 mythreadno
, line
, err
);
2671 (void) door_setparam(DoorFd
, DOOR_PARAM_DATA_MAX
, 0);
2672 DPRINT2(5, "open_door(%u): door_create() succeeded, "
2673 "DoorFd=%d\n", mythreadno
, DoorFd
);
2678 (void) fdetach(DoorFileName
); /* just in case... */
2680 (void) door_server_create(door_server_pool
);
2682 if (fattach(DoorFd
, DoorFileName
) < 0) {
2684 (void) snprintf(line
, sizeof (line
), "fattach() of fd"
2685 " %d to %s failed - fatal", DoorFd
, DoorFileName
);
2686 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno
,
2694 DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno
,
2698 * create pidfile anyway, so those using it to control
2699 * syslogd (with kill `cat /etc/syslog.pid` perhaps)
2703 if (!PidfileCreated
) {
2708 if ((pidfd
= open(PidFileName
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644))
2711 (void) snprintf(line
, sizeof (line
),
2712 "open() of %s failed", PidFileName
);
2713 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2714 mythreadno
, line
, err
);
2720 (void) fchmod(pidfd
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
);
2721 (void) sprintf(line
, "%ld\n", getpid());
2723 if (write(pidfd
, line
, strlen(line
)) < 0) {
2725 (void) snprintf(line
, sizeof (line
),
2726 "write to %s on fd %d failed", PidFileName
, pidfd
);
2727 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2728 mythreadno
, line
, err
);
2734 (void) close(pidfd
);
2736 DPRINT2(5, "open_door(%u): %s created\n",
2737 mythreadno
, PidFileName
);
2739 if (strcmp(PidFileName
, PIDFILE
) == 0) {
2740 if (lstat(OLD_PIDFILE
, &buf
) == 0) {
2741 DPRINT2(5, "open_door(%u): lstat() of %s "
2742 "succeded\n", mythreadno
, OLD_PIDFILE
);
2744 if (S_ISDIR(buf
.st_mode
)) {
2745 (void) snprintf(line
, sizeof (line
),
2746 "file %s is a directory",
2748 DPRINT2(1, "open_door(%u): warning: "
2749 "%s\n", mythreadno
, line
);
2755 if (unlink(OLD_PIDFILE
) < 0) {
2757 (void) snprintf(line
, sizeof (line
),
2758 "unlink() of %s failed",
2760 DPRINT2(5, "open_door(%u): %s\n",
2764 DPRINT3(1, "open_door (%u): "
2767 mythreadno
, line
, err
);
2773 DPRINT1(5, "open_door(%u): unlink "
2774 "failure OK on RO file "
2775 "system\n", mythreadno
);
2778 DPRINT2(5, "open_door(%u): file %s doesn't "
2779 "exist\n", mythreadno
, OLD_PIDFILE
);
2782 if (symlink(RELATIVE_PIDFILE
, OLD_PIDFILE
) < 0) {
2784 (void) snprintf(line
, sizeof (line
),
2785 "symlink %s -> %s failed", OLD_PIDFILE
,
2787 DPRINT2(5, "open_door(%u): %s\n", mythreadno
,
2791 DPRINT3(1, "open_door(%u): warning: "
2792 "%s, errno=%d\n", mythreadno
,
2799 DPRINT1(5, "open_door(%u): symlink failure OK "
2800 "on RO file system\n", mythreadno
);
2804 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2805 "succeeded\n", mythreadno
, OLD_PIDFILE
,
2812 * the 'server' function that we export via the door. It does
2813 * nothing but return.
2817 server(void *cookie
, char *argp
, size_t arg_size
,
2818 door_desc_t
*dp
, uint_t n
)
2820 (void) door_return(NULL
, 0, NULL
, 0);
2826 create_door_thr(void *arg
)
2828 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
2829 (void) door_return(NULL
, 0, NULL
, 0);
2832 * If there is an error in door_return(), it will return here and
2833 * the thread will exit. Hence we need to decrement door_server_cnt.
2835 (void) pthread_mutex_lock(&door_server_cnt_lock
);
2837 (void) pthread_mutex_unlock(&door_server_cnt_lock
);
2842 * Max number of door server threads for syslogd. Since door is used
2843 * to check the health of syslogd, we don't need large number of
2846 #define MAX_DOOR_SERVER_THR 3
2849 * Manage door server thread pool.
2853 door_server_pool(door_info_t
*dip
)
2855 (void) pthread_mutex_lock(&door_server_cnt_lock
);
2856 if (door_server_cnt
<= MAX_DOOR_SERVER_THR
&&
2857 pthread_create(NULL
, &door_thr_attr
, create_door_thr
, NULL
) == 0) {
2859 (void) pthread_mutex_unlock(&door_server_cnt_lock
);
2863 (void) pthread_mutex_unlock(&door_server_cnt_lock
);
2867 * checkm4 - used to verify that the external utilities that
2868 * syslogd depends on are where we expect them to be.
2869 * Returns 0 if all utilities are found, > 0 if any are missing.
2870 * Also logs errors so user knows what's missing
2877 pthread_t mythreadno
;
2880 mythreadno
= pthread_self();
2883 if (access("/usr/ccs/bin/m4", X_OK
) < 0) {
2885 logerror("/usr/ccs/bin/m4");
2886 DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access "
2887 "returned %d\n", mythreadno
, saverrno
);
2895 * INIT -- Initialize syslogd from configuration table, start up
2896 * input and logger threads. This routine is called only once.
2902 pthread_attr_t sys_attr
, net_attr
, log_attr
, hnl_attr
;
2904 pthread_t mythreadno
;
2907 mythreadno
= pthread_self();
2910 DPRINT1(2, "init(%u): initializing\n", mythreadno
);
2912 /* hand-craft a host_list_t entry for our local host name */
2913 if ((up
= malloc(sizeof (struct utsname
))) == NULL
) {
2917 LocalHostName
.hl_cnt
= 1;
2918 if ((LocalHostName
.hl_hosts
= malloc(sizeof (char *))) == NULL
) {
2921 if ((LocalHostName
.hl_hosts
[0] = strdup(up
->nodename
)) == NULL
) {
2922 free(LocalHostName
.hl_hosts
);
2926 /* also hand craft one for use if name resolution fails */
2927 NullHostName
.hl_cnt
= 1;
2928 if ((NullHostName
.hl_hosts
= malloc(sizeof (char *))) == NULL
) {
2931 if ((NullHostName
.hl_hosts
[0] = strdup("name lookup failed")) == NULL
) {
2938 * Note that getnets will allocate network resources, but won't be
2939 * binding UDP port. This is because, there could be a race
2940 * condition between door. If we bind here, one syslogd could grab
2941 * UDP port first, but later another syslogd could take over without
2942 * getting UDP port but grab the door file. The 2nd syslogd could
2943 * continue to run without listening network.
2944 * bindnet() will be called after door was successfully opened.
2949 * Start up configured theads
2954 * allocate thread stacks for the persistant threads
2956 nthread
= (turnoff
== 0) ? 4 : 2;
2958 if ((stack_ptr
= alloc_stacks(nthread
)) == NULL
) {
2959 logerror("alloc_stacks failed - fatal");
2964 dumpstats(STDOUT_FILENO
);
2967 (void) dataq_init(&inputq
); /* init the input queue */
2969 if (pthread_attr_init(&sys_attr
) != 0 ||
2970 pthread_attr_init(&log_attr
) != 0 ||
2971 pthread_attr_init(&net_attr
) != 0 ||
2972 pthread_attr_init(&hnl_attr
) != 0 ||
2973 pthread_attr_init(&door_thr_attr
) != 0) {
2974 logerror("pthread_attr_init failed - fatal");
2978 (void) pthread_attr_setscope(&sys_attr
, PTHREAD_SCOPE_PROCESS
);
2979 (void) pthread_attr_setscope(&log_attr
, PTHREAD_SCOPE_PROCESS
);
2980 (void) pthread_attr_setscope(&net_attr
, PTHREAD_SCOPE_PROCESS
);
2981 (void) pthread_attr_setscope(&hnl_attr
, PTHREAD_SCOPE_PROCESS
);
2982 (void) pthread_attr_setscope(&door_thr_attr
, PTHREAD_SCOPE_SYSTEM
);
2983 (void) pthread_attr_setdetachstate(&door_thr_attr
,
2984 PTHREAD_CREATE_DETACHED
);
2986 /* 1: logmsg thread */
2987 (void) pthread_attr_setstacksize(&log_attr
, stacksize
);
2988 (void) pthread_attr_setstackaddr(&log_attr
, stack_ptr
);
2989 stack_ptr
+= stacksize
+ redzonesize
;
2990 if (pthread_create(&log_thread
, &log_attr
, logmsg
, NULL
) != 0) {
2991 logerror("pthread_create failed - fatal");
2996 * open the log device, and pull up all pending message
2997 * from the log driver.
3002 * Now we can deliver the pending internal error messages.
3006 /* 2: sys_poll thread */
3007 (void) pthread_attr_setstacksize(&sys_attr
, stacksize
);
3008 (void) pthread_attr_setstackaddr(&sys_attr
, stack_ptr
);
3009 stack_ptr
+= stacksize
+ redzonesize
;
3010 if (pthread_create(&sys_thread
, &sys_attr
, sys_poll
, NULL
) != 0) {
3011 logerror("pthread_create failed - fatal");
3016 * We've started the sys_poll() and logmsg() threads. Now we are ready
3017 * to open the door. This cannot happen before spawning sys_poll(),
3018 * because after opening the door, syslog() will no longer take care of
3019 * LOG_CONS. Therefor, we should pull up all pending log messages and
3020 * activate sys_poll() before opening the door, so that log driver
3021 * won't drop messages.
3025 DPRINT1(1, "init(%u): accepting messages from local system\n",
3029 /* init the hostname lookup queue */
3030 (void) dataq_init(&hnlq
);
3032 /* 3: hostname lookup thread */
3033 (void) pthread_attr_setstacksize(&hnl_attr
, stacksize
);
3034 (void) pthread_attr_setstackaddr(&hnl_attr
, stack_ptr
);
3035 stack_ptr
+= stacksize
+ redzonesize
;
3036 if (pthread_create(&hnl_thread
, &hnl_attr
,
3037 hostname_lookup
, NULL
) != 0) {
3038 logerror("pthread_create failed - fatal");
3042 /* 4: net_poll thread */
3043 (void) pthread_attr_setstacksize(&net_attr
, stacksize
);
3044 (void) pthread_attr_setstackaddr(&net_attr
, stack_ptr
);
3045 stack_ptr
+= stacksize
+ redzonesize
;
3050 if (pthread_create(&net_thread
, &net_attr
, net_poll
,
3052 logerror("pthread_create failed - fatal");
3055 DPRINT1(1, "init(%u): accepting messages from remote\n",
3059 (void) pthread_attr_destroy(&sys_attr
);
3060 (void) pthread_attr_destroy(&net_attr
);
3061 (void) pthread_attr_destroy(&log_attr
);
3062 (void) pthread_attr_destroy(&hnl_attr
);
3064 curalarm
= MarkInterval
* 60 / MARKCOUNT
;
3065 (void) alarm((unsigned)curalarm
);
3066 DPRINT2(2, "init(%u): Next alarm in %d seconds\n",
3067 mythreadno
, curalarm
);
3068 DPRINT1(1, "init(%u): syslogd: started\n", mythreadno
);
3072 * will print a bunch of debugging stats on 'fd'
3082 char *dashes
= "------------------------";
3083 static int conversion_printed
;
3085 if ((out
= fdopen(fd
, "w+")) == NULL
)
3088 (void) fprintf(out
, "\nSyslogd started: %s",
3089 ctime_r(&start_time
, cbuf
));
3090 (void) fprintf(out
, "Input message count: system %d, network %d\n",
3091 sys_msg_count
, net_msg_count
);
3092 (void) fprintf(out
, "# Outputs: %d\n\n", nlogs
);
3094 (void) fprintf(out
, "%s priority = [file, facility] %s\n\n",
3097 for (i
= 0; i
< LOG_NFACILITIES
+ 1; i
++) {
3098 (void) fprintf(out
, "%d ", i
/ 10);
3100 (void) fprintf(out
, "\n");
3101 for (i
= 0; i
< LOG_NFACILITIES
+ 1; i
++) {
3102 (void) fprintf(out
, "%d ", i
% 10);
3104 (void) fprintf(out
, "\n");
3105 for (i
= 0; i
< LOG_NFACILITIES
+ 1; i
++) {
3106 (void) fprintf(out
, "--");
3108 (void) fprintf(out
, "\n");
3110 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
3111 for (i
= 0; i
< LOG_NFACILITIES
+ 1; i
++) {
3112 if (f
->f_pmask
[i
] == NOPRI
)
3113 (void) fprintf(out
, "X ");
3115 (void) fprintf(out
, "%d ",
3118 (void) fprintf(out
, "%s: ", TypeNames
[f
->f_type
]);
3119 switch (f
->f_type
) {
3123 (void) fprintf(out
, "%s", f
->f_un
.f_fname
);
3126 (void) fprintf(out
, "%s", f
->f_un
.f_forw
.f_hname
);
3129 for (i
= 0; i
< MAXUNAMES
&&
3130 *f
->f_un
.f_uname
[i
]; i
++) {
3132 (void) fprintf(out
, "%s",
3133 f
->f_un
.f_uname
[i
]);
3135 (void) fprintf(out
, ", %s",
3136 f
->f_un
.f_uname
[i
]);
3140 (void) fprintf(out
, "\n");
3143 if (!conversion_printed
) {
3144 (void) fprintf(out
, "\nFacilities:\n");
3146 for (i
= 0; FacNames
[i
].c_val
!= -1; i
++) {
3147 (void) fprintf(out
, " [%02d] %s: %3d\n", i
,
3148 FacNames
[i
].c_name
, FacNames
[i
].c_val
);
3151 (void) fprintf(out
, "\nPriorities:\n");
3153 for (i
= 0; PriNames
[i
].c_val
!= -1; i
++) {
3154 (void) fprintf(out
, " [%02d] %s: %3d\n", i
,
3155 PriNames
[i
].c_name
, PriNames
[i
].c_val
);
3158 conversion_printed
= 1;
3161 (void) fprintf(out
, "\n\n\n\t\tPer File Statistics\n");
3162 (void) fprintf(out
, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File");
3163 (void) fprintf(out
, "%-24s\t---\t----\t-----\t----\n", "----");
3164 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
3165 switch (f
->f_type
) {
3169 (void) fprintf(out
, "%-24s", f
->f_un
.f_fname
);
3172 (void) fprintf(out
, "%-24s", TypeNames
[f
->f_type
]);
3175 (void) fprintf(out
, "%-24s", f
->f_un
.f_forw
.f_hname
);
3178 for (i
= 0; i
< MAXUNAMES
&&
3179 *f
->f_un
.f_uname
[i
]; i
++) {
3181 (void) strcpy(users
,
3182 f
->f_un
.f_uname
[i
]);
3184 (void) strcat(users
, ",");
3185 (void) strcat(users
,
3186 f
->f_un
.f_uname
[i
]);
3189 (void) fprintf(out
, "%-24s", users
);
3192 (void) fprintf(out
, "\t%d\t%d\t%d\t%d\n",
3193 f
->f_stat
.total
, f
->f_stat
.dups
,
3194 f
->f_stat
.cantfwd
, f
->f_stat
.errs
);
3196 (void) fprintf(out
, "\n\n");
3197 if (Debug
&& fd
== 1)
3203 * conf_init - This routine is code seperated from the
3204 * init routine in order to be re-callable when we get
3216 pthread_t mythreadno
;
3219 mythreadno
= pthread_self();
3222 DPRINT1(2, "conf_init(%u): starting logger threads\n",
3225 m4argv
[m4argc
++] = "m4";
3227 if (amiloghost() == 1) {
3228 DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno
);
3229 m4argv
[m4argc
++] = "-DLOGHOST=1";
3232 m4argv
[m4argc
++] = ConfFile
;
3233 m4argv
[m4argc
] = NULL
;
3236 * Make sure the configuration file and m4 exist, and then parse
3237 * the configuration file with m4. If any of these fail, resort
3238 * to our hardcoded fallback configuration.
3241 if (access(ConfFile
, R_OK
) == -1) {
3242 DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno
,
3244 logerror("can't open configuration file");
3246 Files
= (struct filed
*) &fallback
; /*lint !e545 */
3247 cfline("*.ERR\t/dev/sysmsg", 0, &Files
[0]);
3248 cfline("*.PANIC\t*", 0, &Files
[1]);
3253 if (checkm4() != 0 || conf_open(&cf
, "/usr/ccs/bin/m4", m4argv
) == -1) {
3254 DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno
,
3257 Files
= (struct filed
*) &fallback
; /*lint !e545 */
3258 cfline("*.ERR\t/dev/sysmsg", 0, &Files
[0]);
3259 cfline("*.PANIC\t*", 0, &Files
[1]);
3264 /* Count the number of lines which are not blanks or comments */
3266 while ((p
= conf_read(&cf
)) != NULL
) {
3267 if (p
[0] != '\0' && p
[0] != '#')
3271 Files
= (struct filed
*)malloc(sizeof (struct filed
) * nlogs
);
3274 DPRINT1(1, "conf_init(%u): malloc failed - can't "
3275 "allocate 'Files' array\n", mythreadno
);
3276 MALLOC_FAIL("loading minimum configuration");
3278 Files
= (struct filed
*) &fallback
; /*lint !e545 */
3279 cfline("*.ERR\t/dev/sysmsg", 0, &Files
[0]);
3280 cfline("*.PANIC\t*", 0, &Files
[1]);
3287 * Foreach line in the conf table, open that file.
3292 while (((p
= conf_read(&cf
)) != NULL
) && (f
< &Files
[nlogs
])) {
3294 /* check for end-of-section */
3295 if (p
[0] == '\0' || p
[0] == '#')
3299 if (f
->f_type
== F_UNUSED
)
3308 * See if marks are to be written to any files. If so, set up a
3309 * timeout for marks.
3315 * allocate thread stacks - one for each logger thread.
3317 if ((cstack_ptr
= alloc_stacks(nlogs
)) == NULL
) {
3318 logerror("alloc_stacks failed - fatal");
3322 /* And now one thread for each configured file */
3323 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
3324 if (filed_init(f
) != 0) {
3325 logerror("pthread_create failed - fatal");
3329 (void) pthread_mutex_lock(&cft
);
3331 (void) pthread_mutex_unlock(&cft
);
3333 if (f
->f_type
!= F_UNUSED
&&
3334 f
->f_pmask
[LOG_NFACILITIES
] != NOPRI
)
3340 * filed init - initialize fields in a file descriptor struct
3341 * this is called before multiple threads are running, so no mutex
3342 * needs to be held at this time.
3345 filed_init(struct filed
*f
)
3347 pthread_attr_t stack_attr
;
3348 pthread_t mythreadno
;
3351 mythreadno
= pthread_self();
3354 if (pthread_mutex_init(&f
->filed_mutex
, NULL
) != 0) {
3355 logerror("pthread_mutex_init failed");
3359 DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n",
3360 mythreadno
, (void *)&f
->f_queue
);
3361 (void) dataq_init(&f
->f_queue
);
3363 if (pthread_attr_init(&stack_attr
) != 0) {
3364 logerror("pthread_attr_init failed");
3368 (void) pthread_attr_setstacksize(&stack_attr
, stacksize
);
3369 (void) pthread_attr_setstackaddr(&stack_attr
, cstack_ptr
);
3370 cstack_ptr
+= stacksize
+ redzonesize
;
3373 f
->f_prevmsg
.msg
[0] = '\0';
3374 f
->f_prevmsg
.flags
= 0;
3375 f
->f_prevmsg
.pri
= 0;
3376 f
->f_prevmsg
.host
[0] = '\0';
3378 f
->f_current
.msg
[0] = '\0';
3379 f
->f_current
.flags
= 0;
3380 f
->f_current
.pri
= 0;
3381 f
->f_current
.host
[0] = '\0';
3386 f
->f_stat
.total
= 0;
3388 f
->f_stat
.cantfwd
= 0;
3391 if (pthread_create(&f
->f_thread
, NULL
, logit
, (void *)f
) != 0) {
3392 logerror("pthread_create failed");
3393 (void) pthread_attr_destroy(&stack_attr
);
3397 (void) pthread_attr_destroy(&stack_attr
);
3403 * Crack a configuration file line
3406 cfline(char *line
, int lineno
, struct filed
*f
)
3414 char ebuf
[SYS_NMLN
+1+40];
3415 mode_t fmode
, omode
= O_WRONLY
|O_APPEND
|O_NOCTTY
;
3417 pthread_t mythreadno
;
3420 mythreadno
= pthread_self();
3423 DPRINT2(1, "cfline(%u): (%s)\n", mythreadno
, line
);
3425 errno
= 0; /* keep errno related stuff out of logerror messages */
3427 /* clear out file entry */
3428 bzero((char *)f
, sizeof (*f
));
3429 for (i
= 0; i
<= LOG_NFACILITIES
; i
++)
3430 f
->f_pmask
[i
] = NOPRI
;
3432 /* scan through the list of selectors */
3433 for (p
= line
; *p
&& *p
!= '\t'; ) {
3435 /* find the end of this facility name list */
3436 for (q
= p
; *q
&& *q
!= '\t' && *q
++ != '.'; )
3439 /* collect priority name */
3440 for (bp
= buf
; *q
&& !strchr("\t,;", *q
); )
3445 while (strchr(", ;", *q
))
3448 /* decode priority name */
3449 pri
= decode(buf
, PriNames
);
3451 logerror("line %d: unknown priority name \"%s\"",
3456 /* scan facilities */
3457 while (*p
&& !strchr("\t.;", *p
)) {
3458 for (bp
= buf
; *p
&& !strchr("\t,;.", *p
); )
3462 for (i
= 0; i
< LOG_NFACILITIES
; i
++)
3463 f
->f_pmask
[i
] = (uchar_t
)pri
;
3465 i
= decode(buf
, FacNames
);
3467 logerror("line %d: unknown facility"
3468 " name \"%s\"", lineno
, buf
);
3471 f
->f_pmask
[i
>> 3] = (uchar_t
)pri
;
3473 while (*p
== ',' || *p
== ' ')
3480 /* skip to action part */
3481 while (*p
== '\t' || *p
== ' ')
3487 logerror("line %d: no action part", lineno
);
3491 (void) strlcpy(f
->f_un
.f_forw
.f_hname
, ++p
, SYS_NMLN
);
3492 if (logforward(f
, ebuf
, sizeof (ebuf
)) != 0) {
3493 logerror("line %d: %s", lineno
, ebuf
);
3500 (void) strlcpy(f
->f_un
.f_fname
, p
, MAXPATHLEN
);
3501 if (stat64(p
, &sbuf
) < 0) {
3506 * don't block trying to open a pipe
3507 * with no reader on the other end
3509 fmode
= 0; /* reset each pass */
3510 if (S_ISFIFO(sbuf
.st_mode
))
3513 f
->f_file
= open64(p
, omode
|fmode
);
3514 if (f
->f_file
< 0) {
3515 if (fmode
&& errno
== ENXIO
) {
3517 logerror("%s - no reader", p
);
3524 * Fifos are initially opened NONBLOCK
3525 * to insure we don't hang, but once
3526 * we are open, we need to change the
3527 * behavior back to blocking, otherwise
3528 * we may get write errors, and the log
3529 * will get closed down the line.
3531 if (S_ISFIFO(sbuf
.st_mode
))
3532 (void) fcntl(f
->f_file
, F_SETFL
, omode
);
3534 if (isatty(f
->f_file
)) {
3540 if ((strcmp(p
, ctty
) == 0) || (strcmp(p
, sysmsg
) == 0))
3541 f
->f_type
= F_CONSOLE
;
3549 for (i
= 0; i
< MAXUNAMES
&& *p
; i
++) {
3550 for (q
= p
; *q
&& *q
!= ','; )
3552 (void) strlcpy(f
->f_un
.f_uname
[i
], p
, UNAMESZ
);
3553 if ((q
- p
) > UNAMESZ
)
3554 f
->f_un
.f_uname
[i
][UNAMESZ
] = '\0';
3556 f
->f_un
.f_uname
[i
][q
- p
] = '\0';
3557 while (*q
== ',' || *q
== ' ')
3561 f
->f_type
= F_USERS
;
3564 f
->f_orig_type
= f
->f_type
;
3569 * Decode a symbolic name to a numeric value
3572 decode(char *name
, struct code
*codetab
)
3579 return (atoi(name
));
3581 (void) strncpy(buf
, name
, sizeof (buf
) - 1);
3582 for (p
= buf
; *p
; p
++)
3585 for (c
= codetab
; c
->c_name
; c
++)
3586 if (!(strcmp(buf
, c
->c_name
)))
3593 ismyaddr(struct netbuf
*nbp
)
3600 for (i
= 1; i
< Ninputs
; i
++) {
3601 if (same_addr(nbp
, Myaddrs
[i
]))
3610 struct nd_hostserv hs
;
3611 struct netconfig
*ncp
;
3612 struct nd_addrlist
*nap
;
3617 pthread_t mythreadno
;
3620 mythreadno
= pthread_self();
3624 DPRINT1(1, "getnets(%u): network is being turned off\n",
3629 hs
.h_host
= HOST_SELF
;
3630 hs
.h_serv
= "syslog";
3632 if ((handle
= setnetconfig()) == NULL
) {
3636 while ((ncp
= getnetconfig(handle
)) != NULL
) {
3637 if (ncp
->nc_semantics
!= NC_TPI_CLTS
) {
3641 if (netdir_getbyname(ncp
, &hs
, &nap
) != 0) {
3645 if (nap
== NULL
|| nap
->n_cnt
<= 0) {
3646 DPRINT1(1, "getnets(%u): found no address\n",
3648 netdir_free((void *)nap
, ND_ADDRLIST
);
3653 DPRINT2(1, "getnets(%u): found %d addresses",
3654 mythreadno
, nap
->n_cnt
);
3655 DPRINT0(1, ", they are: ");
3658 for (i
= 0; i
< nap
->n_cnt
; i
++) {
3659 if ((uap
= taddr2uaddr(ncp
, nbp
)) != NULL
) {
3660 DPRINT1(1, "%s ", uap
);
3669 inputs
= Ninputs
+ nap
->n_cnt
;
3671 Nfd
= reallocarray(Nfd
, inputs
, sizeof (struct pollfd
));
3672 Ncf
= reallocarray(Ncf
, inputs
, sizeof (struct netconfig
));
3673 Myaddrs
= reallocarray(Myaddrs
, inputs
,
3674 sizeof (struct netbuf
*));
3675 Udp
= reallocarray(Udp
, inputs
, sizeof (struct t_unitdata
*));
3676 Errp
= reallocarray(Errp
, inputs
, sizeof (struct t_uderr
*));
3679 * all malloc failures here are fatal
3681 if (Nfd
== NULL
|| Ncf
== NULL
|| Myaddrs
== NULL
||
3682 Udp
== NULL
|| Errp
== NULL
) {
3688 for (i
= 0; i
< nap
->n_cnt
; i
++, nbp
++) {
3691 if (addnet(ncp
, nbp
) == 0) {
3696 (void) strcpy(ebuf
, "Unable to configure syslog port");
3698 if ((uap
= taddr2uaddr(ncp
, nbp
)) != NULL
) {
3699 size_t l
= strlen(ebuf
);
3700 (void) snprintf(ebuf
+ l
, sizeof (ebuf
) - l
,
3704 DPRINT2(1, "getnets(%u): %s",
3713 * Here maybe syslogd can quit. However, syslogd
3714 * has been ignoring this error and keep running.
3715 * So we won't break it.
3719 netdir_free((void *)nap
, ND_ADDRLIST
);
3722 (void) endnetconfig(handle
);
3726 * Open the network device, and allocate necessary resources.
3727 * Myaddrs will also be filled, so that we can call ismyaddr() before
3728 * being bound to the network.
3731 addnet(struct netconfig
*ncp
, struct netbuf
*nbp
)
3736 fd
= t_open(ncp
->nc_device
, O_RDWR
, NULL
);
3742 (void) memcpy(&Ncf
[Ninputs
], ncp
, sizeof (struct netconfig
));
3745 Udp
[Ninputs
] = (struct t_unitdata
*)t_alloc(fd
, T_UNITDATA
, T_ADDR
);
3747 if (Udp
[Ninputs
] == NULL
) {
3753 Errp
[Ninputs
] = (struct t_uderr
*)t_alloc(fd
, T_UDERROR
, T_ADDR
);
3755 if (Errp
[Ninputs
] == NULL
) {
3757 (void) t_free((char *)Udp
[Ninputs
], T_UNITDATA
);
3761 if ((bp
= malloc(sizeof (struct netbuf
))) == NULL
||
3762 (bp
->buf
= malloc(nbp
->len
)) == NULL
) {
3763 MALLOC_FAIL("allocating address buffer");
3765 (void) t_free((char *)Udp
[Ninputs
], T_UNITDATA
);
3766 (void) t_free((char *)Errp
[Ninputs
], T_UDERROR
);
3776 (void) memcpy(bp
->buf
, nbp
->buf
, nbp
->len
);
3777 Myaddrs
[Ninputs
] = bp
;
3779 Nfd
[Ninputs
].fd
= fd
;
3780 Nfd
[Ninputs
].events
= POLLIN
;
3786 * Allocate UDP buffer to minimize packet loss.
3789 set_udp_buffer(int fd
)
3791 struct t_optmgmt req
, resp
;
3793 size_t optsize
, bsize
= 256 * 1024;
3794 pthread_t mythreadno
;
3797 mythreadno
= pthread_self();
3800 optsize
= sizeof (struct opthdr
) + sizeof (int);
3801 if ((opt
= malloc(optsize
)) == NULL
) {
3802 MALLOC_FAIL("will have no udp buffer");
3805 opt
->level
= SOL_SOCKET
;
3806 opt
->name
= SO_RCVBUF
;
3807 opt
->len
= sizeof (int);
3808 *(int *)(opt
+ 1) = bsize
;
3810 req
.flags
= T_NEGOTIATE
;
3811 req
.opt
.len
= optsize
;
3812 req
.opt
.buf
= (char *)opt
;
3815 resp
.opt
.maxlen
= optsize
;
3816 resp
.opt
.buf
= (char *)opt
;
3818 while (t_optmgmt(fd
, &req
, &resp
) == -1 || resp
.flags
!= T_SUCCESS
) {
3819 if (t_errno
!= TSYSERR
|| errno
!= ENOBUFS
) {
3827 *(int *)(opt
+ 1) = bsize
;
3830 logerror("failed to allocate UDP buffer");
3832 DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n",
3833 mythreadno
, bsize
, fd
);
3838 * Attach the network, and allocate UDP buffer for the interface.
3843 struct t_bind bind
, *bound
;
3846 pthread_t mythreadno
;
3849 mythreadno
= pthread_self();
3854 while (cnt
< Ninputs
) {
3858 bound
= (struct t_bind
*)t_alloc(Nfd
[cnt
].fd
, T_BIND
, T_ADDR
);
3859 bind
.addr
= *Myaddrs
[cnt
];
3862 if (t_bind(Nfd
[cnt
].fd
, &bind
, bound
) == 0) {
3863 if (same_addr(&bind
.addr
, &bound
->addr
)) {
3864 (void) t_free((char *)bound
, T_BIND
);
3865 set_udp_buffer(Nfd
[cnt
].fd
);
3871 /* failed to bind port */
3872 (void) t_free((char *)bound
, T_BIND
);
3874 (void) strcpy(ebuf
, "Unable to bind syslog port");
3876 uap
= taddr2uaddr(&Ncf
[cnt
], Myaddrs
[cnt
]);
3879 (void) snprintf(ebuf
+ i
, sizeof (ebuf
) - i
,
3883 DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n",
3884 mythreadno
, uap
? uap
: "<unknown>");
3893 (void) t_close(Nfd
[cnt
].fd
);
3894 free(Myaddrs
[cnt
]->buf
);
3896 (void) t_free((char *)Udp
[cnt
], T_UNITDATA
);
3897 (void) t_free((char *)Errp
[cnt
], T_UDERROR
);
3899 for (i
= cnt
; i
< (Ninputs
-1); i
++) {
3900 Nfd
[i
] = Nfd
[i
+ 1];
3901 Ncf
[i
] = Ncf
[i
+ 1];
3902 Myaddrs
[i
] = Myaddrs
[i
+ 1];
3903 Udp
[i
] = Udp
[i
+ 1];
3904 Errp
[i
] = Errp
[i
+ 1];
3912 logforward(struct filed
*f
, char *ebuf
, size_t elen
)
3914 struct nd_hostserv hs
;
3916 struct netconfig
*ncp
;
3917 struct nd_addrlist
*nap
;
3921 hp
= f
->f_un
.f_forw
.f_hname
;
3923 hs
.h_serv
= "syslog";
3925 if ((handle
= setnetconfig()) == NULL
) {
3926 (void) strlcpy(ebuf
,
3927 "unable to rewind the netconfig database", elen
);
3932 while ((ncp
= getnetconfig(handle
)) != NULL
) {
3933 if (ncp
->nc_semantics
== NC_TPI_CLTS
) {
3934 if (netdir_getbyname(ncp
, &hs
, &nap
) == 0) {
3943 (void) endnetconfig(handle
);
3944 (void) snprintf(ebuf
, elen
,
3945 "WARNING: %s could not be resolved", hp
);
3950 (void) endnetconfig(handle
);
3951 (void) snprintf(ebuf
, elen
, "unknown host %s", hp
);
3956 if (ismyaddr(nbp
)) { /*lint !e644 */
3957 netdir_free((void *)nap
, ND_ADDRLIST
);
3958 (void) endnetconfig(handle
);
3959 (void) snprintf(ebuf
, elen
,
3960 "host %s is this host - logging loop", hp
);
3964 f
->f_un
.f_forw
.f_addr
.buf
= malloc(nbp
->len
);
3965 if (f
->f_un
.f_forw
.f_addr
.buf
== NULL
) {
3966 netdir_free((void *)nap
, ND_ADDRLIST
);
3967 (void) endnetconfig(handle
);
3968 (void) strlcpy(ebuf
, "malloc failed", elen
);
3971 bcopy(nbp
->buf
, f
->f_un
.f_forw
.f_addr
.buf
, nbp
->len
);
3972 f
->f_un
.f_forw
.f_addr
.len
= nbp
->len
;
3973 f
->f_file
= t_open(ncp
->nc_device
, O_RDWR
, NULL
);
3974 if (f
->f_file
< 0) {
3975 netdir_free((void *)nap
, ND_ADDRLIST
);
3976 (void) endnetconfig(handle
);
3977 free(f
->f_un
.f_forw
.f_addr
.buf
);
3978 (void) strlcpy(ebuf
, "t_open", elen
);
3981 netdir_free((void *)nap
, ND_ADDRLIST
);
3982 (void) endnetconfig(handle
);
3983 if (t_bind(f
->f_file
, NULL
, NULL
) < 0) {
3984 (void) strlcpy(ebuf
, "t_bind", elen
);
3985 free(f
->f_un
.f_forw
.f_addr
.buf
);
3986 (void) t_close(f
->f_file
);
3995 struct nd_hostserv hs
;
3996 struct netconfig
*ncp
;
3997 struct nd_addrlist
*nap
;
4002 struct t_bind bind
, *bound
;
4003 pthread_t mythreadno
;
4006 mythreadno
= pthread_self();
4010 * we need to know if we are running on the loghost. This is
4011 * checked by binding to the address associated with "loghost"
4012 * and "syslogd" service over the connectionless transport
4014 hs
.h_host
= "loghost";
4015 hs
.h_serv
= "syslog";
4017 if ((handle
= setnetconfig()) == NULL
) {
4021 while ((ncp
= getnetconfig(handle
)) != NULL
) {
4022 if (ncp
->nc_semantics
!= NC_TPI_CLTS
) {
4026 if (netdir_getbyname(ncp
, &hs
, &nap
) != 0) {
4036 for (i
= 0; i
< nap
->n_cnt
; i
++) {
4037 if ((uap
= taddr2uaddr(ncp
, nbp
)) != NULL
) {
4038 DPRINT2(1, "amiloghost(%u): testing %s\n",
4044 fd
= t_open(ncp
->nc_device
, O_RDWR
, NULL
);
4047 netdir_free((void *)nap
, ND_ADDRLIST
);
4048 (void) endnetconfig(handle
);
4053 bound
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
4057 if (t_bind(fd
, &bind
, bound
) == 0) {
4059 (void) t_free((char *)bound
, T_BIND
);
4060 netdir_free((void *)nap
, ND_ADDRLIST
);
4061 (void) endnetconfig(handle
);
4065 (void) t_free((char *)bound
, T_BIND
);
4071 netdir_free((void *)nap
, ND_ADDRLIST
);
4074 (void) endnetconfig(handle
);
4079 same_addr(struct netbuf
*na
, struct netbuf
*nb
)
4084 assert(na
->buf
!= NULL
&& nb
->buf
!= NULL
);
4086 if (na
->len
!= nb
->len
) {
4104 * allocates a new message structure, initializes it
4105 * and returns a pointer to it
4107 static log_message_t
*
4111 pthread_t mythreadno
;
4114 mythreadno
= pthread_self();
4117 if ((lm
= malloc(sizeof (log_message_t
))) == NULL
)
4118 return ((log_message_t
*)NULL
);
4120 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lm
))
4122 if (pthread_mutex_init(&lm
->msg_mutex
, NULL
) != 0)
4123 return ((log_message_t
*)NULL
);
4131 DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno
, (void *)lm
);
4136 * frees a message structure - should only be called if
4140 free_msg(log_message_t
*lm
)
4142 pthread_t mythreadno
;
4145 mythreadno
= pthread_self();
4148 assert(lm
!= NULL
&& lm
->refcnt
== 0);
4149 if (lm
->hlp
!= NULL
)
4151 DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno
, (void *)lm
);
4156 * Make sure that the message makes sense in the current locale, and
4157 * does not contain stray control characters.
4160 filter_string(char *mbstr
, char *filtered
, size_t max
)
4164 unsigned char *p
= (unsigned char *)mbstr
;
4165 pthread_t mythreadno
= 0;
4168 mythreadno
= pthread_self();
4171 assert(mbstr
!= NULL
&& filtered
!= NULL
);
4174 * Since the access to MB_CUR_MAX is expensive (because
4175 * MB_CUR_MAX lives in a global area), it should be
4176 * restrained for the better performance.
4178 mb_cur_max
= (size_t)MB_CUR_MAX
;
4179 if (mb_cur_max
> 1) {
4180 /* multibyte locale */
4184 while (*p
!= '\0') {
4185 if ((mlen
= mbtowc(&wc
, (char *)p
,
4186 mb_cur_max
)) == -1) {
4188 * Invalid byte sequence found.
4190 * try to print one byte
4193 DPRINT2(9, "filter_string(%u): Invalid "
4194 "MB sequence: %ld\n", mythreadno
,
4197 if (!putctrlc(*p
++, &filtered
, &cs
, max
)) {
4198 /* not enough buffer */
4205 * Since *p is not a null byte here,
4206 * mbtowc should have never returned 0.
4208 * A valid wide character found.
4211 if (wc
!= L
'\t' && iswcntrl(wc
)) {
4213 * non-tab, non-newline, and
4214 * control character found.
4216 * try to print this wide character
4221 DPRINT2(9, "filter_string(%u): MB"
4222 " control character: %ld\n",
4226 if (!putctrlc(*p
++, &filtered
,
4229 * not enough buffer in
4244 * tab, newline, or non-control
4247 if (cs
+ mlen
< max
) {
4255 /* not enough buffer */
4262 /* singlebyte locale */
4264 while (*p
!= '\0') {
4265 if (*p
!= '\t' && iscntrl(*p
)) {
4267 * non-tab, non-newline,
4268 * and control character found.
4270 * try to print this singlebyte character
4273 DPRINT2(9, "filter_string(%u): control "
4274 "character: %d\n", mythreadno
, *p
);
4276 if (!putctrlc(*p
++, &filtered
, &cs
, max
)) {
4277 /* not enough buffer */
4282 } else if (*p
!= '\t' && !isprint(*p
)) {
4284 * non-tab and non printable character found
4285 * this check is required for the C locale
4287 DPRINT2(9, "filter_string(%u): non-printable "
4288 "character: %d\n", mythreadno
, *p
);
4289 if (!putctrlc(*p
++, &filtered
, &cs
, max
)) {
4290 /* not enough buffer */
4297 * tab, newline, non-control character, or
4305 /* not enough buffer */
4316 filtered
[-2] == '\\' && filtered
[-1] == 'n') {
4317 filtered
[-2] = '\0';
4322 alloc_stacks(int numstacks
)
4324 size_t pagesize
, mapsize
;
4329 pagesize
= (size_t)sysconf(_SC_PAGESIZE
);
4331 * stacksize and redzonesize are global so threads
4332 * can be created elsewhere and refer to the sizes
4334 stacksize
= (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN
) +
4335 DEFAULT_STACKSIZE
, pagesize
);
4336 redzonesize
= (size_t)roundup(DEFAULT_REDZONESIZE
, pagesize
);
4339 * allocate an additional "redzonesize" chunk in addition
4340 * to what we require, so we can create a redzone at the
4341 * bottom of the last stack as well.
4343 mapsize
= redzonesize
+ numstacks
* (stacksize
+ redzonesize
);
4344 stack_top
= mmap(NULL
, mapsize
, PROT_READ
|PROT_WRITE
,
4345 MAP_PRIVATE
|MAP_ANON
, -1, 0);
4346 if (stack_top
== MAP_FAILED
)
4351 * this loop is intentionally <= instead of <, so we can
4352 * protect the redzone at the bottom of the last stack
4354 for (i
= 0; i
<= numstacks
; i
++) {
4355 (void) mprotect(addr
, redzonesize
, PROT_NONE
);
4356 addr
+= stacksize
+ redzonesize
;
4358 return ((char *)(stack_top
+ redzonesize
));
4362 dealloc_stacks(int numstacks
)
4364 size_t pagesize
, mapsize
;
4366 pagesize
= (size_t)sysconf(_SC_PAGESIZE
);
4368 stacksize
= (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN
) +
4369 DEFAULT_STACKSIZE
, pagesize
);
4371 redzonesize
= (size_t)roundup(DEFAULT_REDZONESIZE
, pagesize
);
4373 mapsize
= redzonesize
+ numstacks
* (stacksize
+ redzonesize
);
4374 (void) munmap(cstack_ptr
- mapsize
, mapsize
);
4378 filed_destroy(struct filed
*f
)
4380 (void) dataq_destroy(&f
->f_queue
);
4381 (void) pthread_mutex_destroy(&f
->filed_mutex
);
4387 pthread_t mythreadno
;
4390 mythreadno
= pthread_self();
4393 (void) fdetach(DoorFileName
);
4395 DPRINT2(5, "close_door(%u): detached server() from %s\n",
4396 mythreadno
, DoorFileName
);
4400 delete_doorfiles(void)
4402 pthread_t mythreadno
;
4405 char line
[MAXLINE
+1];
4408 mythreadno
= pthread_self();
4412 if (lstat(DoorFileName
, &sb
) == 0 && !S_ISDIR(sb
.st_mode
)) {
4413 if (unlink(DoorFileName
) < 0) {
4415 (void) snprintf(line
, sizeof (line
),
4416 "unlink() of %s failed - fatal", DoorFileName
);
4419 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4420 "errno=%d\n", mythreadno
, line
, err
);
4424 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4425 mythreadno
, DoorFileName
);
4428 if (strcmp(DoorFileName
, DOORFILE
) == 0) {
4429 if (lstat(OLD_DOORFILE
, &sb
) == 0 && !S_ISDIR(sb
.st_mode
)) {
4430 if (unlink(OLD_DOORFILE
) < 0) {
4432 (void) snprintf(line
, sizeof (line
),
4433 "unlink() of %s failed", OLD_DOORFILE
);
4434 DPRINT2(5, "delete_doorfiles(%u): %s\n",
4439 (void) strlcat(line
, " - fatal",
4442 DPRINT3(1, "delete_doorfiles(%u): "
4443 "error: %s, errno=%d\n",
4444 mythreadno
, line
, err
);
4448 DPRINT1(5, "delete_doorfiles(%u): unlink() "
4449 "failure OK on RO file system\n",
4453 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4454 mythreadno
, OLD_DOORFILE
);
4458 if (lstat(PidFileName
, &sb
) == 0 && !S_ISDIR(sb
.st_mode
)) {
4459 if (unlink(PidFileName
) < 0) {
4461 (void) snprintf(line
, sizeof (line
),
4462 "unlink() of %s failed - fatal", PidFileName
);
4465 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4466 "errno=%d\n", mythreadno
, line
, err
);
4470 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno
,
4474 if (strcmp(PidFileName
, PIDFILE
) == 0) {
4475 if (lstat(OLD_PIDFILE
, &sb
) == 0 && !S_ISDIR(sb
.st_mode
)) {
4476 if (unlink(OLD_PIDFILE
) < 0) {
4478 (void) snprintf(line
, sizeof (line
),
4479 "unlink() of %s failed", OLD_PIDFILE
);
4480 DPRINT2(5, "delete_doorfiles(%u): %s, \n",
4485 (void) strlcat(line
, " - fatal",
4488 DPRINT3(1, "delete_doorfiles(%u): "
4489 "error: %s, errno=%d\n",
4490 mythreadno
, line
, err
);
4494 DPRINT1(5, "delete_doorfiles(%u): unlink "
4495 "failure OK on RO file system\n",
4499 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4500 mythreadno
, OLD_PIDFILE
);
4505 (void) door_revoke(DoorFd
);
4508 DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n",
4509 mythreadno
, DoorFd
);
4515 signull(int sig
, siginfo_t
*sip
, void *utp
)
4517 DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n",
4520 * Do nothing, as this is a place-holder used in conjunction with
4521 * sigaction()/sigwait() to ensure that the proper disposition is
4522 * given to the signals we handle in main().
4527 * putctrlc returns zero, if failed due to not enough buffer.
4528 * Otherwise, putctrlc returns non-zero.
4530 * c: a byte to print in ASCII format
4531 * **buf: a pointer to the pointer to the output buffer.
4532 * *cl: current length of characters in the output buffer
4533 * max: maximum length of the buffer
4537 putctrlc(int c
, char **buf
, size_t *cl
, size_t max
)
4542 if (*cl
+ 2 < max
) {
4551 } else if (c
< 0200) {
4552 /* ascii control character */
4553 if (*cl
+ 2 < max
) {
4563 if (*cl
+ 4 < max
) {
4565 *p
++ = ((c
>> 6) & 07) + '0';
4566 *p
++ = ((c
>> 3) & 07) + '0';
4567 *p
++ = (c
& 07) + '0';
4579 * Scans each character in buf until it finds the last newline in buf,
4580 * or the scanned character becomes the last COMPLETE character in buf.
4581 * Returns the number of scanned bytes.
4583 * buf - pointer to a buffer containing the message string
4584 * len - the length of the buffer
4587 findnl_bkwd(const char *buf
, const size_t len
)
4591 pthread_t mythreadno
;
4594 mythreadno
= pthread_self();
4601 mb_cur_max
= MB_CUR_MAX
;
4603 if (mb_cur_max
== 1) {
4604 /* single-byte locale */
4605 for (p
= buf
+ len
- 1; p
!= buf
; p
--) {
4607 return ((size_t)(p
- buf
));
4610 return ((size_t)len
);
4612 /* multi-byte locale */
4619 for (rem
= len
; rem
>= mb_cur_max
; ) {
4620 mlen
= mblen(p
, mb_cur_max
);
4623 * Invalid character found.
4625 DPRINT1(9, "findnl_bkwd(%u): Invalid MB "
4626 "sequence\n", mythreadno
);
4628 * handle as a single byte character.
4634 * It's guaranteed that *p points to
4635 * the 1st byte of a multibyte character.
4645 return ((size_t)(nl
- buf
));
4648 * no newline nor null byte found.
4649 * Also it's guaranteed that *p points to
4650 * the 1st byte of a (multibyte) character
4659 * Scans each character in buf and copies the scanned character to obuf
4660 * until it finds a null byte or a newline, or
4661 * the number of the remaining bytes in obuf gets to exceed obuflen
4662 * if copying the scanned character to obuf.
4663 * Returns the number of scanned bytes.
4665 * obuf - buffer to be copied the scanned character
4666 * obuflen - the size of obuf
4667 * buf - pointer to a buffer containing the message string
4668 * len - the length of the buffer
4671 copynl_frwd(char *obuf
, const size_t obuflen
,
4672 const char *buf
, const size_t len
)
4678 pthread_t mythreadno
;
4681 mythreadno
= pthread_self();
4688 mb_cur_max
= MB_CUR_MAX
;
4690 if (mb_cur_max
== 1) {
4691 /* single-byte locale */
4692 for (p
= buf
; *p
; ) {
4693 if (obuflen
> olen
+ 1) {
4699 return ((size_t)(p
- buf
));
4703 return ((size_t)(p
- buf
));
4707 return ((size_t)(p
- buf
));
4709 /* multi-byte locale */
4712 for (p
= buf
; *p
; ) {
4713 mlen
= mblen(p
, mb_cur_max
);
4716 * Invalid character found.
4718 DPRINT1(9, "copynl_frwd(%u): Invalid MB "
4719 "sequence\n", mythreadno
);
4721 * handle as a single byte character.
4723 if (obuflen
> olen
+ 1) {
4728 return ((size_t)(p
- buf
));
4732 * It's guaranteed that *p points to
4733 * the 1st byte of a multibyte character.
4737 return ((size_t)(p
- buf
));
4739 if (obuflen
> olen
+ mlen
) {
4741 for (n
= 0; n
< mlen
; n
++) {
4747 return ((size_t)(p
- buf
));
4752 * no newline nor null byte found.
4753 * Also it's guaranteed that *p points to
4754 * the 1st byte of a (multibyte) character
4758 return ((size_t)(p
- buf
));
4764 * Scans each character in buf and copies the scanned character to obuf
4765 * until the number of the remaining bytes in obuf gets to exceed obuflen
4766 * if copying the scanned character to obuf.
4767 * Returns the number of scanned (copied) bytes.
4769 * obuf - buffer to be copied the scanned character
4770 * obuflen - the size of obuf
4771 * buf - pointer to a buffer containing the message string
4772 * len - the length of the buffer
4775 copy_frwd(char *obuf
, const size_t obuflen
,
4776 const char *buf
, const size_t len
)
4782 pthread_t mythreadno
;
4785 mythreadno
= pthread_self();
4792 mb_cur_max
= MB_CUR_MAX
;
4794 if (mb_cur_max
== 1) {
4795 /* single-byte locale */
4796 if (obuflen
> len
) {
4797 (void) memcpy(obuf
, buf
, len
);
4799 return ((size_t)len
);
4801 (void) memcpy(obuf
, buf
, obuflen
- 1);
4802 obuf
[obuflen
- 1] = '\0';
4803 return (obuflen
- 1);
4806 /* multi-byte locale */
4809 for (p
= buf
; *p
; ) {
4810 mlen
= mblen(p
, mb_cur_max
);
4813 * Invalid character found.
4815 DPRINT1(9, "copy_frwd(%u): Invalid MB "
4816 "sequence\n", mythreadno
);
4818 * handle as a single byte character.
4820 if (obuflen
> olen
+ 1) {
4825 return ((size_t)(p
- buf
));
4828 if (obuflen
> olen
+ mlen
) {
4830 for (n
= 0; n
< mlen
; n
++) {
4836 return ((size_t)(p
- buf
));
4841 return ((size_t)(p
- buf
));
4847 * Get properties from SMF framework.
4852 scf_simple_prop_t
*prop
;
4855 if ((prop
= scf_simple_prop_get(NULL
, NULL
, "config",
4856 "log_from_remote")) != NULL
) {
4857 if ((bool = scf_simple_prop_next_boolean(prop
)) != NULL
) {
4859 turnoff
= 1; /* log_from_remote = false */
4861 turnoff
= 0; /* log_from_remote = true */
4863 scf_simple_prop_free(prop
);
4864 DPRINT1(1, "properties: setting turnoff to %s\n",
4865 turnoff
? "true" : "false");
4870 * close all the input devices.
4873 shutdown_input(void)
4879 for (cnt
= 0; cnt
< Ninputs
; cnt
++) {
4880 (void) t_close(Nfd
[cnt
].fd
);
4883 (void) close(Pfd
.fd
);
4887 * This is for the one thread that dedicates to resolve the
4888 * hostname. This will get the messages from net_poll() through
4889 * hnlq, and resolve the hostname, and push the messages back
4894 hostname_lookup(void *ap
)
4899 char failsafe_addr
[SYS_NMLN
+ 1];
4900 pthread_t mythreadno
;
4903 mythreadno
= pthread_self();
4906 DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n",
4910 (void) dataq_dequeue(&hnlq
, (void **)&mp
, 0);
4912 DPRINT3(5, "hostname_lookup(%u): dequeued msg %p"
4913 " from queue %p\n", mythreadno
, (void *)mp
,
4916 hip
= (host_info_t
*)mp
->ptr
;
4917 if ((uap
= taddr2uaddr(hip
->ncp
, &hip
->addr
)) != NULL
) {
4918 (void) strlcpy(failsafe_addr
, uap
, SYS_NMLN
);
4921 (void) strlcpy(failsafe_addr
, "<unknown>", SYS_NMLN
);
4924 mp
->hlp
= cvthname(&hip
->addr
, hip
->ncp
, failsafe_addr
);
4926 if (mp
->hlp
== NULL
) {
4927 mp
->hlp
= &NullHostName
;
4930 free(hip
->addr
.buf
);
4934 if (dataq_enqueue(&inputq
, (void *)mp
) == -1) {
4935 MALLOC_FAIL("dropping message from remote");
4940 DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue "
4941 "%p\n", mythreadno
, (void *)mp
, (void *)&inputq
);
4949 * Does all HUP(re-configuration) process.
4954 int cnt
, loop
, drops
;
4956 int console_stuck
= 0;
4962 pthread_t mythreadno
;
4965 mythreadno
= pthread_self();
4968 /* If we get here then we must need to regen */
4971 if (logmymsg(LOG_SYSLOG
|LOG_INFO
, "syslogd: configuration restart",
4972 ADDDATE
, 0) == -1) {
4973 MALLOC_FAIL("dropping message");
4977 * make sure the logmsg thread is not in the waiting state.
4978 * Otherwise, changing hup_state will prevent the logmsg thread
4979 * getting out from the waiting loop.
4984 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()"
4985 " moving to the safe place\n",
4986 mythreadno
, ctime_r(&tim
, cbuf
)+4);
4989 for (loop
= 0; loop
< LOOP_MAX
; loop
++) {
4990 /* we don't need the mutex to read */
4991 if (hup_state
== HUP_ACCEPTABLE
)
4995 if (hup_state
!= HUP_ACCEPTABLE
) {
5001 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n",
5002 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5006 * Prevent logging until we are truly done processing the HUP
5008 (void) pthread_mutex_lock(&hup_lock
);
5009 hup_state
= HUP_INPROGRESS
;
5010 (void) pthread_mutex_unlock(&hup_lock
);
5013 * We will be going into a critical state. Any error message
5014 * from syslogd needs to be dumped to the console by default
5015 * immediately. Also, those error messages are quened in a temporary
5016 * queue to be able to post into the regular stream later.
5022 DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n",
5023 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5026 /* stop configured threads */
5027 if (shutdown_msg() == -1) {
5029 * No memory, message will be dumped to the console.
5031 MALLOC_FAIL("unable to restart syslogd");
5035 /* make sure logmsg() is in suspended state */
5036 for (loop
= 0; loop
< LOOP_INTERVAL
; loop
++) {
5037 if (hup_state
& HUP_LOGMSG_SUSPENDED
)
5042 if ((hup_state
& HUP_LOGMSG_SUSPENDED
) == 0) {
5045 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not "
5046 "stop. enforcing\n",
5047 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5050 /* probably we have too long input queue, or really stuck */
5051 (void) pthread_mutex_lock(&hup_lock
);
5052 hup_state
|= HUP_SUSP_LOGMSG_REQD
;
5053 (void) pthread_mutex_unlock(&hup_lock
);
5055 for (loop
= 0; loop
< LOOP_MAX
; loop
++) {
5056 if (hup_state
& HUP_LOGMSG_SUSPENDED
)
5060 if ((hup_state
& HUP_LOGMSG_SUSPENDED
) == 0) {
5063 DPRINT2(3, "reconfigure(%u): %.15s: logmsg()"
5064 " does not stop. give up\n",
5065 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5067 logerror("could not suspend logmsg - fatal");
5074 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n",
5075 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5079 * Will wait for LOOP_MAX secs with watching queue lengths for the
5080 * each logger threads. If they have backlogs, and no change in the
5081 * length of queue found in 30 seconds, those will be counted as
5083 * If all running logger threads become "really stuck" state, there
5084 * should be no worth waiting for them to quit.
5085 * In that case, we will go ahead and close out file descriptors to
5086 * have them pull out from hanging system call, and give them a last
5087 * chance(LOOP_INTERVAL sec) to quit.
5092 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be"
5093 " shutdown\n", mythreadno
, ctime_r(&tim
, cbuf
)+4);
5098 while (cnt
< (LOOP_MAX
/LOOP_INTERVAL
) &&
5099 conf_threads
> really_stuck
) {
5101 /* save initial queue count */
5102 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
5103 f
->f_prev_queue_count
= (f
->f_type
== F_UNUSED
) ?
5104 -1 : f
->f_queue_count
;
5107 for (loop
= 0; loop
< LOOP_INTERVAL
; loop
++) {
5108 if (conf_threads
== 0)
5113 if (conf_threads
== 0)
5118 DPRINT3(3, "reconfigure(%u): %.15s: "
5119 "%d threads are still alive.\n",
5120 mythreadno
, ctime_r(&tim
, cbuf
)+4,
5125 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
5126 if (f
->f_type
== F_UNUSED
) {
5127 f
->f_prev_queue_count
= -1;
5130 if (f
->f_prev_queue_count
== f
->f_queue_count
) {
5132 f
->f_prev_queue_count
= 1;
5133 DPRINT2(3, "reconfigure(%u): "
5134 "tid=%d is really stuck.\n",
5135 mythreadno
, f
->f_thread
);
5137 f
->f_prev_queue_count
= 0;
5138 DPRINT2(3, "reconfigure(%u): "
5139 "tid=%d is still active.\n",
5140 mythreadno
, f
->f_thread
);
5144 * Here we have one of following values in the
5145 * f_prev_queue_count:
5146 * 0: logger thread is still actively working.
5147 * 1: logger thread is really stuck.
5148 * -1: logger thread has already died.
5156 DPRINT2(3, "reconfigure(%u): %.15s:"
5157 " complete awaiting logit()\n",
5158 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5159 DPRINT3(3, "reconfigure(%u): %d threads alive."
5160 " %d threads stuck\n",
5161 mythreadno
, conf_threads
, really_stuck
);
5165 * Still running? If so, mark it as UNUSED, and close
5166 * the fd so that logger threads can bail out from the loop.
5170 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
5171 if (f
->f_type
== F_CONSOLE
&&
5172 f
->f_prev_queue_count
== 1) {
5173 /* console is really stuck */
5176 if (f
->f_type
== F_USERS
|| f
->f_type
== F_WALL
||
5177 f
->f_type
== F_UNUSED
)
5179 cnt
= f
->f_queue_count
;
5180 drops
+= (cnt
> 0) ? cnt
- 1: 0;
5181 f
->f_type
= F_UNUSED
;
5183 if (f
->f_orig_type
== F_FORW
)
5184 (void) t_close(f
->f_file
);
5186 (void) close(f
->f_file
);
5191 DPRINT1(3, "reconfigure(%u): terminating logit()\n",
5195 /* last chance to exit */
5196 for (loop
= 0; loop
< LOOP_MAX
; loop
++) {
5197 if (conf_threads
== 0)
5204 DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n",
5205 mythreadno
, ctime_r(&tim
, cbuf
)+4,
5210 if (conf_threads
== 0 && drops
) {
5212 logerror("Could not completely output pending messages"
5213 " while preparing re-configuration");
5214 logerror("discarded %d messages and restart configuration.",
5218 DPRINT3(3, "reconfigure(%u): %.15s: "
5219 "discarded %d messages\n",
5220 mythreadno
, ctime_r(&tim
, cbuf
)+4, drops
);
5225 * If all threads still haven't exited
5226 * something is stuck or hosed. We just
5227 * have no option but to exit.
5233 DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n",
5234 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5241 (void) snprintf(buf
, sizeof (buf
),
5242 "syslogd(%s): some logger thread(s) "
5243 "are stuck%s; syslogd is shutting down.",
5245 console_stuck
? " (including the console)" : "");
5247 if (console_stuck
) {
5248 FILE *m
= popen(MAILCMD
, "w");
5251 (void) fprintf(m
, "%s\n", buf
);
5261 /* Free up some resources */
5262 if (Files
!= (struct filed
*)&fallback
) {
5263 for (f
= Files
; f
< &Files
[nlogs
]; f
++) {
5264 (void) pthread_join(f
->f_thread
, NULL
);
5270 dealloc_stacks(nlogs
);
5274 DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n",
5275 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5278 hnc_init(1); /* purge hostname cache */
5279 conf_init(); /* start reconfigure */
5282 /* Now should be ready to dispatch error messages from syslogd. */
5285 /* Wake up the log thread */
5289 DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n",
5290 mythreadno
, ctime_r(&tim
, cbuf
)+4);
5293 (void) pthread_mutex_lock(&hup_lock
);
5294 hup_state
= HUP_COMPLETED
;
5295 (void) pthread_cond_signal(&hup_done
);
5296 (void) pthread_mutex_unlock(&hup_lock
);
5300 * The following function implements simple hostname cache mechanism.
5301 * Host name cache is implemented through hash table bucket chaining method.
5302 * Collisions are handled by bucket chaining.
5305 * allocate and initialize the cache. If reinit is set,
5306 * invalidate all cache entries.
5308 * It hashes the ipaddress gets the index and walks thru the
5309 * single linked list. if cached entry was found, it will
5310 * put in the head of the list, and return.While going through
5311 * the entries, an entry which has already expired will be invalidated.
5313 * Hashes the ipaddress finds the index and puts current entry to the list.
5315 * invalidate the cachep.
5319 hnc_init(int reinit
)
5321 struct hostname_cache
**hpp
;
5322 pthread_t mythreadno
;
5326 mythreadno
= pthread_self();
5330 (void) pthread_mutex_lock(&hnc_mutex
);
5332 for (i
= 0; i
< hnc_size
; i
++) {
5333 for (hpp
= &hnc_cache
[i
]; *hpp
!= NULL
; ) {
5338 (void) pthread_mutex_unlock(&hnc_mutex
);
5339 DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n",
5343 hnc_cache
= calloc(hnc_size
, sizeof (struct hostname_cache
*));
5345 if (hnc_cache
== NULL
) {
5346 MALLOC_FAIL("hostname cache");
5347 logerror("hostname cache disabled");
5351 DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry"
5352 " ttl:%d\n", mythreadno
, hnc_size
, hnc_ttl
);
5356 static host_list_t
*
5357 hnc_lookup(struct netbuf
*nbp
, struct netconfig
*ncp
, int *hindex
)
5359 struct hostname_cache
**hpp
, *hp
;
5361 pthread_t mythreadno
;
5365 mythreadno
= pthread_self();
5368 if (hnc_cache
== NULL
) {
5372 (void) pthread_mutex_lock(&hnc_mutex
);
5375 *hindex
= index
= addr_hash(nbp
);
5377 for (hpp
= &hnc_cache
[index
]; (hp
= *hpp
) != NULL
; ) {
5378 DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n",
5379 mythreadno
, (void *)hp
->h
, (void *)hp
,
5380 hp
->h
->hl_hosts
[0]);
5382 if (hp
->expire
< now
) {
5383 DPRINT2(9, "hnc_lookup(%u): purge %p\n",
5384 mythreadno
, (void *)hp
);
5389 if (ncp
== hp
->ncp
&& same_addr(&hp
->addr
, nbp
)) {
5392 * Put the entry at the top.
5395 if (hp
!= hnc_cache
[index
]) {
5396 /* unlink from active list */
5397 *hpp
= (*hpp
)->next
;
5398 /* push it onto the top */
5399 hp
->next
= hnc_cache
[index
];
5400 hnc_cache
[index
] = hp
;
5403 (void) pthread_mutex_lock(&hp
->h
->hl_mutex
);
5405 (void) pthread_mutex_unlock(&hp
->h
->hl_mutex
);
5407 DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n",
5408 mythreadno
, (void *)hp
->h
, (void *)hp
,
5409 hp
->h
->hl_hosts
[0]);
5411 (void) pthread_mutex_unlock(&hnc_mutex
);
5418 (void) pthread_mutex_unlock(&hnc_mutex
);
5423 hnc_register(struct netbuf
*nbp
, struct netconfig
*ncp
,
5424 host_list_t
*h
, int hindex
)
5426 struct hostname_cache
**hpp
, **tailp
, *hp
, *entry
;
5429 pthread_t mythreadno
;
5433 mythreadno
= pthread_self();
5436 if (hnc_cache
== NULL
) {
5440 if ((addrbuf
= malloc(nbp
->len
)) == NULL
) {
5441 MALLOC_FAIL("pushing hostname cache");
5445 if ((entry
= malloc(sizeof (struct hostname_cache
))) == NULL
) {
5446 MALLOC_FAIL("pushing hostname entry");
5451 (void) pthread_mutex_lock(&hnc_mutex
);
5457 * first go through active list, and discard the
5458 * caches which has been invalid. Count number of
5459 * non-expired buckets.
5462 for (hpp
= &hnc_cache
[hindex
]; (hp
= *hpp
) != NULL
; ) {
5465 if (hp
->expire
< now
) {
5466 DPRINT2(9, "hnc_register(%u): discard %p\n",
5467 mythreadno
, (void *)hp
);
5476 * If max limit of chained hash buckets has been used up
5477 * delete the least active element in the chain.
5479 if (i
== MAX_BUCKETS
) {
5483 (void) memcpy(addrbuf
, nbp
->buf
, nbp
->len
);
5484 entry
->addr
.len
= nbp
->len
;
5485 entry
->addr
.buf
= addrbuf
;
5488 entry
->expire
= time(NULL
) + hnc_ttl
;
5490 /* insert it at the top */
5491 entry
->next
= hnc_cache
[hindex
];
5492 hnc_cache
[hindex
] = entry
;
5495 * As far as cache is valid, corresponding host_list must
5496 * also be valid. Increments the refcnt to avoid freeing
5500 DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n",
5501 mythreadno
, (void *)entry
->h
, (void *)entry
, entry
->h
->hl_hosts
[0]);
5502 (void) pthread_mutex_unlock(&hnc_mutex
);
5506 hnc_unreg(struct hostname_cache
**hpp
)
5508 struct hostname_cache
*hp
= *hpp
;
5509 pthread_t mythreadno
;
5512 mythreadno
= pthread_self();
5515 DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n",
5516 mythreadno
, (void *)hp
->h
, (void *)hp
, hp
->h
->hl_hosts
[0]);
5520 /* unlink from active list */
5521 *hpp
= (*hpp
)->next
;
5527 * Once this is called, error messages through logerror() will go to
5528 * the console immediately. Also, messages are queued into the tmpq
5529 * to be able to later put them into inputq.
5534 (void) dataq_init(&tmpq
);
5536 (void) pthread_mutex_lock(&logerror_lock
);
5538 (void) pthread_mutex_unlock(&logerror_lock
);
5542 * Turn internal error messages to regular input stream.
5543 * All pending messages are pulled and pushed into the regular
5551 (void) pthread_mutex_lock(&logerror_lock
);
5553 (void) pthread_mutex_unlock(&logerror_lock
);
5556 * push all the pending messages into inputq.
5558 while (dataq_dequeue(&tmpq
, (void **)&mp
, 1) == 0) {
5559 (void) dataq_enqueue(&inputq
, mp
);
5561 (void) dataq_destroy(&tmpq
);
5565 * Generate a hash value of the given address and derive
5566 * an index into the hnc_cache hashtable.
5567 * The hashing method is similar to what Java does for strings.
5570 addr_hash(struct netbuf
*nbp
)
5574 unsigned long hcode
= 0;
5583 * Compute a hashcode of the address string
5585 for (i
= 0; i
< nbp
->len
; i
++)
5586 hcode
= (31 * hcode
) + uap
[i
];
5589 * Scramble the hashcode for better distribution
5591 hcode
+= ~(hcode
<< 9);
5592 hcode
^= (hcode
>> 14);
5593 hcode
+= (hcode
<< 4);
5594 hcode
^= (hcode
>> 10);
5596 return ((int)(hcode
% hnc_size
));