8366 remove warlock leftovers from usr/src/cmd and usr/src/lib
[unleashed.git] / usr / src / cmd / syslogd / syslogd.c
blobf3489f02dbb9c8110d35c2df725e9cd91b19ee41
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
30 * All Rights Reserved
34 * University Copyright- Copyright (c) 1982, 1986, 1988
35 * The Regents of the University of California
36 * All Rights Reserved
38 * University Acknowledgment- Portions of this document are derived from
39 * software developed by the University of California, Berkeley, and its
40 * contributors.
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.
54 * Defined Constants:
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.
62 #include <unistd.h>
63 #include <errno.h>
64 #include <sys/types.h>
65 #include <stdio.h>
66 #include <stdio_ext.h>
67 #include <stdlib.h>
68 #include <ctype.h>
69 #include <signal.h>
70 #include <string.h>
71 #include <strings.h>
72 #include <libscf.h>
73 #include <netconfig.h>
74 #include <netdir.h>
75 #include <pwd.h>
76 #include <sys/socket.h>
77 #include <tiuser.h>
78 #include <utmpx.h>
79 #include <limits.h>
80 #include <pthread.h>
81 #include <fcntl.h>
82 #include <stropts.h>
83 #include <assert.h>
84 #include <sys/statvfs.h>
86 #include <sys/param.h>
87 #include <sys/sysmacros.h>
88 #include <sys/syslog.h>
89 #include <sys/strlog.h>
90 #include <sys/stat.h>
91 #include <sys/time.h>
92 #include <sys/utsname.h>
93 #include <sys/poll.h>
94 #include <sys/wait.h>
95 #include <sys/resource.h>
96 #include <sys/mman.h>
97 #include <door.h>
99 #include <wchar.h>
100 #include <locale.h>
101 #include <stdarg.h>
103 #include "dataq.h"
104 #include "conf.h"
105 #include "syslogd.h"
107 #define DOORFILE "/var/run/syslog_door"
108 #define RELATIVE_DOORFILE "../var/run/syslog_door"
109 #define OLD_DOORFILE "/etc/.syslog_door"
111 #define PIDFILE "/var/run/syslog.pid"
112 #define RELATIVE_PIDFILE "../var/run/syslog.pid"
113 #define OLD_PIDFILE "/etc/syslog.pid"
115 static char *LogName = "/dev/log";
116 static char *ConfFile = "/etc/syslog.conf";
117 static char ctty[] = "/dev/console";
118 static char sysmsg[] = "/dev/sysmsg";
119 static int DoorFd = -1;
120 static int DoorCreated = 0;
121 static int PidfileCreated = 0;
122 static char *DoorFileName = DOORFILE;
123 static char *PidFileName = PIDFILE;
126 * configuration file directives
129 static struct code PriNames[] = {
130 "panic", LOG_EMERG,
131 "emerg", LOG_EMERG,
132 "alert", LOG_ALERT,
133 "crit", LOG_CRIT,
134 "err", LOG_ERR,
135 "error", LOG_ERR,
136 "warn", LOG_WARNING,
137 "warning", LOG_WARNING,
138 "notice", LOG_NOTICE,
139 "info", LOG_INFO,
140 "debug", LOG_DEBUG,
141 "none", NOPRI,
142 NULL, -1
145 static struct code FacNames[] = {
146 "kern", LOG_KERN,
147 "user", LOG_USER,
148 "mail", LOG_MAIL,
149 "daemon", LOG_DAEMON,
150 "auth", LOG_AUTH,
151 "security", LOG_AUTH,
152 "mark", LOG_MARK,
153 "syslog", LOG_SYSLOG,
154 "lpr", LOG_LPR,
155 "news", LOG_NEWS,
156 "uucp", LOG_UUCP,
157 "altcron", LOG_ALTCRON,
158 "authpriv", LOG_AUTHPRIV,
159 "ftp", LOG_FTP,
160 "ntp", LOG_NTP,
161 "audit", LOG_AUDIT,
162 "console", LOG_CONSOLE,
163 "cron", LOG_CRON,
164 "local0", LOG_LOCAL0,
165 "local1", LOG_LOCAL1,
166 "local2", LOG_LOCAL2,
167 "local3", LOG_LOCAL3,
168 "local4", LOG_LOCAL4,
169 "local5", LOG_LOCAL5,
170 "local6", LOG_LOCAL6,
171 "local7", LOG_LOCAL7,
172 NULL, -1
175 static char *TypeNames[7] = {
176 "UNUSED", "FILE", "TTY", "CONSOLE",
177 "FORW", "USERS", "WALL"
181 * we allocate our own thread stacks so we can create them
182 * without the MAP_NORESERVE option. We need to be sure
183 * we have stack space even if the machine runs out of swap
186 #define DEFAULT_STACKSIZE (100 * 1024) /* 100 k stack */
187 #define DEFAULT_REDZONESIZE (8 * 1024) /* 8k redzone */
189 static pthread_mutex_t wmp = PTHREAD_MUTEX_INITIALIZER; /* wallmsg lock */
191 static pthread_mutex_t cft = PTHREAD_MUTEX_INITIALIZER;
192 static int conf_threads = 0;
194 static pthread_mutex_t hup_lock = PTHREAD_MUTEX_INITIALIZER;
195 static pthread_cond_t hup_done = PTHREAD_COND_INITIALIZER;
197 static pthread_mutex_t logerror_lock = PTHREAD_MUTEX_INITIALIZER;
199 #define HUP_ACCEPTABLE 0x0000 /* can start SIGHUP process */
200 #define HUP_INPROGRESS 0x0001 /* SIGHUP process in progress */
201 #define HUP_COMPLETED 0x0002 /* SIGHUP process completed */
202 #define HUP_SUSP_LOGMSG_REQD 0x1000 /* request to suspend */
203 #define HUP_LOGMSG_SUSPENDED 0x2000 /* logmsg is suspended */
204 static int hup_state = HUP_ACCEPTABLE;
206 static size_t stacksize; /* thread stack size */
207 static size_t redzonesize; /* thread stack redzone size */
208 static char *stack_ptr; /* ptr to allocated stacks */
209 static char *cstack_ptr; /* ptr to conf_thr stacks */
211 static time_t start_time;
213 static pthread_t sys_thread; /* queues messages from us */
214 static pthread_t net_thread; /* queues messages from the net */
215 static pthread_t log_thread; /* message processing thread */
216 static pthread_t hnl_thread; /* hostname lookup thread */
218 static dataq_t inputq; /* the input queue */
219 static dataq_t tmpq; /* temporary queue for err msg */
220 static dataq_t hnlq; /* hostname lookup queue */
222 static struct filed fallback[2];
223 static struct filed *Files;
224 static int nlogs;
225 static int Debug; /* debug flag */
226 static host_list_t LocalHostName; /* our hostname */
227 static host_list_t NullHostName; /* in case of lookup failure */
228 static int debuglev = 1; /* debug print level */
229 static int interrorlog; /* internal error logging */
231 static int MarkInterval = 20; /* interval between marks (mins) */
232 static int Marking = 0; /* non-zero if marking some file */
233 static int Ninputs = 0; /* number of network inputs */
234 static int curalarm = 0; /* current timeout value (secs) */
235 static int sys_msg_count = 0; /* total msgs rcvd from local log */
236 static int sys_init_msg_count = 0; /* initially received */
237 static int net_msg_count = 0; /* total msgs rcvd from net */
239 static struct pollfd Pfd; /* Pollfd for local the log device */
240 static struct pollfd *Nfd; /* Array of pollfds for udp ports */
241 static struct netconfig *Ncf;
242 static struct netbuf **Myaddrs;
243 static struct t_unitdata **Udp;
244 static struct t_uderr **Errp;
245 static int turnoff = 0;
246 static int shutting_down;
248 /* for managing door server threads */
249 static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
250 static uint_t door_server_cnt = 0;
251 static pthread_attr_t door_thr_attr;
253 static struct hostname_cache **hnc_cache;
254 static pthread_mutex_t hnc_mutex = PTHREAD_MUTEX_INITIALIZER;
255 static size_t hnc_size = DEF_HNC_SIZE;
256 static unsigned int hnc_ttl = DEF_HNC_TTL;
258 #define DPRINT0(d, m) if ((Debug) && debuglev >= (d)) \
259 (void) fprintf(stderr, m)
260 #define DPRINT1(d, m, a) if ((Debug) && debuglev >= (d)) \
261 (void) fprintf(stderr, m, a)
262 #define DPRINT2(d, m, a, b) if ((Debug) && debuglev >= (d)) \
263 (void) fprintf(stderr, m, a, b)
264 #define DPRINT3(d, m, a, b, c) if ((Debug) && debuglev >= (d)) \
265 (void) fprintf(stderr, m, a, b, c)
266 #define DPRINT4(d, m, a, b, c, e) if ((Debug) && debuglev >= (d)) \
267 (void) fprintf(stderr, m, a, b, c, e)
268 #define MALLOC_FAIL(x) \
269 logerror("malloc failed: " x)
270 #define MALLOC_FAIL_EXIT \
271 logerror("malloc failed - fatal"); \
272 exit(1)
275 #define MAILCMD "mailx -s \"syslogd shut down\" root"
278 * Number of seconds to wait before giving up on threads that won't
279 * shutdown: (that's right, 10 minutes!)
281 #define LOOP_MAX (10 * 60)
284 * Interval(sec) to check the status of output queue while processing
285 * HUP signal.
287 #define LOOP_INTERVAL (15)
290 main(int argc, char **argv)
292 int i;
293 char *pstr;
294 int sig, fd;
295 int tflag = 0, Tflag = 0;
296 sigset_t sigs, allsigs;
297 struct rlimit rlim;
298 char *debugstr;
299 int mcount = 0;
300 struct sigaction act;
301 pthread_t mythreadno = 0;
302 char cbuf [30];
303 struct stat sb;
305 #ifdef DEBUG
306 #define DEBUGDIR "/var/tmp"
307 if (chdir(DEBUGDIR))
308 DPRINT2(1, "main(%u): Unable to cd to %s\n", mythreadno,
309 DEBUGDIR);
310 #endif /* DEBUG */
312 (void) setlocale(LC_ALL, "");
314 if ((debugstr = getenv("SYSLOGD_DEBUG")) != NULL)
315 if ((debuglev = atoi(debugstr)) == 0)
316 debuglev = 1;
318 #if ! defined(TEXT_DOMAIN) /* should be defined by cc -D */
319 #define TEXT_DOMAIN "SYS_TEST"
320 #endif
321 (void) textdomain(TEXT_DOMAIN);
323 (void) time(&start_time);
325 if (lstat("/var/run", &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
326 DoorFileName = OLD_DOORFILE;
327 PidFileName = OLD_PIDFILE;
330 properties();
332 while ((i = getopt(argc, argv, "df:p:m:tT")) != EOF) {
333 switch (i) {
334 case 'f': /* configuration file */
335 ConfFile = optarg;
336 break;
338 case 'd': /* debug */
339 Debug++;
340 break;
342 case 'p': /* path */
343 LogName = optarg;
344 break;
346 case 'm': /* mark interval */
347 for (pstr = optarg; *pstr; pstr++) {
348 if (! (isdigit(*pstr))) {
349 (void) fprintf(stderr,
350 "Illegal interval\n");
351 usage();
354 MarkInterval = atoi(optarg);
355 if (MarkInterval < 1 || MarkInterval > INT_MAX) {
356 (void) fprintf(stderr,
357 "Interval must be between 1 and %d\n",
358 INT_MAX);
359 usage();
361 break;
362 case 't': /* turn off remote reception */
363 tflag++;
364 turnoff++;
365 break;
366 case 'T': /* turn on remote reception */
367 Tflag++;
368 turnoff = 0;
369 break;
370 default:
371 usage();
375 if (optind < argc)
376 usage();
378 if (tflag && Tflag) {
379 (void) fprintf(stderr, "specify only one of -t and -T\n");
380 usage();
384 * close all fd's except 0-2
387 closefrom(3);
389 if (!Debug) {
390 if (fork())
391 return (0);
392 (void) close(0);
393 (void) open("/", 0);
394 (void) dup2(0, 1);
395 (void) dup2(0, 2);
396 untty();
399 if (Debug) {
400 mythreadno = pthread_self();
404 * DO NOT call logerror() until tmpq is initialized.
406 disable_errorlog();
409 * ensure that file descriptor limit is "high enough"
411 (void) getrlimit(RLIMIT_NOFILE, &rlim);
412 if (rlim.rlim_cur < rlim.rlim_max)
413 rlim.rlim_cur = rlim.rlim_max;
414 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
415 logerror("Unable to increase file descriptor limit.");
416 (void) enable_extended_FILE_stdio(-1, -1);
418 /* block all signals from all threads initially */
419 (void) sigfillset(&allsigs);
420 (void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL);
422 DPRINT2(1, "main(%u): Started at time %s", mythreadno,
423 ctime_r(&start_time, cbuf));
425 init(); /* read configuration, start threads */
427 DPRINT1(1, "main(%u): off & running....\n", mythreadno);
429 /* now set up to catch signals we care about */
431 (void) sigemptyset(&sigs);
432 (void) sigaddset(&sigs, SIGHUP); /* reconfigure */
433 (void) sigaddset(&sigs, SIGALRM); /* mark & flush timer */
434 (void) sigaddset(&sigs, SIGTERM); /* exit */
435 (void) sigaddset(&sigs, SIGINT); /* exit if debugging */
436 (void) sigaddset(&sigs, SIGQUIT); /* exit if debugging */
437 (void) sigaddset(&sigs, SIGPIPE); /* catch & discard */
438 (void) sigaddset(&sigs, SIGUSR1); /* dump debug stats */
441 * We must set up to catch these signals, even though sigwait
442 * will get them before the isr does. Setting SA_SIGINFO ensures
443 * that signals will be enqueued.
446 act.sa_flags = SA_SIGINFO;
447 act.sa_sigaction = signull;
449 (void) sigaction(SIGHUP, &act, NULL);
450 (void) sigaction(SIGALRM, &act, NULL);
451 (void) sigaction(SIGTERM, &act, NULL);
452 (void) sigaction(SIGINT, &act, NULL);
453 (void) sigaction(SIGQUIT, &act, NULL);
454 (void) sigaction(SIGPIPE, &act, NULL);
455 (void) sigaction(SIGUSR1, &act, NULL);
457 /* we now turn into the signal handling thread */
459 DPRINT1(2, "main(%u): now handling signals\n", mythreadno);
460 for (;;) {
461 (void) sigwait(&sigs, &sig);
462 DPRINT2(2, "main(%u): received signal %d\n", mythreadno, sig);
463 switch (sig) {
464 case SIGALRM:
465 DPRINT1(1, "main(%u): Got SIGALRM\n",
466 mythreadno);
467 flushmsg(NOCOPY);
468 if (Marking && (++mcount % MARKCOUNT == 0)) {
469 if (logmymsg(LOG_INFO, "-- MARK --",
470 ADDDATE|MARK|NOCOPY, 0) == -1) {
471 MALLOC_FAIL(
472 "dropping MARK message");
475 mcount = 0;
477 curalarm = MarkInterval * 60 / MARKCOUNT;
478 (void) alarm((unsigned)curalarm);
479 DPRINT2(2, "main(%u): Next alarm in %d "
480 "seconds\n", mythreadno, curalarm);
481 break;
482 case SIGHUP:
483 DPRINT1(1, "main(%u): got SIGHUP - "
484 "reconfiguring\n", mythreadno);
486 reconfigure();
488 DPRINT1(1, "main(%u): done processing SIGHUP\n",
489 mythreadno);
490 break;
491 case SIGQUIT:
492 case SIGINT:
493 if (!Debug) {
494 /* allow these signals if debugging */
495 break;
497 /* FALLTHROUGH */
498 case SIGTERM:
499 DPRINT2(1, "main(%u): going down on signal %d\n",
500 mythreadno, sig);
501 (void) alarm(0);
502 flushmsg(0);
503 errno = 0;
504 t_errno = 0;
505 logerror("going down on signal %d", sig);
506 disable_errorlog(); /* force msg to console */
507 (void) shutdown_msg(); /* stop threads */
508 shutdown_input();
509 close_door();
510 delete_doorfiles();
511 return (0);
512 case SIGUSR1: /* secret debug dump mode */
513 /* if in debug mode, use stdout */
515 if (Debug) {
516 dumpstats(STDOUT_FILENO);
517 break;
519 /* otherwise dump to a debug file */
520 if ((fd = open(DEBUGFILE,
521 (O_WRONLY|O_CREAT|O_TRUNC|O_EXCL),
522 0644)) < 0)
523 break;
524 dumpstats(fd);
525 (void) close(fd);
526 break;
527 default:
528 DPRINT2(2, "main(%u): unexpected signal %d\n",
529 mythreadno, sig);
530 break;
536 * Attempts to open the local log device
537 * and return a file descriptor.
539 static int
540 openklog(char *name, int mode)
542 int fd;
543 struct strioctl str;
544 pthread_t mythreadno;
546 if (Debug) {
547 mythreadno = pthread_self();
550 if ((fd = open(name, mode)) < 0) {
551 logerror("cannot open %s", name);
552 DPRINT3(1, "openklog(%u): cannot create %s (%d)\n",
553 mythreadno, name, errno);
554 return (-1);
556 str.ic_cmd = I_CONSLOG;
557 str.ic_timout = 0;
558 str.ic_len = 0;
559 str.ic_dp = NULL;
560 if (ioctl(fd, I_STR, &str) < 0) {
561 logerror("cannot register to log console messages");
562 DPRINT2(1, "openklog(%u): cannot register to log "
563 "console messages (%d)\n", mythreadno, errno);
564 return (-1);
566 return (fd);
571 * Open the log device, and pull up all pending messages.
573 static void
574 prepare_sys_poll()
576 int nfds, funix;
578 if ((funix = openklog(LogName, O_RDONLY)) < 0) {
579 logerror("can't open kernel log device - fatal");
580 exit(1);
583 Pfd.fd = funix;
584 Pfd.events = POLLIN;
586 for (;;) {
587 nfds = poll(&Pfd, 1, 0);
588 if (nfds <= 0) {
589 if (sys_init_msg_count > 0)
590 flushmsg(SYNC_FILE);
591 break;
594 if (Pfd.revents & POLLIN) {
595 getkmsg(0);
596 } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
597 logerror("kernel log driver poll error");
598 break;
605 * this thread listens to the local stream log driver for log messages
606 * generated by this host, formats them, and queues them to the logger
607 * thread.
609 /*ARGSUSED*/
610 static void *
611 sys_poll(void *ap)
613 int nfds;
614 static int klogerrs = 0;
615 pthread_t mythreadno;
617 if (Debug) {
618 mythreadno = pthread_self();
621 DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno);
624 * Process messages, blocking on poll because timeout is set
625 * to INFTIM. When poll returns with a message, call getkmsg
626 * to pull up one message from the log driver and enqueue it
627 * with the sync flag set.
630 sys_init_msg_count = 0;
632 for (;;) {
633 errno = 0;
634 t_errno = 0;
636 nfds = poll(&Pfd, 1, INFTIM);
638 if (nfds == 0)
639 continue;
641 if (nfds < 0) {
642 if (errno != EINTR)
643 logerror("poll");
644 continue;
646 if (Pfd.revents & POLLIN) {
647 getkmsg(INFTIM);
648 } else {
649 if (shutting_down) {
650 pthread_exit(0);
652 if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
653 logerror("kernel log driver poll error");
654 (void) close(Pfd.fd);
655 Pfd.fd = -1;
659 while (Pfd.fd == -1 && klogerrs++ < 10) {
660 Pfd.fd = openklog(LogName, O_RDONLY);
662 if (klogerrs >= 10) {
663 logerror("can't reopen kernel log device - fatal");
664 exit(1);
667 /*NOTREACHED*/
668 return (NULL);
672 * Pull up one message from log driver.
674 static void
675 getkmsg(int timeout)
677 int flags = 0, i;
678 char *lastline;
679 struct strbuf ctl, dat;
680 struct log_ctl hdr;
681 char buf[MAXLINE+1];
682 size_t buflen;
683 size_t len;
684 char tmpbuf[MAXLINE+1];
685 pthread_t mythreadno;
687 if (Debug) {
688 mythreadno = pthread_self();
691 dat.maxlen = MAXLINE;
692 dat.buf = buf;
693 ctl.maxlen = sizeof (struct log_ctl);
694 ctl.buf = (caddr_t)&hdr;
696 while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
697 lastline = &dat.buf[dat.len];
698 *lastline = '\0';
700 DPRINT2(5, "getkmsg:(%u): getmsg: dat.len = %d\n",
701 mythreadno, dat.len);
702 buflen = strlen(buf);
703 len = findnl_bkwd(buf, buflen);
705 (void) memcpy(tmpbuf, buf, len);
706 tmpbuf[len] = '\0';
709 * Format sys will enqueue the log message.
710 * Set the sync flag if timeout != 0, which
711 * means that we're done handling all the
712 * initial messages ready during startup.
714 if (timeout == 0) {
715 formatsys(&hdr, tmpbuf, 0);
716 sys_init_msg_count++;
717 } else {
718 formatsys(&hdr, tmpbuf, 1);
720 sys_msg_count++;
722 if (len != buflen) {
723 /* If anything remains in buf */
724 size_t remlen;
726 if (buf[len] == '\n') {
727 /* skip newline */
728 len++;
732 * Move the remaining bytes to
733 * the beginnning of buf.
736 remlen = buflen - len;
737 (void) memcpy(buf, &buf[len], remlen);
738 dat.maxlen = MAXLINE - remlen;
739 dat.buf = &buf[remlen];
740 } else {
741 dat.maxlen = MAXLINE;
742 dat.buf = buf;
746 if (i == 0 && dat.len > 0) {
747 dat.buf[dat.len] = '\0';
749 * Format sys will enqueue the log message.
750 * Set the sync flag if timeout != 0, which
751 * means that we're done handling all the
752 * initial messages ready during startup.
754 DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n",
755 mythreadno, dat.maxlen);
756 DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n",
757 mythreadno, dat.len);
758 DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n",
759 mythreadno, strlen(dat.buf));
760 DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n",
761 mythreadno, dat.buf);
762 DPRINT2(5, "getkmsg(%u): buf len = %d\n",
763 mythreadno, strlen(buf));
764 if (timeout == 0) {
765 formatsys(&hdr, buf, 0);
766 sys_init_msg_count++;
767 } else {
768 formatsys(&hdr, buf, 1);
770 sys_msg_count++;
771 } else if (i < 0 && errno != EINTR) {
772 if (!shutting_down) {
773 logerror("kernel log driver read error");
775 (void) close(Pfd.fd);
776 Pfd.fd = -1;
781 * this thread polls all the network interfaces for syslog messages
782 * forwarded to us, tags them with the hostname they are received
783 * from, and queues them to the logger thread.
785 /*ARGSUSED*/
786 static void *
787 net_poll(void *ap)
789 int nfds, i;
790 int flags = 0;
791 struct t_unitdata *udp;
792 struct t_uderr *errp;
793 char buf[MAXLINE+1];
794 char *uap;
795 log_message_t *mp;
796 host_info_t *hinfo;
797 pthread_t mythreadno;
799 if (Debug) {
800 mythreadno = pthread_self();
803 DPRINT1(1, "net_poll(%u): net_thread started\n", mythreadno);
805 for (;;) {
806 errno = 0;
807 t_errno = 0;
808 nfds = poll(Nfd, Ninputs, -1);
809 if (nfds == 0)
810 continue;
812 if (nfds < 0) {
813 if (errno != EINTR)
814 logerror("poll");
815 continue;
817 for (i = 0; nfds > 0 && i < Ninputs; i++) {
818 if ((Nfd[i].revents & POLLIN) == 0) {
819 if (shutting_down) {
820 pthread_exit(0);
822 if (Nfd[i].revents &
823 (POLLNVAL|POLLHUP|POLLERR)) {
824 logerror("POLLNVAL|POLLHUP|POLLERR");
825 (void) t_close(Nfd[i].fd);
826 Nfd[i].fd = -1;
827 nfds--;
829 continue;
832 udp = Udp[i];
833 udp->udata.buf = buf;
834 udp->udata.maxlen = MAXLINE;
835 udp->udata.len = 0;
836 flags = 0;
837 if (t_rcvudata(Nfd[i].fd, udp, &flags) < 0) {
838 errp = Errp[i];
839 if (t_errno == TLOOK) {
840 if (t_rcvuderr(Nfd[i].fd, errp) < 0) {
841 if (!shutting_down) {
842 logerror("t_rcvuderr");
844 (void) t_close(Nfd[i].fd);
845 Nfd[i].fd = -1;
847 } else {
848 if (!shutting_down) {
849 logerror("t_rcvudata");
851 (void) t_close(Nfd[i].fd);
852 Nfd[i].fd = -1;
854 nfds--;
855 if (shutting_down) {
856 pthread_exit(0);
858 continue;
860 nfds--;
862 if (udp->udata.len == 0) {
863 if (Debug) {
864 uap = NULL;
865 if (udp->addr.len > 0) {
866 uap = taddr2uaddr(&Ncf[i],
867 &udp->addr);
869 DPRINT2(1, "net_poll(%u):"
870 " received empty packet"
871 " from %s\n", mythreadno,
872 uap ? uap : "<unknown>");
873 if (uap)
874 free(uap);
876 continue; /* No data */
878 if (udp->addr.len == 0) {
880 * The previous message was larger than
881 * MAXLINE, and T_MORE should have been set.
882 * Further data needs to be discarded as
883 * we've already received MAXLINE.
885 DPRINT1(1, "net_poll(%u): discarding packet "
886 "exceeds max line size\n", mythreadno);
887 continue;
890 net_msg_count++;
892 if ((mp = new_msg()) == NULL) {
893 MALLOC_FAIL("dropping message from "
894 "remote");
895 continue;
898 buf[udp->udata.len] = '\0';
899 formatnet(&udp->udata, mp);
901 if (Debug) {
902 uap = taddr2uaddr(&Ncf[i], &udp->addr);
903 DPRINT2(1, "net_poll(%u): received message"
904 " from %s\n", mythreadno,
905 uap ? uap : "<unknown>");
906 free(uap);
908 if ((hinfo = malloc(sizeof (*hinfo))) == NULL ||
909 (hinfo->addr.buf =
910 malloc(udp->addr.len)) == NULL) {
911 MALLOC_FAIL("dropping message from "
912 "remote");
913 if (hinfo) {
914 free(hinfo);
916 free_msg(mp);
917 continue;
920 hinfo->ncp = &Ncf[i];
921 hinfo->addr.len = udp->addr.len;
922 (void) memcpy(hinfo->addr.buf, udp->addr.buf,
923 udp->addr.len);
924 mp->ptr = hinfo;
925 if (dataq_enqueue(&hnlq, (void *)mp) == -1) {
926 MALLOC_FAIL("dropping message from "
927 "remote");
928 free_msg(mp);
929 free(hinfo->addr.buf);
930 free(hinfo);
931 continue;
933 DPRINT3(5, "net_poll(%u): enqueued msg %p "
934 "on queue %p\n", mythreadno, (void *)mp,
935 (void *)&hnlq);
938 /*NOTREACHED*/
939 return (NULL);
942 static void
943 usage(void)
945 (void) fprintf(stderr,
946 "usage: syslogd [-d] [-t|-T] [-mmarkinterval] [-ppath]"
947 " [-fconffile]\n");
948 exit(1);
951 static void
952 untty(void)
954 if (!Debug)
955 (void) setsid();
959 * generate a log message internally. The original version of syslogd
960 * simply called logmsg directly, but because everything is now based
961 * on message passing, we need an internal way to generate and queue
962 * log messages from within syslogd itself.
964 static int
965 logmymsg(int pri, char *msg, int flags, int pending)
967 log_message_t *mp;
968 pthread_t mythreadno;
969 dataq_t *qptr;
971 if (Debug) {
972 mythreadno = pthread_self();
975 if ((mp = new_msg()) == NULL) {
976 return (-1);
979 mp->pri = pri;
980 mp->hlp = &LocalHostName;
981 (void) strlcpy(mp->msg, msg, MAXLINE+1);
982 mp->flags = flags;
983 (void) time(&mp->ts);
985 qptr = pending ? &tmpq : &inputq;
986 if (dataq_enqueue(qptr, (void *)mp) == -1) {
987 free_msg(mp);
988 return (-1);
991 DPRINT3(5, "logmymsg(%u): enqueued msg %p on queue %p\n",
992 mythreadno, (void *)mp, (void *)qptr);
993 DPRINT2(5, "logmymsg(%u): Message content: %s\n", mythreadno, msg);
994 return (0);
998 * Generate an internal shutdown message
1000 static int
1001 shutdown_msg(void)
1003 pthread_t mythreadno;
1004 log_message_t *mp;
1006 if (Debug) {
1007 mythreadno = pthread_self();
1010 if ((mp = new_msg()) == NULL) {
1011 return (-1);
1014 mp->flags = SHUTDOWN;
1015 mp->hlp = &LocalHostName;
1017 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1018 free_msg(mp);
1019 return (-1);
1022 DPRINT3(5, "shutdown_msg(%u): enqueued msg %p on queue %p\n",
1023 mythreadno, (void *)mp, (void *)&inputq);
1024 return (0);
1028 * Generate an internal flush message
1030 static void
1031 flushmsg(int flags)
1033 log_message_t *mp;
1034 pthread_t mythreadno;
1036 if (Debug) {
1037 mythreadno = pthread_self();
1040 if ((mp = new_msg()) == NULL) {
1041 MALLOC_FAIL("dropping flush msg");
1042 return;
1045 mp->flags = FLUSHMSG | flags;
1046 mp->hlp = &LocalHostName;
1048 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1049 free_msg(mp);
1050 MALLOC_FAIL("dropping flush msg");
1051 return;
1054 DPRINT4(5, "flush_msg(%u): enqueued msg %p on queue %p, flags "
1055 "0x%x\n", mythreadno, (void *)mp, (void *)&inputq, flags);
1059 * Do some processing on messages received from the net
1061 static void
1062 formatnet(struct netbuf *nbp, log_message_t *mp)
1064 char *p;
1065 int pri;
1066 pthread_t mythreadno;
1068 if (Debug) {
1069 mythreadno = pthread_self();
1072 DPRINT2(5, "formatnet(%u): called for msg %p\n", mythreadno,
1073 (void *)mp);
1075 mp->flags = NETWORK;
1076 (void) time(&mp->ts);
1078 /* test for special codes */
1079 pri = DEFUPRI;
1080 p = nbp->buf;
1081 DPRINT2(9, "formatnet(%u): Message content:\n>%s<\n", mythreadno,
1083 if (*p == '<' && isdigit(*(p+1))) {
1084 pri = 0;
1085 while (isdigit(*++p))
1086 pri = 10 * pri + (*p - '0');
1087 if (*p == '>')
1088 ++p;
1089 if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
1090 pri = DEFUPRI;
1093 mp->pri = pri;
1094 (void) strlcpy(mp->msg, p, MAXLINE+1);
1098 * Do some processing on messages generated by this host
1099 * and then enqueue the log message.
1101 static void
1102 formatsys(struct log_ctl *lp, char *msg, int sync)
1104 char *p, *q;
1105 char line[MAXLINE + 1];
1106 size_t msglen;
1107 log_message_t *mp;
1108 char cbuf[30];
1109 pthread_t mythreadno;
1111 if (Debug) {
1112 mythreadno = pthread_self();
1115 DPRINT3(3, "formatsys(%u): log_ctl.mid = %d, log_ctl.sid = %d\n",
1116 mythreadno, lp->mid, lp->sid);
1117 DPRINT2(9, "formatsys(%u): Message Content:\n>%s<\n", mythreadno,
1118 msg);
1120 /* msglen includes the null termination */
1121 msglen = strlen(msg) + 1;
1123 for (p = msg; *p != '\0'; ) {
1124 size_t linelen;
1125 size_t len;
1128 * Allocate a log_message_t structure.
1129 * We should do it here since a single message (msg)
1130 * could be composed of many lines.
1132 if ((mp = new_msg()) == NULL) {
1133 MALLOC_FAIL("dropping message");
1135 * Should bail out from the loop.
1137 break;
1140 mp->flags &= ~NETWORK;
1141 mp->hlp = &LocalHostName;
1142 mp->ts = lp->ttime;
1143 if (lp->flags & SL_LOGONLY)
1144 mp->flags |= IGN_CONS;
1145 if (lp->flags & SL_CONSONLY)
1146 mp->flags |= IGN_FILE;
1148 /* extract facility */
1149 if ((lp->pri & LOG_FACMASK) == LOG_KERN) {
1150 (void) sprintf(line, "%.15s ",
1151 ctime_r(&mp->ts, cbuf) + 4);
1152 } else {
1153 (void) sprintf(line, "");
1156 linelen = strlen(line);
1157 q = line + linelen;
1159 DPRINT2(5, "formatsys(%u): msglen = %d\n", mythreadno, msglen);
1160 len = copynl_frwd(q, MAXLINE + 1 - linelen, p, msglen);
1161 DPRINT2(5, "formatsys(%u): len (copynl_frwd) = %d\n",
1162 mythreadno, len);
1164 p += len;
1165 msglen -= len;
1167 if (*p == '\n') {
1168 /* skip newline */
1169 p++;
1172 if (sync && ((lp->pri & LOG_FACMASK) == LOG_KERN))
1173 mp->flags |= SYNC_FILE; /* fsync file after write */
1175 if (len != 0) {
1176 (void) strlcpy(mp->msg, line, MAXLINE+1);
1177 mp->pri = lp->pri;
1179 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1180 free_msg(mp);
1181 MALLOC_FAIL("dropping message");
1182 break;
1185 DPRINT3(5, "formatsys(%u): sys_thread enqueued msg "
1186 "%p on queue %p\n", mythreadno, (void *)mp,
1187 (void *)&inputq);
1188 } else
1189 free_msg(mp);
1194 * Log a message to the appropriate log files, users, etc. based on
1195 * the priority.
1197 /*ARGSUSED*/
1198 static void *
1199 logmsg(void *ap)
1201 struct filed *f;
1202 int fac, prilev, flags, refcnt;
1203 int fake_shutdown, skip_shutdown;
1204 log_message_t *mp, *save_mp;
1205 pthread_t mythreadno;
1207 if (Debug) {
1208 mythreadno = pthread_self();
1211 DPRINT1(1, "logmsg(%u): msg dispatcher started\n", mythreadno);
1213 fake_shutdown = skip_shutdown = 0;
1214 save_mp = NULL;
1215 for (;;) {
1216 if (save_mp) {
1218 * If we have set aside a message in order to fake a
1219 * SHUTDOWN, use that message before picking from the
1220 * queue again.
1222 mp = save_mp;
1223 save_mp = NULL;
1224 } else {
1225 (void) dataq_dequeue(&inputq, (void **)&mp, 0);
1227 DPRINT3(5, "logmsg(%u): msg dispatcher dequeued %p from "
1228 "queue %p\n", mythreadno, (void *)mp,
1229 (void *)&inputq);
1232 * In most cases, if the message traffic is low, logmsg() wakes
1233 * up when it receives the SHUTDOWN msg, and will sleep until
1234 * HUP process is complete. However, if the inputq is too
1235 * long, logmsg() may not receive SHUTDOWN before reconfigure()
1236 * releases the logger fds, filed and logit threads. That, in
1237 * turn, will cause logmsg to refer to invalid fileds.
1239 * logmsg() needs to respond to the SHUTDOWN message within
1240 * LOOP_INTERVAL seconds when reconfigure() enqueues it. It
1241 * does so in most cases. When it does not respond in time,
1242 * logmsg() needs to be in suspended state immediately, since
1243 * filed may have been invalidated. reconfigure() will set the
1244 * HUP_SUSP_LOGMSG_REQD bit in hup_state and wait another
1245 * LOOP_INTERVAL seconds before proceeding.
1247 * When HUP_SUSP_LOGMSG_REQD is set, we will create a fake
1248 * SHUTDOWN message, and dispatch it to the various logit
1249 * threads, and logmsg() itself will suspend. In order to
1250 * ignore the real SHUTDOWN which will arrive later, we keep a
1251 * counter (skip_shutdown) and decrement it when the SHUTDOWN
1252 * message arrives.
1254 if ((hup_state & HUP_SUSP_LOGMSG_REQD) &&
1255 (mp->flags & SHUTDOWN) == 0) {
1256 DPRINT1(3, "logmsg(%u): suspend request\n",
1257 mythreadno);
1259 save_mp = mp;
1261 /* create a fake SHUTDOWN msg */
1262 if ((mp = new_msg()) == NULL) {
1263 MALLOC_FAIL("dropping message");
1264 if (mp->flags & SHUTDOWN) {
1265 (void) logerror_to_console(1,
1266 "unable to shutdown "
1267 "logger thread");
1269 continue;
1271 mp->flags = SHUTDOWN;
1272 mp->hlp = &LocalHostName;
1273 fake_shutdown = 1;
1274 skip_shutdown++;
1275 DPRINT2(3, "logmsg(%u): pending SHUTDOWN %d\n",
1276 mythreadno, skip_shutdown);
1280 * is it a shutdown or flush message ?
1282 if ((mp->flags & SHUTDOWN) || (mp->flags & FLUSHMSG)) {
1283 (void) pthread_mutex_lock(&mp->msg_mutex);
1285 if ((mp->flags & SHUTDOWN) &&
1286 !fake_shutdown && skip_shutdown > 0) {
1287 skip_shutdown--;
1288 (void) pthread_mutex_unlock(&mp->msg_mutex);
1289 free_msg(mp);
1290 DPRINT2(3, "logmsg(%u): released late "
1291 "arrived SHUTDOWN. pending %d\n",
1292 mythreadno, skip_shutdown);
1293 continue;
1296 for (f = Files; f < &Files[nlogs]; f++) {
1297 (void) pthread_mutex_lock(&f->filed_mutex);
1299 if (f->f_type == F_UNUSED) {
1300 (void) pthread_mutex_unlock(
1301 &f->filed_mutex);
1302 continue;
1305 f->f_queue_count++;
1306 mp->refcnt++;
1308 if (dataq_enqueue(&f->f_queue,
1309 (void *)mp) == -1) {
1310 f->f_queue_count--;
1311 mp->refcnt--;
1312 (void) pthread_mutex_unlock(
1313 &f->filed_mutex);
1314 MALLOC_FAIL("dropping message");
1316 if (mp->flags & SHUTDOWN) {
1317 (void) logerror_to_console(1,
1318 "unable to shutdown "
1319 "logger thread");
1322 continue;
1324 DPRINT3(5, "logmsg(%u): enqueued msg %p "
1325 "on queue %p\n", mythreadno,
1326 (void *)mp, (void *)&f->f_queue);
1327 (void) pthread_mutex_unlock(&f->filed_mutex);
1331 * flags value needs to be saved because mp may
1332 * have been freed before SHUTDOWN test below.
1334 flags = mp->flags;
1335 refcnt = mp->refcnt;
1337 (void) pthread_mutex_unlock(&mp->msg_mutex);
1338 if (refcnt == 0)
1339 free_msg(mp);
1341 if (flags & SHUTDOWN) {
1342 (void) pthread_mutex_lock(&hup_lock);
1343 while (hup_state != HUP_COMPLETED) {
1344 hup_state |= HUP_LOGMSG_SUSPENDED;
1345 (void) pthread_cond_wait(&hup_done,
1346 &hup_lock);
1347 hup_state &= ~HUP_LOGMSG_SUSPENDED;
1349 hup_state = HUP_ACCEPTABLE;
1350 (void) pthread_mutex_unlock(&hup_lock);
1351 fake_shutdown = 0;
1353 continue;
1357 * Check to see if msg looks non-standard.
1359 if ((int)strlen(mp->msg) < 16 || mp->msg[3] != ' ' ||
1360 mp->msg[6] != ' ' || mp->msg[9] != ':' ||
1361 mp->msg[12] != ':' || mp->msg[15] != ' ')
1362 mp->flags |= ADDDATE;
1364 /* extract facility and priority level */
1365 fac = (mp->pri & LOG_FACMASK) >> 3;
1366 if (mp->flags & MARK)
1367 fac = LOG_NFACILITIES;
1368 prilev = mp->pri & LOG_PRIMASK;
1370 DPRINT3(3, "logmsg(%u): fac = %d, pri = %d\n",
1371 mythreadno, fac, prilev);
1374 * Because different devices log at different speeds,
1375 * it's important to hold the mutex for the current
1376 * message until it's been enqueued to all log files,
1377 * so the reference count is accurate before any
1378 * of the log threads can decrement it.
1380 (void) pthread_mutex_lock(&mp->msg_mutex);
1382 for (f = Files; f < &Files[nlogs]; f++) {
1383 /* skip messages that are incorrect priority */
1384 if (f->f_pmask[fac] < (unsigned)prilev ||
1385 f->f_pmask[fac] == NOPRI)
1386 continue;
1387 if (f->f_queue_count > Q_HIGHWATER_MARK) {
1388 DPRINT4(5, "logmsg(%u): Dropping message "
1389 "%p on file %p, count = %d\n",
1390 mythreadno, (void *)mp, (void *)f,
1391 f->f_queue_count);
1392 continue;
1396 * Need to grab filed_mutex before testing the f_type.
1397 * Otherwise logit() may set F_UNUSED after the test
1398 * below, and start pulling out the pending messages.
1401 (void) pthread_mutex_lock(&f->filed_mutex);
1403 if (f->f_type == F_UNUSED ||
1404 (f->f_type == F_FILE && (mp->flags & IGN_FILE)) ||
1405 (f->f_type == F_CONSOLE &&
1406 (mp->flags & IGN_CONS))) {
1407 (void) pthread_mutex_unlock(&f->filed_mutex);
1408 continue;
1411 f->f_queue_count++;
1412 mp->refcnt++;
1414 if (dataq_enqueue(&f->f_queue, (void *)mp) == -1) {
1415 f->f_queue_count--;
1416 mp->refcnt--;
1417 (void) pthread_mutex_unlock(&f->filed_mutex);
1418 MALLOC_FAIL("dropping message");
1419 continue;
1422 DPRINT3(5, "logmsg(%u): enqueued msg %p on queue "
1423 "%p\n", mythreadno, (void *)mp,
1424 (void *)&f->f_queue);
1425 (void) pthread_mutex_unlock(&f->filed_mutex);
1427 refcnt = mp->refcnt;
1428 (void) pthread_mutex_unlock(&mp->msg_mutex);
1429 if (refcnt == 0)
1430 free_msg(mp);
1432 /*NOTREACHED*/
1433 return (NULL);
1437 * function to actually write the log message to the selected file.
1438 * each file has a logger thread that runs this routine. The function
1439 * is called with a pointer to its file structure.
1441 static void *
1442 logit(void *ap)
1444 struct filed *f = ap;
1445 log_message_t *mp;
1446 int forwardingloop = 0;
1447 const char *errmsg = "logit(%u): %s to %s forwarding loop detected\n";
1448 int i, currofst, prevofst, refcnt;
1449 host_list_t *hlp;
1451 assert(f != NULL);
1453 DPRINT4(5, "logit(%u): logger started for \"%s\" (queue %p, filed "
1454 "%p)\n", f->f_thread, f->f_un.f_fname, (void *)&f->f_queue,
1455 (void *)f);
1457 while (f->f_type != F_UNUSED) {
1458 (void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
1459 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1460 "%p\n", f->f_thread, (void *)mp, (void *)&f->f_queue);
1461 (void) pthread_mutex_lock(&f->filed_mutex);
1462 assert(f->f_queue_count > 0);
1463 f->f_queue_count--;
1464 (void) pthread_mutex_unlock(&f->filed_mutex);
1465 assert(mp->refcnt > 0);
1468 * is it a shutdown message ?
1470 if (mp->flags & SHUTDOWN) {
1471 (void) pthread_mutex_lock(&mp->msg_mutex);
1472 refcnt = --mp->refcnt;
1473 (void) pthread_mutex_unlock(&mp->msg_mutex);
1474 if (refcnt == 0)
1475 free_msg(mp);
1476 break;
1480 * Is it a logsync message?
1482 if ((mp->flags & (FLUSHMSG | LOGSYNC)) ==
1483 (FLUSHMSG | LOGSYNC)) {
1484 if (f->f_type != F_FILE)
1485 goto out; /* nothing to do */
1486 (void) close(f->f_file);
1487 f->f_file = open64(f->f_un.f_fname,
1488 O_WRONLY|O_APPEND|O_NOCTTY);
1489 if (f->f_file < 0) {
1490 f->f_type = F_UNUSED;
1491 logerror(f->f_un.f_fname);
1492 f->f_stat.errs++;
1494 goto out;
1498 * If the message flags include both flush and sync,
1499 * then just sync the file out to disk if appropriate.
1501 if ((mp->flags & (FLUSHMSG | SYNC_FILE)) ==
1502 (FLUSHMSG | SYNC_FILE)) {
1503 if (f->f_type == F_FILE) {
1504 DPRINT2(5, "logit(%u): got FLUSH|SYNC "
1505 "for filed %p\n", f->f_thread,
1506 (void *)f);
1507 (void) fsync(f->f_file);
1509 goto out;
1513 * Otherwise if it's a standard flush message, write
1514 * out any saved messages to the file.
1516 if ((mp->flags & FLUSHMSG) && (f->f_prevcount > 0)) {
1517 set_flush_msg(f);
1518 writemsg(SAVED, f);
1519 goto out;
1522 (void) strlcpy(f->f_current.msg, mp->msg, MAXLINE+1);
1523 (void) strlcpy(f->f_current.host, mp->hlp->hl_hosts[0],
1524 SYS_NMLN);
1525 f->f_current.pri = mp->pri;
1526 f->f_current.flags = mp->flags;
1527 f->f_current.time = mp->ts;
1528 f->f_msgflag &= ~CURRENT_VALID;
1529 hlp = mp->hlp;
1531 prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
1532 currofst = (f->f_current.flags & ADDDATE) ? 0 : 16;
1534 if (f->f_type == F_FORW) {
1536 * Should not forward MARK messages, as they are
1537 * not defined outside of the current system.
1540 if (mp->flags & MARK) {
1541 DPRINT1(1, "logit(%u): cannot forward "
1542 "Mark\n", f->f_thread);
1543 goto out;
1547 * can not forward message if we do
1548 * not have a host to forward to
1550 if (hlp == (host_list_t *)NULL)
1551 goto out;
1553 * a forwarding loop is created on machines
1554 * with multiple interfaces because the
1555 * network address of the sender is different
1556 * to the receiver even though it is the
1557 * same machine. Instead, if the
1558 * hostname the source and target are
1559 * the same the message if thrown away
1561 forwardingloop = 0;
1562 for (i = 0; i < hlp->hl_cnt; i++) {
1563 if (strcmp(hlp->hl_hosts[i],
1564 f->f_un.f_forw.f_hname) == 0) {
1565 DPRINT3(1, errmsg, f->f_thread,
1566 f->f_un.f_forw.f_hname,
1567 hlp->hl_hosts[i]);
1568 forwardingloop = 1;
1569 break;
1573 if (forwardingloop == 1) {
1574 f->f_stat.cantfwd++;
1575 goto out;
1579 f->f_msgflag |= CURRENT_VALID;
1581 /* check for dup message */
1582 if (f->f_type != F_FORW &&
1583 (f->f_msgflag & OLD_VALID) &&
1584 prevofst == currofst &&
1585 (strcmp(f->f_prevmsg.msg + prevofst,
1586 f->f_current.msg + currofst) == 0) &&
1587 (strcmp(f->f_prevmsg.host,
1588 f->f_current.host) == 0)) {
1589 /* a dup */
1590 DPRINT2(2, "logit(%u): msg is dup - %p\n",
1591 f->f_thread, (void *)mp);
1592 if (currofst == 16) {
1593 (void) strncpy(f->f_prevmsg.msg,
1594 f->f_current.msg, 15); /* update time */
1596 f->f_prevcount++;
1597 f->f_stat.dups++;
1598 f->f_stat.total++;
1599 f->f_msgflag &= ~CURRENT_VALID;
1600 } else {
1601 /* new: mark or prior dups exist */
1602 if (f->f_current.flags & MARK || f->f_prevcount > 0) {
1603 if (f->f_prevcount > 0 && f->f_type != F_FORW) {
1604 set_flush_msg(f);
1605 if (f->f_msgflag & OLD_VALID) {
1606 writemsg(SAVED, f);
1609 if (f->f_msgflag & CURRENT_VALID)
1610 writemsg(CURRENT, f);
1611 if (!(mp->flags & NOCOPY))
1612 copy_msg(f);
1613 if (f->f_current.flags & MARK) {
1614 DPRINT2(2, "logit(%u): msg is "
1615 "mark - %p)\n", f->f_thread,
1616 (void *)mp);
1617 f->f_msgflag &= ~OLD_VALID;
1618 } else {
1619 DPRINT2(2, "logit(%u): saving "
1620 "message - %p\n", f->f_thread,
1621 (void *)mp);
1623 f->f_stat.total++;
1624 } else { /* new message */
1625 DPRINT2(2, "logit(%u): msg is new "
1626 "- %p\n", f->f_thread, (void *)mp);
1627 writemsg(CURRENT, f);
1628 if (!(mp->flags & NOCOPY))
1629 copy_msg(f);
1630 f->f_stat.total++;
1634 * if message refcnt goes to zero after we decrement
1635 * it here, we are the last consumer of the message,
1636 * and we should free it. We need to hold the lock
1637 * between decrementing the count and checking for
1638 * zero so another thread doesn't beat us to it.
1640 out:
1641 (void) pthread_mutex_lock(&mp->msg_mutex);
1642 refcnt = --mp->refcnt;
1643 (void) pthread_mutex_unlock(&mp->msg_mutex);
1644 if (refcnt == 0)
1645 free_msg(mp);
1647 /* register our exit */
1650 * Pull out all pending messages, if they exist.
1653 (void) pthread_mutex_lock(&f->filed_mutex);
1655 while (f->f_queue_count > 0) {
1656 (void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
1657 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1658 "%p\n",
1659 f->f_thread, (void *)mp, (void *)&f->f_queue);
1660 (void) pthread_mutex_lock(&mp->msg_mutex);
1661 refcnt = --mp->refcnt;
1662 (void) pthread_mutex_unlock(&mp->msg_mutex);
1663 if (refcnt == 0)
1664 free_msg(mp);
1665 f->f_queue_count--;
1668 (void) pthread_mutex_unlock(&f->filed_mutex);
1670 if (f->f_type != F_USERS && f->f_type != F_WALL &&
1671 f->f_type != F_UNUSED) {
1672 if (f->f_type == F_FORW)
1673 (void) t_close(f->f_file);
1674 else
1675 (void) close(f->f_file);
1679 * Since f_type may have been changed before this point, we need
1680 * to test orig_type.
1682 if (f->f_orig_type == F_FORW) {
1683 free(f->f_un.f_forw.f_addr.buf);
1686 f->f_type = F_UNUSED;
1687 (void) pthread_mutex_lock(&cft);
1688 --conf_threads;
1689 (void) pthread_mutex_unlock(&cft);
1690 DPRINT1(5, "logit(%u): logging thread exited\n", f->f_thread);
1691 return (NULL);
1695 * change the previous message to a flush message, stating how
1696 * many repeats occurred since the last flush
1698 static void
1699 set_flush_msg(struct filed *f)
1701 char tbuf[10];
1702 int prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
1704 if (f->f_prevcount == 1)
1705 (void) strncpy(tbuf, "time", sizeof (tbuf));
1706 else
1707 (void) strncpy(tbuf, "times", sizeof (tbuf));
1709 (void) snprintf(f->f_prevmsg.msg+prevofst,
1710 sizeof (f->f_prevmsg.msg) - prevofst,
1711 "last message repeated %d %s", f->f_prevcount, tbuf);
1712 f->f_prevcount = 0;
1713 f->f_msgflag |= OLD_VALID;
1718 * the actual writing of the message is broken into a separate function
1719 * because each file has a current and saved message associated with
1720 * it (for duplicate message detection). It is necessary to be able
1721 * to write either the saved message or the current message.
1723 static void
1724 writemsg(int selection, struct filed *f)
1726 char *cp, *p;
1727 int pri;
1728 int flags;
1729 int l;
1730 time_t ts;
1731 struct t_unitdata ud;
1732 char *eomp, *eomp2, *from, *text, *msg;
1733 char line[MAXLINE*2];
1734 char head[MAXLINE+1];
1735 char tmpbuf[MAXLINE+1];
1736 char cbuf[30];
1737 char *filtered;
1738 char *msgid_start, *msgid_end;
1739 pthread_t mythreadno;
1740 size_t hlen, filter_len;
1742 if (Debug) {
1743 mythreadno = pthread_self();
1746 switch (selection) {
1747 default:
1748 case CURRENT: /* print current message */
1749 msg = f->f_current.msg;
1750 from = f->f_current.host;
1751 pri = f->f_current.pri;
1752 flags = f->f_current.flags;
1753 ts = f->f_current.time;
1754 f->f_msgflag &= ~CURRENT_VALID;
1755 break;
1756 case SAVED: /* print saved message */
1757 msg = f->f_prevmsg.msg;
1758 from = f->f_prevmsg.host;
1759 pri = f->f_prevmsg.pri;
1760 flags = f->f_prevmsg.flags;
1761 ts = f->f_prevmsg.time;
1762 f->f_msgflag &= ~OLD_VALID;
1763 break;
1766 if (msg[0] == '\0')
1767 return;
1769 cp = line;
1771 if (flags & ADDDATE)
1772 (void) strncpy(cp, ctime_r(&ts, cbuf) + 4, 15);
1773 else
1774 (void) strncpy(cp, msg, 15);
1776 line[15] = '\0';
1777 (void) strcat(cp, " ");
1778 (void) strcat(cp, from);
1779 (void) strcat(cp, " ");
1780 text = cp + strlen(cp);
1782 if (flags & ADDDATE)
1783 (void) strcat(cp, msg);
1784 else
1785 (void) strcat(cp, msg+16);
1786 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
1788 errno = 0;
1789 t_errno = 0;
1790 switch (f->f_type) {
1791 case F_UNUSED:
1792 DPRINT1(1, "writemsg(%u): UNUSED\n", mythreadno);
1793 break;
1794 case F_FORW:
1795 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1796 mythreadno, msg, TypeNames[f->f_type],
1797 f->f_un.f_forw.f_hname);
1799 hlen = snprintf(head, sizeof (head),
1800 "<%d>%.15s ", pri, cp);
1802 DPRINT2(5, "writemsg(%u): head = \"%s\"\n", mythreadno, head);
1803 DPRINT2(5, "writemsg(%u): hlen = %d\n", mythreadno, hlen);
1805 l = strlen(text);
1806 p = text;
1808 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
1809 DPRINT2(5, "writemsg(%u): strlen(text) = %d\n", mythreadno, l);
1811 (void) strncpy(tmpbuf, head, hlen);
1813 while (l > 0) {
1814 size_t len;
1816 len = copy_frwd(tmpbuf + hlen, sizeof (tmpbuf) - hlen,
1817 p, l);
1819 DPRINT2(5, "writemsg(%u): tmpbuf = \"%s\"\n",
1820 mythreadno, tmpbuf);
1821 DPRINT2(5, "writemsg(%u): len = %d\n", mythreadno,
1822 len);
1823 DPRINT2(5, "writemsg(%u): strlen(tmpbuf) = %d\n",
1824 mythreadno, strlen(tmpbuf));
1826 ud.opt.buf = NULL;
1827 ud.opt.len = 0;
1828 ud.udata.buf = tmpbuf;
1829 ud.udata.len = len + hlen;
1830 ud.addr.maxlen = f->f_un.f_forw.f_addr.maxlen;
1831 ud.addr.buf = f->f_un.f_forw.f_addr.buf;
1832 ud.addr.len = f->f_un.f_forw.f_addr.len;
1833 if (t_sndudata(f->f_file, &ud) < 0) {
1834 if ((hup_state & HUP_INPROGRESS) &&
1835 f->f_type == F_UNUSED) {
1836 break;
1838 (void) t_close(f->f_file);
1839 f->f_type = F_UNUSED;
1840 logerror("t_sndudata");
1843 * Since it has already failed, it's not worth
1844 * continuing output from the middle of
1845 * message string.
1847 break;
1849 p += len;
1850 l -= len;
1852 break;
1853 case F_CONSOLE:
1854 case F_TTY:
1855 case F_FILE:
1856 case F_USERS:
1857 case F_WALL:
1858 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1859 mythreadno, msg, TypeNames[f->f_type],
1860 ((f->f_type == F_USERS) || (f->f_type == F_WALL)) ?
1861 "" : f->f_un.f_fname);
1863 * filter the string in preparation for writing it
1864 * save the original for possible forwarding.
1865 * In case every byte in cp is a control character,
1866 * allocates large enough buffer for filtered.
1869 filter_len = strlen(cp) * 4 + 1;
1870 filtered = (char *)malloc(filter_len);
1871 if (!filtered) {
1872 MALLOC_FAIL("dropping message");
1873 /* seems we can just return */
1874 return;
1876 DPRINT3(5, "writemsg(%u): "
1877 "filtered allocated (%p: %d bytes)\n",
1878 mythreadno, (void *)filtered, filter_len);
1879 /* -3 : we may add "\r\n" to ecomp(filtered) later */
1880 filter_string(cp, filtered, filter_len - 3);
1882 DPRINT2(5, "writemsg(%u): strlen(filtered) = %d\n",
1883 mythreadno, strlen(filtered));
1885 * If we're writing to the console, strip out the message ID
1886 * to reduce visual clutter.
1888 if ((msgid_start = strstr(filtered, "[ID ")) != NULL &&
1889 (msgid_end = strstr(msgid_start, "] ")) != NULL &&
1890 f->f_type == F_CONSOLE)
1891 (void) strcpy(msgid_start, msgid_end + 2);
1893 eomp = filtered + strlen(filtered);
1895 if ((f->f_type == F_USERS) || (f->f_type == F_WALL)) {
1896 /* CSTYLED */
1897 (void) strcat(eomp, "\r\n"); /*lint !e669*/
1899 * Since wallmsg messes with utmpx we need
1900 * to guarantee single threadedness...
1902 (void) pthread_mutex_lock(&wmp);
1903 wallmsg(f, from, filtered);
1904 (void) pthread_mutex_unlock(&wmp);
1907 * The contents of filtered have been copied
1908 * out to the struct walldev. We should free it here.
1911 free(filtered);
1913 /* exiting the switch */
1914 break;
1915 } else if (f->f_type != F_FILE) {
1916 /* CSTYLED */
1917 (void) strncpy(eomp, "\r\n", 3); /*lint !e669*/
1918 } else {
1919 if ((eomp2 = strchr(filtered, '\r')) != NULL) {
1920 (void) strncpy(eomp2, "\n", 2);
1921 } else {
1922 /* CSTYLED */
1923 (void) strncpy(eomp, "\n", 2); /*lint !e669*/
1926 if (write(f->f_file, filtered, strlen(filtered)) < 0) {
1927 int e = errno;
1929 if ((hup_state & HUP_INPROGRESS) &&
1930 f->f_type == F_UNUSED) {
1931 free(filtered);
1932 break;
1934 (void) close(f->f_file);
1936 * Check for EBADF on TTY's due
1937 * to vhangup() XXX
1939 if (e == EBADF && f->f_type != F_FILE) {
1940 f->f_file = open(f->f_un.f_fname,
1941 O_WRONLY|O_APPEND|O_NOCTTY);
1942 if (f->f_file < 0) {
1943 f->f_type = F_UNUSED;
1944 logerror(f->f_un.f_fname);
1945 f->f_stat.errs++;
1947 untty();
1948 } else {
1949 f->f_type = F_UNUSED;
1950 f->f_stat.errs++;
1951 errno = e;
1952 logerror(f->f_un.f_fname);
1954 } else if (flags & SYNC_FILE)
1955 if (((pri & LOG_FACMASK) >> 3) == LOG_KERN)
1956 (void) fsync(f->f_file);
1958 DPRINT2(5, "writemsg(%u): freeing filtered (%p)\n",
1959 mythreadno, (void *)filtered);
1961 free(filtered);
1962 break;
1967 * WALLMSG -- Write a message to the world at large
1969 * Write the specified message to either the entire
1970 * world, or a list of approved users.
1972 static void
1973 wallmsg(struct filed *f, char *from, char *msg)
1975 int i;
1976 size_t len, clen;
1977 char *buf = NULL;
1978 struct utmpx *utxp;
1979 time_t now;
1980 char line[512], dev[100];
1981 char cp[MAXLINE+1];
1982 struct stat statbuf;
1983 walldev_t *w;
1984 char cbuf[30];
1985 pthread_t mythreadno;
1987 if (Debug) {
1988 mythreadno = pthread_self();
1991 if (access(UTMPX_FILE, R_OK) != 0 || stat(UTMPX_FILE, &statbuf) != 0) {
1992 logerror(UTMPX_FILE);
1993 return;
1994 } else if (statbuf.st_uid != 0 || (statbuf.st_mode & 07777) != 0644) {
1995 (void) snprintf(line, sizeof (line), "%s %s", UTMPX_FILE,
1996 "not owned by root or not mode 644.\n"
1997 "This file must be owned by root "
1998 "and not writable by\n"
1999 "anyone other than root. This alert is being "
2000 "dropped because of\n"
2001 "this problem.");
2002 logerror(line);
2003 return;
2006 if (f->f_type == F_WALL) {
2007 (void) time(&now);
2008 len = snprintf(line, sizeof (line),
2009 "\r\n\7Message from syslogd@%s "
2010 "at %.24s ...\r\n", from, ctime_r(&now, cbuf));
2011 len += strlen(msg + 16);
2012 buf = (char *)malloc(len + 1);
2013 if (!buf) {
2014 MALLOC_FAIL("dropping message");
2015 return;
2017 DPRINT3(5, "wallmsg(%u): buf allocated (%p: %d bytes)\n",
2018 mythreadno, (void *)buf, len + 1);
2019 (void) strcpy(buf, line);
2020 (void) strcat(buf, msg + 16);
2021 clen = copy_frwd(cp, sizeof (cp), buf, len);
2022 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2023 mythreadno, clen);
2024 DPRINT2(5, "wallmsg(%u): freeing buf (%p)\n",
2025 mythreadno, (void *)buf);
2026 free(buf);
2027 } else {
2028 clen = copy_frwd(cp, sizeof (cp), msg, strlen(msg));
2029 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2030 mythreadno, clen);
2032 /* scan the user login file */
2033 setutxent();
2034 while ((utxp = getutxent()) != NULL) {
2035 /* is this slot used? */
2036 if (utxp->ut_name[0] == '\0' ||
2037 utxp->ut_line[0] == '\0' ||
2038 utxp->ut_type != USER_PROCESS)
2039 continue;
2040 /* should we send the message to this user? */
2041 if (f->f_type == F_USERS) {
2042 for (i = 0; i < MAXUNAMES; i++) {
2043 if (!f->f_un.f_uname[i][0]) {
2044 i = MAXUNAMES;
2045 break;
2047 if (strncmp(f->f_un.f_uname[i],
2048 utxp->ut_name, UNAMESZ) == 0)
2049 break;
2051 if (i >= MAXUNAMES)
2052 continue;
2055 /* compute the device name */
2056 if (utxp->ut_line[0] == '/') {
2057 (void) strncpy(dev, utxp->ut_line, UDEVSZ);
2058 } else {
2059 (void) strcpy(dev, "/dev/");
2060 (void) strncat(dev, utxp->ut_line, UDEVSZ);
2062 DPRINT2(1, "wallmsg(%u): write to '%s'\n", mythreadno,
2063 dev);
2065 if ((w = malloc(sizeof (walldev_t))) != NULL) {
2066 int rc;
2067 (void) pthread_attr_init(&w->thread_attr);
2068 (void) pthread_attr_setdetachstate(&w->thread_attr,
2069 PTHREAD_CREATE_DETACHED);
2070 (void) strncpy(w->dev, dev, PATH_MAX);
2071 (void) strncpy(w->msg, cp, MAXLINE+1);
2072 (void) strncpy(w->ut_name, utxp->ut_name,
2073 sizeof (w->ut_name));
2075 if ((rc = pthread_create(&w->thread, &w->thread_attr,
2076 writetodev, (void *) w)) != 0) {
2077 DPRINT2(5, "wallmsg(%u): wallmsg thread "
2078 "create failed rc = %d\n",
2079 mythreadno, rc);
2080 free(w);
2081 break;
2083 } else {
2084 MALLOC_FAIL("dropping message to user");
2087 /* close the user login file */
2088 endutxent();
2092 * Each time we need to write to a tty device (a potentially expensive
2093 * or long-running operation) this routine gets called as a new
2094 * detached, unbound thread. This allows writes to many devices
2095 * to proceed nearly in parallel, without having to resort to
2096 * asynchronous I/O or forking.
2098 static void *
2099 writetodev(void *ap)
2101 walldev_t *w = ap;
2102 int ttyf;
2103 int len;
2104 struct stat statb;
2105 struct passwd pw, *pwp;
2106 char pwbuf[MAXLINE];
2107 pthread_t mythreadno;
2109 if (Debug) {
2110 mythreadno = pthread_self();
2113 DPRINT1(1, "writetodev(%u): Device writer thread started\n",
2114 mythreadno);
2116 len = strlen(w->msg);
2118 ttyf = open(w->dev, O_WRONLY|O_NOCTTY|O_NDELAY);
2119 if (ttyf >= 0) {
2120 if (fstat(ttyf, &statb) != 0) {
2121 DPRINT2(1, "writetodev(%u): Can't stat '%s'\n",
2122 mythreadno, w->dev);
2123 errno = 0;
2124 logerror("Can't stat '%s'", w->dev);
2125 } else if (!(statb.st_mode & S_IWRITE)) {
2126 DPRINT2(1, "writetodev(%u): Can't write to "
2127 "'%s'\n", mythreadno, w->dev);
2128 } else if (!isatty(ttyf)) {
2129 DPRINT2(1, "writetodev(%u): '%s' not a tty\n",
2130 mythreadno, w->dev);
2132 * We might hit dtremote here. Don't generate
2133 * error message.
2135 } else if (getpwuid_r(statb.st_uid, &pw, pwbuf,
2136 sizeof (pwbuf), &pwp) != 0) {
2137 DPRINT2(1, "writetodev(%u): Can't determine owner "
2138 "of '%s'\n", mythreadno, w->dev);
2139 errno = 0;
2140 logerror("Can't determine owner of '%s'", w->dev);
2141 } else if (strncmp(pw.pw_name, w->ut_name, UNAMESZ) != 0) {
2142 DPRINT2(1, "writetodev(%u): Bad terminal owner '%s'"
2143 "\n", mythreadno, w->dev);
2144 errno = 0;
2145 logerror("%s %s owns '%s' %s %.*s",
2146 "Bad terminal owner;", pw.pw_name, w->dev,
2147 "but utmpx says", UNAMESZ, w->ut_name);
2148 } else if (write(ttyf, w->msg, len) != len) {
2149 DPRINT2(1, "writetodev(%u): Write failed to "
2150 "'%s'\n", mythreadno, w->dev);
2151 errno = 0;
2152 logerror("Write failed to '%s'", w->dev);
2155 DPRINT2(1, "writetodev(%u): write to '%s' succeeded\n",
2156 mythreadno, w->dev);
2158 (void) close(ttyf);
2159 } else {
2160 DPRINT2(1, "writetodev(%u): Can't open '%s'\n",
2161 mythreadno, w->dev);
2164 (void) pthread_attr_destroy(&w->thread_attr);
2165 free(w);
2167 DPRINT1(1, "writetodev(%u): Device writer thread exiting\n",
2168 mythreadno);
2170 pthread_exit(0);
2171 return (NULL);
2172 /*NOTREACHED*/
2176 * Return a printable representation of a host address. If unable to
2177 * look up hostname, format the numeric address for display instead.
2179 * First calls hnc_lookup to see if there is valid cache entry for
2180 * given network address. If it failed, cvthname looks up hostname,
2181 * and push the results into the hostname cache.
2183 static host_list_t *
2184 cvthname(struct netbuf *nbp, struct netconfig *ncp, char *failsafe_addr)
2186 int i;
2187 host_list_t *h;
2188 struct nd_hostservlist *hsp;
2189 struct nd_hostserv *hspp;
2190 pthread_t mythreadno;
2191 int hindex;
2192 char *uap;
2194 if (Debug) {
2195 mythreadno = pthread_self();
2198 if (Debug)
2199 uap = taddr2uaddr(ncp, nbp);
2201 DPRINT2(2, "cvthname(%u): looking up hostname for %s\n",
2202 mythreadno, uap ? uap : "<unknown>");
2204 if ((h = hnc_lookup(nbp, ncp, &hindex)) != NULL) {
2205 DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n",
2206 mythreadno, (void *)h, uap ? uap : "<unknown>",
2207 h->hl_hosts[0]);
2208 return (h);
2210 DPRINT2(2, "cvthname(%u): No cache found for %s\n",
2211 mythreadno, uap ? uap : "<unknown>");
2213 if (Debug)
2214 free(uap);
2216 if (ncp->nc_semantics != NC_TPI_CLTS) {
2217 return (NULL);
2220 /* memory allocation failure here is fatal */
2221 if ((h = malloc(sizeof (host_list_t))) == NULL) {
2222 MALLOC_FAIL("host name conversion");
2223 return (NULL);
2226 if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) {
2227 if (hsp->h_cnt <= 0) {
2228 out: netdir_free((void *)hsp, ND_HOSTSERVLIST);
2229 free(h);
2230 return (NULL);
2233 hspp = hsp->h_hostservs;
2234 h->hl_cnt = hsp->h_cnt;
2235 h->hl_hosts = (char **)malloc(sizeof (char *) * (h->hl_cnt));
2236 if (h->hl_hosts == NULL) {
2237 MALLOC_FAIL("host name conversion");
2238 goto out;
2241 DPRINT2(2, "cvthname(%u): Found %d hostnames\n",
2242 mythreadno, h->hl_cnt);
2243 for (i = 0; i < h->hl_cnt; i++) {
2244 h->hl_hosts[i] = (char *)
2245 malloc(sizeof (char) * (strlen(hspp->h_host) + 1));
2246 if (h->hl_hosts[i] == NULL) {
2247 int j;
2248 for (j = 0; j < i; j++) {
2249 free(h->hl_hosts[j]);
2251 free(h->hl_hosts);
2252 MALLOC_FAIL("host name conversion");
2253 goto out;
2255 (void) strcpy(h->hl_hosts[i], hspp->h_host);
2256 hspp++;
2258 netdir_free((void *)hsp, ND_HOSTSERVLIST);
2259 } else { /* unknown address */
2260 h->hl_cnt = 1;
2261 h->hl_hosts = (char **)malloc(sizeof (char *));
2262 if (h->hl_hosts == NULL) {
2263 free(h);
2264 MALLOC_FAIL("host name conversion");
2265 return (NULL);
2267 h->hl_hosts[0] = (char *)malloc(strlen(failsafe_addr) + 3);
2268 if (h->hl_hosts[0] == NULL) {
2269 free(h->hl_hosts);
2270 free(h);
2271 MALLOC_FAIL("host name conversion");
2272 return (NULL);
2274 /*LINTED*/
2275 (void) sprintf(h->hl_hosts[0], "[%s]", failsafe_addr);
2276 DPRINT2(1, "cvthname(%u): Hostname lookup failed "
2277 "- using address %s instead\n",
2278 mythreadno, h->hl_hosts[0]);
2281 h->hl_refcnt = 1;
2282 if (pthread_mutex_init(&h->hl_mutex, NULL) != 0) {
2283 logerror("pthread_mutex_init failed");
2284 /* This host_list won't be shared by the cache. */
2285 return (h);
2287 hnc_register(nbp, ncp, h, hindex);
2288 DPRINT3(2, "cvthname(%u): returning %p for %s\n",
2289 mythreadno, (void *)h, h->hl_hosts[0]);
2290 return (h);
2294 * Print syslogd errors some place. Need to be careful here, because
2295 * this routine is called at times when we're not initialized and
2296 * ready to log messages...in this case, fall back to using the console.
2298 void
2299 logerror(const char *type, ...)
2301 char buf[MAXLINE+1];
2302 pthread_t mythreadno;
2303 int flag;
2304 va_list ap;
2306 if (Debug) {
2307 mythreadno = pthread_self();
2310 va_start(ap, type);
2311 logerror_format(type, buf, ap);
2312 va_end(ap);
2313 DPRINT2(1, "logerror(%u): %s\n", mythreadno, buf);
2315 (void) pthread_mutex_lock(&logerror_lock);
2316 if (!interrorlog) {
2317 flag = 0;
2318 if (logerror_to_console(1, buf) == 0) {
2319 /* has written to the console */
2320 flag = IGN_CONS;
2322 (void) logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE|flag, 1);
2323 } else {
2324 if (logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE, 0) == -1) {
2325 (void) logerror_to_console(1, buf);
2328 (void) pthread_mutex_unlock(&logerror_lock);
2330 errno = 0;
2331 t_errno = 0;
2334 static void
2335 logerror_format(const char *type, char *buf, va_list ap)
2337 char tmpbuf[MAXLINE + 1];
2338 pthread_t mythreadno;
2340 if (Debug) {
2341 mythreadno = pthread_self();
2344 (void) vsnprintf(tmpbuf, MAXLINE, type, ap);
2346 if (t_errno == 0 || t_errno == TSYSERR) {
2347 char *errstr;
2349 if (errno == 0) {
2350 (void) snprintf(buf, MAXLINE, "syslogd: %.*s",
2351 MAXLINE, tmpbuf);
2352 } else if ((errstr = strerror(errno)) == (char *)NULL) {
2353 (void) snprintf(buf, MAXLINE, "syslogd: %s: error"
2354 " %d", tmpbuf, errno);
2355 } else {
2356 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
2357 tmpbuf, errstr);
2359 } else {
2360 if (t_errno > t_nerr) {
2361 (void) snprintf(buf, MAXLINE, "syslogd: %s:"
2362 " t_error %d", tmpbuf, t_errno);
2363 } else {
2364 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
2365 tmpbuf, t_errlist[t_errno]);
2369 DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno, buf);
2372 static int
2373 logerror_to_console(int nonblock, const char *buf)
2375 int cfd, modes;
2376 pthread_t mythreadno;
2377 int ret = 0, len;
2378 char tmpbuf[MAXLINE + 1];
2380 if (Debug) {
2381 mythreadno = pthread_self();
2384 DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno, buf);
2387 * must use open here instead of fopen, because
2388 * we need the O_NOCTTY behavior - otherwise we
2389 * could hang the console at boot time
2392 modes = (nonblock) ?
2393 O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK :
2394 O_WRONLY|O_APPEND|O_NOCTTY;
2396 if (((cfd = open(sysmsg, modes)) >= 0) ||
2397 ((cfd = open(ctty, modes)) >= 0)) {
2398 (void) snprintf(tmpbuf, MAXLINE, "%s\n", buf);
2399 len = strlen(tmpbuf);
2400 if (write(cfd, tmpbuf, len) != len) {
2401 ret = 1;
2403 (void) close(cfd);
2404 } else {
2405 ret = 1;
2407 /* punt */
2408 DPRINT1(1, "logerror_console(%u): can't open console\n",
2409 mythreadno);
2411 return (ret);
2415 * copy current message to saved message in filed structure.
2417 static void
2418 copy_msg(struct filed *f)
2420 (void) strlcpy(f->f_prevmsg.msg, f->f_current.msg, MAXLINE+1);
2421 (void) strlcpy(f->f_prevmsg.host, f->f_current.host, SYS_NMLN);
2422 f->f_prevmsg.pri = f->f_current.pri;
2423 f->f_prevmsg.flags = f->f_current.flags;
2424 f->f_prevmsg.time = f->f_current.time;
2425 f->f_msgflag |= OLD_VALID;
2430 * function to free a host_list_t struct that was allocated
2431 * out of cvthname(). There is a special case where we don't
2432 * free the hostname list in LocalHostName, because that's
2433 * our own addresses, and we just want to have to look it
2434 * up once and save it. Also don't free it if it's
2435 * NullHostName, because that's a special one we use if
2436 * name service lookup fails.
2438 * By having hostname cache, now host_list_t will be shared
2439 * by messages and hostname cache. hl_refcnt is used for
2440 * the purpose.
2442 static void
2443 freehl(host_list_t *h)
2445 int i, refcnt;
2446 pthread_t mythreadno;
2448 if (Debug) {
2449 mythreadno = pthread_self();
2452 DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno, (void *)h);
2454 if (h == NULL || h == &LocalHostName || h == &NullHostName) {
2455 return;
2458 (void) pthread_mutex_lock(&h->hl_mutex);
2459 refcnt = --h->hl_refcnt;
2460 (void) pthread_mutex_unlock(&h->hl_mutex);
2462 if (refcnt != 0) {
2463 DPRINT3(5, "freehl(%u): %p has reference %d\n",
2464 mythreadno, (void *)h, refcnt);
2465 return;
2468 (void) pthread_mutex_destroy(&h->hl_mutex);
2470 DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno, (void *)h);
2472 for (i = 0; i < h->hl_cnt; i++) {
2473 free(h->hl_hosts[i]);
2476 free(h->hl_hosts);
2477 free(h);
2481 * Create the door file and the pid file in /var/run. If the filesystem
2482 * containing /etc is writable, create symlinks /etc/.syslog_door and
2483 * /etc/syslog.pid to them. On systems that do not support /var/run, create
2484 * /etc/.syslog_door and /etc/syslog.pid directly.
2486 * Note: it is not considered fatal to fail to create the pid file or its
2487 * symlink. Attempts to use them in the usual way will fail, of course, but
2488 * syslogd will function nicely without it (not so for the door file).
2491 static void
2492 open_door(void)
2494 struct stat buf;
2495 door_info_t info;
2496 char line[MAXLINE+1];
2497 pthread_t mythreadno;
2498 int err;
2500 if (Debug) {
2501 mythreadno = pthread_self();
2505 * first see if another syslogd is running by trying
2506 * a door call - if it succeeds, there is already
2507 * a syslogd process active
2510 if (!DoorCreated) {
2511 int door;
2513 if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
2514 DPRINT2(5, "open_door(%u): %s opened "
2515 "successfully\n", mythreadno, DoorFileName);
2517 if (door_info(door, &info) >= 0) {
2518 DPRINT2(5, "open_door(%u): "
2519 "door_info:info.di_target = %ld\n",
2520 mythreadno, info.di_target);
2522 if (info.di_target > 0) {
2523 (void) sprintf(line, "syslogd pid %ld"
2524 " already running. Cannot "
2525 "start another syslogd pid %ld",
2526 info.di_target, getpid());
2527 DPRINT2(5, "open_door(%u): error: "
2528 "%s\n", mythreadno, line);
2529 errno = 0;
2530 logerror(line);
2531 exit(1);
2535 (void) close(door);
2536 } else {
2537 if (lstat(DoorFileName, &buf) < 0) {
2538 err = errno;
2540 DPRINT3(5, "open_door(%u): lstat() of %s "
2541 "failed, errno=%d\n",
2542 mythreadno, DoorFileName, err);
2544 if ((door = creat(DoorFileName, 0644)) < 0) {
2545 err = errno;
2546 (void) snprintf(line, sizeof (line),
2547 "creat() of %s failed - fatal",
2548 DoorFileName);
2549 DPRINT3(1, "open_door(%u): error: %s, "
2550 "errno=%d\n", mythreadno, line,
2551 err);
2552 errno = err;
2553 logerror(line);
2554 delete_doorfiles();
2555 exit(1);
2558 (void) fchmod(door,
2559 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
2561 DPRINT2(5, "open_door(%u): creat() of %s "
2562 "succeeded\n", mythreadno,
2563 DoorFileName);
2565 (void) close(door);
2569 if (strcmp(DoorFileName, DOORFILE) == 0) {
2570 if (lstat(OLD_DOORFILE, &buf) == 0) {
2571 DPRINT2(5, "open_door(%u): lstat() of %s "
2572 "succeeded\n", mythreadno,
2573 OLD_DOORFILE);
2575 if (S_ISDIR(buf.st_mode)) {
2576 (void) snprintf(line, sizeof (line),
2577 "%s is a directory - fatal",
2578 OLD_DOORFILE);
2579 DPRINT2(1, "open_door(%u): error: "
2580 "%s\n", mythreadno, line);
2581 errno = 0;
2582 logerror(line);
2583 delete_doorfiles();
2584 exit(1);
2587 DPRINT2(5, "open_door(%u): %s is not a "
2588 "directory\n",
2589 mythreadno, OLD_DOORFILE);
2591 if (unlink(OLD_DOORFILE) < 0) {
2592 err = errno;
2593 (void) snprintf(line, sizeof (line),
2594 "unlink() of %s failed",
2595 OLD_DOORFILE);
2596 DPRINT2(5, "open_door(%u): %s\n",
2597 mythreadno, line);
2599 if (err != EROFS) {
2600 DPRINT3(1, "open_door(%u): "
2601 "error: %s, "
2602 "errno=%d\n",
2603 mythreadno, line, err);
2604 (void) strcat(line, " - fatal");
2605 errno = err;
2606 logerror(line);
2607 delete_doorfiles();
2608 exit(1);
2611 DPRINT1(5, "open_door(%u): unlink "
2612 "failure OK on RO file "
2613 "system\n", mythreadno);
2615 } else {
2616 DPRINT2(5, "open_door(%u): file %s doesn't "
2617 "exist\n", mythreadno, OLD_DOORFILE);
2620 if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
2621 err = errno;
2622 (void) snprintf(line, sizeof (line),
2623 "symlink %s -> %s failed", OLD_DOORFILE,
2624 RELATIVE_DOORFILE);
2625 DPRINT2(5, "open_door(%u): %s\n", mythreadno,
2626 line);
2628 if (err != EROFS) {
2629 DPRINT3(1, "open_door(%u): error: %s, "
2630 "errno=%d\n", mythreadno, line,
2631 err);
2632 errno = err;
2633 (void) strcat(line, " - fatal");
2634 logerror(line);
2635 delete_doorfiles();
2636 exit(1);
2639 DPRINT1(5, "open_door(%u): symlink failure OK "
2640 "on RO file system\n", mythreadno);
2641 } else {
2642 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2643 "succeeded\n", mythreadno,
2644 OLD_DOORFILE, RELATIVE_DOORFILE);
2648 if ((DoorFd = door_create(server, 0,
2649 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
2650 err = errno;
2651 (void) sprintf(line, "door_create() failed - fatal");
2652 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n",
2653 mythreadno, line, err);
2654 errno = err;
2655 logerror(line);
2656 delete_doorfiles();
2657 exit(1);
2659 (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
2660 DPRINT2(5, "open_door(%u): door_create() succeeded, "
2661 "DoorFd=%d\n", mythreadno, DoorFd);
2663 DoorCreated = 1;
2666 (void) fdetach(DoorFileName); /* just in case... */
2668 (void) door_server_create(door_server_pool);
2670 if (fattach(DoorFd, DoorFileName) < 0) {
2671 err = errno;
2672 (void) snprintf(line, sizeof (line), "fattach() of fd"
2673 " %d to %s failed - fatal", DoorFd, DoorFileName);
2674 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno,
2675 line, err);
2676 errno = err;
2677 logerror(line);
2678 delete_doorfiles();
2679 exit(1);
2682 DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno,
2683 DoorFileName);
2686 * create pidfile anyway, so those using it to control
2687 * syslogd (with kill `cat /etc/syslog.pid` perhaps)
2688 * don't get broken.
2691 if (!PidfileCreated) {
2692 int pidfd;
2694 PidfileCreated = 1;
2696 if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644))
2697 < 0) {
2698 err = errno;
2699 (void) snprintf(line, sizeof (line),
2700 "open() of %s failed", PidFileName);
2701 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2702 mythreadno, line, err);
2703 errno = err;
2704 logerror(line);
2705 return;
2708 (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
2709 (void) sprintf(line, "%ld\n", getpid());
2711 if (write(pidfd, line, strlen(line)) < 0) {
2712 err = errno;
2713 (void) snprintf(line, sizeof (line),
2714 "write to %s on fd %d failed", PidFileName, pidfd);
2715 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2716 mythreadno, line, err);
2717 errno = err;
2718 logerror(line);
2719 return;
2722 (void) close(pidfd);
2724 DPRINT2(5, "open_door(%u): %s created\n",
2725 mythreadno, PidFileName);
2727 if (strcmp(PidFileName, PIDFILE) == 0) {
2728 if (lstat(OLD_PIDFILE, &buf) == 0) {
2729 DPRINT2(5, "open_door(%u): lstat() of %s "
2730 "succeded\n", mythreadno, OLD_PIDFILE);
2732 if (S_ISDIR(buf.st_mode)) {
2733 (void) snprintf(line, sizeof (line),
2734 "file %s is a directory",
2735 OLD_PIDFILE);
2736 DPRINT2(1, "open_door(%u): warning: "
2737 "%s\n", mythreadno, line);
2738 errno = 0;
2739 logerror(line);
2740 return;
2743 if (unlink(OLD_PIDFILE) < 0) {
2744 err = errno;
2745 (void) snprintf(line, sizeof (line),
2746 "unlink() of %s failed",
2747 OLD_PIDFILE);
2748 DPRINT2(5, "open_door(%u): %s\n",
2749 mythreadno, line);
2751 if (err != EROFS) {
2752 DPRINT3(1, "open_door (%u): "
2753 "warning: %s, "
2754 "errno=%d\n",
2755 mythreadno, line, err);
2756 errno = err;
2757 logerror(line);
2758 return;
2761 DPRINT1(5, "open_door(%u): unlink "
2762 "failure OK on RO file "
2763 "system\n", mythreadno);
2765 } else {
2766 DPRINT2(5, "open_door(%u): file %s doesn't "
2767 "exist\n", mythreadno, OLD_PIDFILE);
2770 if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) {
2771 err = errno;
2772 (void) snprintf(line, sizeof (line),
2773 "symlink %s -> %s failed", OLD_PIDFILE,
2774 RELATIVE_PIDFILE);
2775 DPRINT2(5, "open_door(%u): %s\n", mythreadno,
2776 line);
2778 if (err != EROFS) {
2779 DPRINT3(1, "open_door(%u): warning: "
2780 "%s, errno=%d\n", mythreadno,
2781 line, err);
2782 errno = err;
2783 logerror(line);
2784 return;
2787 DPRINT1(5, "open_door(%u): symlink failure OK "
2788 "on RO file system\n", mythreadno);
2789 return;
2792 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2793 "succeeded\n", mythreadno, OLD_PIDFILE,
2794 RELATIVE_PIDFILE);
2800 * the 'server' function that we export via the door. It does
2801 * nothing but return.
2803 /*ARGSUSED*/
2804 static void
2805 server(void *cookie, char *argp, size_t arg_size,
2806 door_desc_t *dp, uint_t n)
2808 (void) door_return(NULL, 0, NULL, 0);
2809 /* NOTREACHED */
2812 /*ARGSUSED*/
2813 static void *
2814 create_door_thr(void *arg)
2816 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2817 (void) door_return(NULL, 0, NULL, 0);
2820 * If there is an error in door_return(), it will return here and
2821 * the thread will exit. Hence we need to decrement door_server_cnt.
2823 (void) pthread_mutex_lock(&door_server_cnt_lock);
2824 door_server_cnt--;
2825 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2826 return (NULL);
2830 * Max number of door server threads for syslogd. Since door is used
2831 * to check the health of syslogd, we don't need large number of
2832 * server threads.
2834 #define MAX_DOOR_SERVER_THR 3
2837 * Manage door server thread pool.
2839 /*ARGSUSED*/
2840 static void
2841 door_server_pool(door_info_t *dip)
2843 (void) pthread_mutex_lock(&door_server_cnt_lock);
2844 if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
2845 pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
2846 door_server_cnt++;
2847 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2848 return;
2851 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2855 * checkm4 - used to verify that the external utilities that
2856 * syslogd depends on are where we expect them to be.
2857 * Returns 0 if all utilities are found, > 0 if any are missing.
2858 * Also logs errors so user knows what's missing
2860 static int
2861 checkm4(void)
2863 int notfound = 0;
2864 int saverrno;
2865 pthread_t mythreadno;
2867 if (Debug) {
2868 mythreadno = pthread_self();
2871 if (access("/usr/ccs/bin/m4", X_OK) < 0) {
2872 saverrno = errno;
2873 logerror("/usr/ccs/bin/m4");
2874 DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access "
2875 "returned %d\n", mythreadno, saverrno);
2876 notfound++;
2879 return (notfound);
2883 * INIT -- Initialize syslogd from configuration table, start up
2884 * input and logger threads. This routine is called only once.
2886 static void
2887 init(void)
2889 struct utsname *up;
2890 pthread_attr_t sys_attr, net_attr, log_attr, hnl_attr;
2891 int nthread;
2892 pthread_t mythreadno;
2894 if (Debug) {
2895 mythreadno = pthread_self();
2898 DPRINT1(2, "init(%u): initializing\n", mythreadno);
2900 /* hand-craft a host_list_t entry for our local host name */
2901 if ((up = malloc(sizeof (struct utsname))) == NULL) {
2902 MALLOC_FAIL_EXIT;
2904 (void) uname(up);
2905 LocalHostName.hl_cnt = 1;
2906 if ((LocalHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
2907 MALLOC_FAIL_EXIT;
2909 if ((LocalHostName.hl_hosts[0] = strdup(up->nodename)) == NULL) {
2910 free(LocalHostName.hl_hosts);
2911 MALLOC_FAIL_EXIT;
2913 free(up);
2914 /* also hand craft one for use if name resolution fails */
2915 NullHostName.hl_cnt = 1;
2916 if ((NullHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
2917 MALLOC_FAIL_EXIT;
2919 if ((NullHostName.hl_hosts[0] = strdup("name lookup failed")) == NULL) {
2920 MALLOC_FAIL_EXIT;
2923 hnc_init(0);
2926 * Note that getnets will allocate network resources, but won't be
2927 * binding UDP port. This is because, there could be a race
2928 * condition between door. If we bind here, one syslogd could grab
2929 * UDP port first, but later another syslogd could take over without
2930 * getting UDP port but grab the door file. The 2nd syslogd could
2931 * continue to run without listening network.
2932 * bindnet() will be called after door was successfully opened.
2934 getnets();
2937 * Start up configured theads
2939 conf_init();
2942 * allocate thread stacks for the persistant threads
2944 nthread = (turnoff == 0) ? 4 : 2;
2946 if ((stack_ptr = alloc_stacks(nthread)) == NULL) {
2947 logerror("alloc_stacks failed - fatal");
2948 exit(1);
2951 if (Debug) {
2952 dumpstats(STDOUT_FILENO);
2955 (void) dataq_init(&inputq); /* init the input queue */
2957 if (pthread_attr_init(&sys_attr) != 0 ||
2958 pthread_attr_init(&log_attr) != 0 ||
2959 pthread_attr_init(&net_attr) != 0 ||
2960 pthread_attr_init(&hnl_attr) != 0 ||
2961 pthread_attr_init(&door_thr_attr) != 0) {
2962 logerror("pthread_attr_init failed - fatal");
2963 exit(1);
2966 (void) pthread_attr_setscope(&sys_attr, PTHREAD_SCOPE_PROCESS);
2967 (void) pthread_attr_setscope(&log_attr, PTHREAD_SCOPE_PROCESS);
2968 (void) pthread_attr_setscope(&net_attr, PTHREAD_SCOPE_PROCESS);
2969 (void) pthread_attr_setscope(&hnl_attr, PTHREAD_SCOPE_PROCESS);
2970 (void) pthread_attr_setscope(&door_thr_attr, PTHREAD_SCOPE_SYSTEM);
2971 (void) pthread_attr_setdetachstate(&door_thr_attr,
2972 PTHREAD_CREATE_DETACHED);
2974 /* 1: logmsg thread */
2975 (void) pthread_attr_setstacksize(&log_attr, stacksize);
2976 (void) pthread_attr_setstackaddr(&log_attr, stack_ptr);
2977 stack_ptr += stacksize + redzonesize;
2978 if (pthread_create(&log_thread, &log_attr, logmsg, NULL) != 0) {
2979 logerror("pthread_create failed - fatal");
2980 exit(1);
2984 * open the log device, and pull up all pending message
2985 * from the log driver.
2987 prepare_sys_poll();
2990 * Now we can deliver the pending internal error messages.
2992 enable_errorlog();
2994 /* 2: sys_poll thread */
2995 (void) pthread_attr_setstacksize(&sys_attr, stacksize);
2996 (void) pthread_attr_setstackaddr(&sys_attr, stack_ptr);
2997 stack_ptr += stacksize + redzonesize;
2998 if (pthread_create(&sys_thread, &sys_attr, sys_poll, NULL) != 0) {
2999 logerror("pthread_create failed - fatal");
3000 exit(1);
3004 * We've started the sys_poll() and logmsg() threads. Now we are ready
3005 * to open the door. This cannot happen before spawning sys_poll(),
3006 * because after opening the door, syslog() will no longer take care of
3007 * LOG_CONS. Therefor, we should pull up all pending log messages and
3008 * activate sys_poll() before opening the door, so that log driver
3009 * won't drop messages.
3011 open_door();
3013 DPRINT1(1, "init(%u): accepting messages from local system\n",
3014 mythreadno);
3016 if (turnoff == 0) {
3017 /* init the hostname lookup queue */
3018 (void) dataq_init(&hnlq);
3020 /* 3: hostname lookup thread */
3021 (void) pthread_attr_setstacksize(&hnl_attr, stacksize);
3022 (void) pthread_attr_setstackaddr(&hnl_attr, stack_ptr);
3023 stack_ptr += stacksize + redzonesize;
3024 if (pthread_create(&hnl_thread, &hnl_attr,
3025 hostname_lookup, NULL) != 0) {
3026 logerror("pthread_create failed - fatal");
3027 exit(1);
3030 /* 4: net_poll thread */
3031 (void) pthread_attr_setstacksize(&net_attr, stacksize);
3032 (void) pthread_attr_setstackaddr(&net_attr, stack_ptr);
3033 stack_ptr += stacksize + redzonesize;
3035 /* grab UDP port */
3036 bindnet();
3038 if (pthread_create(&net_thread, &net_attr, net_poll,
3039 NULL) != 0) {
3040 logerror("pthread_create failed - fatal");
3041 exit(1);
3043 DPRINT1(1, "init(%u): accepting messages from remote\n",
3044 mythreadno);
3047 (void) pthread_attr_destroy(&sys_attr);
3048 (void) pthread_attr_destroy(&net_attr);
3049 (void) pthread_attr_destroy(&log_attr);
3050 (void) pthread_attr_destroy(&hnl_attr);
3052 curalarm = MarkInterval * 60 / MARKCOUNT;
3053 (void) alarm((unsigned)curalarm);
3054 DPRINT2(2, "init(%u): Next alarm in %d seconds\n",
3055 mythreadno, curalarm);
3056 DPRINT1(1, "init(%u): syslogd: started\n", mythreadno);
3060 * will print a bunch of debugging stats on 'fd'
3062 static void
3063 dumpstats(int fd)
3065 FILE *out;
3066 struct filed *f;
3067 int i;
3068 char users[1024];
3069 char cbuf[30];
3070 char *dashes = "------------------------";
3071 static int conversion_printed;
3073 if ((out = fdopen(fd, "w+")) == NULL)
3074 return;
3076 (void) fprintf(out, "\nSyslogd started: %s",
3077 ctime_r(&start_time, cbuf));
3078 (void) fprintf(out, "Input message count: system %d, network %d\n",
3079 sys_msg_count, net_msg_count);
3080 (void) fprintf(out, "# Outputs: %d\n\n", nlogs);
3082 (void) fprintf(out, "%s priority = [file, facility] %s\n\n",
3083 dashes, dashes);
3085 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3086 (void) fprintf(out, "%d ", i / 10);
3088 (void) fprintf(out, "\n");
3089 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3090 (void) fprintf(out, "%d ", i % 10);
3092 (void) fprintf(out, "\n");
3093 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3094 (void) fprintf(out, "--");
3096 (void) fprintf(out, "\n");
3098 for (f = Files; f < &Files[nlogs]; f++) {
3099 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3100 if (f->f_pmask[i] == NOPRI)
3101 (void) fprintf(out, "X ");
3102 else
3103 (void) fprintf(out, "%d ",
3104 f->f_pmask[i]);
3106 (void) fprintf(out, "%s: ", TypeNames[f->f_type]);
3107 switch (f->f_type) {
3108 case F_FILE:
3109 case F_TTY:
3110 case F_CONSOLE:
3111 (void) fprintf(out, "%s", f->f_un.f_fname);
3112 break;
3113 case F_FORW:
3114 (void) fprintf(out, "%s", f->f_un.f_forw.f_hname);
3115 break;
3116 case F_USERS:
3117 for (i = 0; i < MAXUNAMES &&
3118 *f->f_un.f_uname[i]; i++) {
3119 if (!i)
3120 (void) fprintf(out, "%s",
3121 f->f_un.f_uname[i]);
3122 else
3123 (void) fprintf(out, ", %s",
3124 f->f_un.f_uname[i]);
3126 break;
3128 (void) fprintf(out, "\n");
3131 if (!conversion_printed) {
3132 (void) fprintf(out, "\nFacilities:\n");
3134 for (i = 0; FacNames[i].c_val != -1; i++) {
3135 (void) fprintf(out, " [%02d] %s: %3d\n", i,
3136 FacNames[i].c_name, FacNames[i].c_val);
3139 (void) fprintf(out, "\nPriorities:\n");
3141 for (i = 0; PriNames[i].c_val != -1; i++) {
3142 (void) fprintf(out, " [%02d] %s: %3d\n", i,
3143 PriNames[i].c_name, PriNames[i].c_val);
3146 conversion_printed = 1;
3149 (void) fprintf(out, "\n\n\n\t\tPer File Statistics\n");
3150 (void) fprintf(out, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File");
3151 (void) fprintf(out, "%-24s\t---\t----\t-----\t----\n", "----");
3152 for (f = Files; f < &Files[nlogs]; f++) {
3153 switch (f->f_type) {
3154 case F_FILE:
3155 case F_TTY:
3156 case F_CONSOLE:
3157 (void) fprintf(out, "%-24s", f->f_un.f_fname);
3158 break;
3159 case F_WALL:
3160 (void) fprintf(out, "%-24s", TypeNames[f->f_type]);
3161 break;
3162 case F_FORW:
3163 (void) fprintf(out, "%-24s", f->f_un.f_forw.f_hname);
3164 break;
3165 case F_USERS:
3166 for (i = 0; i < MAXUNAMES &&
3167 *f->f_un.f_uname[i]; i++) {
3168 if (!i)
3169 (void) strcpy(users,
3170 f->f_un.f_uname[i]);
3171 else {
3172 (void) strcat(users, ",");
3173 (void) strcat(users,
3174 f->f_un.f_uname[i]);
3177 (void) fprintf(out, "%-24s", users);
3178 break;
3180 (void) fprintf(out, "\t%d\t%d\t%d\t%d\n",
3181 f->f_stat.total, f->f_stat.dups,
3182 f->f_stat.cantfwd, f->f_stat.errs);
3184 (void) fprintf(out, "\n\n");
3185 if (Debug && fd == 1)
3186 return;
3187 (void) fclose(out);
3191 * conf_init - This routine is code seperated from the
3192 * init routine in order to be re-callable when we get
3193 * a SIGHUP signal.
3195 static void
3196 conf_init(void)
3198 char *p;
3199 int i;
3200 struct filed *f;
3201 char *m4argv[4];
3202 int m4argc = 0;
3203 conf_t cf;
3204 pthread_t mythreadno;
3206 if (Debug) {
3207 mythreadno = pthread_self();
3210 DPRINT1(2, "conf_init(%u): starting logger threads\n",
3211 mythreadno);
3213 m4argv[m4argc++] = "m4";
3215 if (amiloghost() == 1) {
3216 DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno);
3217 m4argv[m4argc++] = "-DLOGHOST=1";
3220 m4argv[m4argc++] = ConfFile;
3221 m4argv[m4argc] = NULL;
3224 * Make sure the configuration file and m4 exist, and then parse
3225 * the configuration file with m4. If any of these fail, resort
3226 * to our hardcoded fallback configuration.
3229 if (access(ConfFile, R_OK) == -1) {
3230 DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno,
3231 ConfFile);
3232 logerror("can't open configuration file");
3233 /* CSTYLED */
3234 Files = (struct filed *) &fallback; /*lint !e545 */
3235 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3236 cfline("*.PANIC\t*", 0, &Files[1]);
3237 nlogs = 2;
3238 goto nofile;
3241 if (checkm4() != 0 || conf_open(&cf, "/usr/ccs/bin/m4", m4argv) == -1) {
3242 DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno,
3243 ConfFile);
3244 /* CSTYLED */
3245 Files = (struct filed *) &fallback; /*lint !e545 */
3246 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3247 cfline("*.PANIC\t*", 0, &Files[1]);
3248 nlogs = 2;
3249 goto nofile;
3252 /* Count the number of lines which are not blanks or comments */
3253 nlogs = 0;
3254 while ((p = conf_read(&cf)) != NULL) {
3255 if (p[0] != '\0' && p[0] != '#')
3256 nlogs++;
3259 Files = (struct filed *)malloc(sizeof (struct filed) * nlogs);
3261 if (!Files) {
3262 DPRINT1(1, "conf_init(%u): malloc failed - can't "
3263 "allocate 'Files' array\n", mythreadno);
3264 MALLOC_FAIL("loading minimum configuration");
3265 /* CSTYLED */
3266 Files = (struct filed *) &fallback; /*lint !e545 */
3267 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3268 cfline("*.PANIC\t*", 0, &Files[1]);
3269 nlogs = 2;
3270 conf_close(&cf);
3271 goto nofile;
3275 * Foreach line in the conf table, open that file.
3277 conf_rewind(&cf);
3278 f = Files;
3279 i = 0;
3280 while (((p = conf_read(&cf)) != NULL) && (f < &Files[nlogs])) {
3281 i++;
3282 /* check for end-of-section */
3283 if (p[0] == '\0' || p[0] == '#')
3284 continue;
3286 cfline(p, i, f);
3287 if (f->f_type == F_UNUSED)
3288 nlogs--;
3289 else
3290 f++;
3293 conf_close(&cf);
3296 * See if marks are to be written to any files. If so, set up a
3297 * timeout for marks.
3299 nofile:
3300 Marking = 0;
3303 * allocate thread stacks - one for each logger thread.
3305 if ((cstack_ptr = alloc_stacks(nlogs)) == NULL) {
3306 logerror("alloc_stacks failed - fatal");
3307 exit(1);
3310 /* And now one thread for each configured file */
3311 for (f = Files; f < &Files[nlogs]; f++) {
3312 if (filed_init(f) != 0) {
3313 logerror("pthread_create failed - fatal");
3314 exit(1);
3317 (void) pthread_mutex_lock(&cft);
3318 ++conf_threads;
3319 (void) pthread_mutex_unlock(&cft);
3321 if (f->f_type != F_UNUSED &&
3322 f->f_pmask[LOG_NFACILITIES] != NOPRI)
3323 Marking = 1;
3328 * filed init - initialize fields in a file descriptor struct
3329 * this is called before multiple threads are running, so no mutex
3330 * needs to be held at this time.
3332 static int
3333 filed_init(struct filed *f)
3335 pthread_attr_t stack_attr;
3336 pthread_t mythreadno;
3338 if (Debug) {
3339 mythreadno = pthread_self();
3342 if (pthread_mutex_init(&f->filed_mutex, NULL) != 0) {
3343 logerror("pthread_mutex_init failed");
3344 return (-1);
3347 DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n",
3348 mythreadno, (void *)&f->f_queue);
3349 (void) dataq_init(&f->f_queue);
3351 if (pthread_attr_init(&stack_attr) != 0) {
3352 logerror("pthread_attr_init failed");
3353 return (-1);
3356 (void) pthread_attr_setstacksize(&stack_attr, stacksize);
3357 (void) pthread_attr_setstackaddr(&stack_attr, cstack_ptr);
3358 cstack_ptr += stacksize + redzonesize;
3360 f->f_msgflag = 0;
3361 f->f_prevmsg.msg[0] = '\0';
3362 f->f_prevmsg.flags = 0;
3363 f->f_prevmsg.pri = 0;
3364 f->f_prevmsg.host[0] = '\0';
3366 f->f_current.msg[0] = '\0';
3367 f->f_current.flags = 0;
3368 f->f_current.pri = 0;
3369 f->f_current.host[0] = '\0';
3371 f->f_prevcount = 0;
3373 f->f_stat.flag = 0;
3374 f->f_stat.total = 0;
3375 f->f_stat.dups = 0;
3376 f->f_stat.cantfwd = 0;
3377 f->f_stat.errs = 0;
3379 if (pthread_create(&f->f_thread, NULL, logit, (void *)f) != 0) {
3380 logerror("pthread_create failed");
3381 (void) pthread_attr_destroy(&stack_attr);
3382 return (-1);
3385 (void) pthread_attr_destroy(&stack_attr);
3386 return (0);
3391 * Crack a configuration file line
3393 static void
3394 cfline(char *line, int lineno, struct filed *f)
3396 char *p;
3397 char *q;
3398 int i;
3399 char *bp;
3400 int pri;
3401 char buf[MAXLINE];
3402 char ebuf[SYS_NMLN+1+40];
3403 mode_t fmode, omode = O_WRONLY|O_APPEND|O_NOCTTY;
3404 struct stat64 sbuf;
3405 pthread_t mythreadno;
3407 if (Debug) {
3408 mythreadno = pthread_self();
3411 DPRINT2(1, "cfline(%u): (%s)\n", mythreadno, line);
3413 errno = 0; /* keep errno related stuff out of logerror messages */
3415 /* clear out file entry */
3416 bzero((char *)f, sizeof (*f));
3417 for (i = 0; i <= LOG_NFACILITIES; i++)
3418 f->f_pmask[i] = NOPRI;
3420 /* scan through the list of selectors */
3421 for (p = line; *p && *p != '\t'; ) {
3423 /* find the end of this facility name list */
3424 for (q = p; *q && *q != '\t' && *q++ != '.'; )
3425 continue;
3427 /* collect priority name */
3428 for (bp = buf; *q && !strchr("\t,;", *q); )
3429 *bp++ = *q++;
3430 *bp = '\0';
3432 /* skip cruft */
3433 while (strchr(", ;", *q))
3434 q++;
3436 /* decode priority name */
3437 pri = decode(buf, PriNames);
3438 if (pri < 0) {
3439 logerror("line %d: unknown priority name \"%s\"",
3440 lineno, buf);
3441 return;
3444 /* scan facilities */
3445 while (*p && !strchr("\t.;", *p)) {
3446 for (bp = buf; *p && !strchr("\t,;.", *p); )
3447 *bp++ = *p++;
3448 *bp = '\0';
3449 if (*buf == '*')
3450 for (i = 0; i < LOG_NFACILITIES; i++)
3451 f->f_pmask[i] = (uchar_t)pri;
3452 else {
3453 i = decode(buf, FacNames);
3454 if (i < 0) {
3455 logerror("line %d: unknown facility"
3456 " name \"%s\"", lineno, buf);
3457 return;
3459 f->f_pmask[i >> 3] = (uchar_t)pri;
3461 while (*p == ',' || *p == ' ')
3462 p++;
3465 p = q;
3468 /* skip to action part */
3469 while (*p == '\t' || *p == ' ')
3470 p++;
3472 switch (*p) {
3473 case '\0':
3474 errno = 0;
3475 logerror("line %d: no action part", lineno);
3476 break;
3478 case '@':
3479 (void) strlcpy(f->f_un.f_forw.f_hname, ++p, SYS_NMLN);
3480 if (logforward(f, ebuf, sizeof (ebuf)) != 0) {
3481 logerror("line %d: %s", lineno, ebuf);
3482 break;
3484 f->f_type = F_FORW;
3485 break;
3487 case '/':
3488 (void) strlcpy(f->f_un.f_fname, p, MAXPATHLEN);
3489 if (stat64(p, &sbuf) < 0) {
3490 logerror(p);
3491 break;
3494 * don't block trying to open a pipe
3495 * with no reader on the other end
3497 fmode = 0; /* reset each pass */
3498 if (S_ISFIFO(sbuf.st_mode))
3499 fmode = O_NONBLOCK;
3501 f->f_file = open64(p, omode|fmode);
3502 if (f->f_file < 0) {
3503 if (fmode && errno == ENXIO) {
3504 errno = 0;
3505 logerror("%s - no reader", p);
3506 } else
3507 logerror(p);
3508 break;
3512 * Fifos are initially opened NONBLOCK
3513 * to insure we don't hang, but once
3514 * we are open, we need to change the
3515 * behavior back to blocking, otherwise
3516 * we may get write errors, and the log
3517 * will get closed down the line.
3519 if (S_ISFIFO(sbuf.st_mode))
3520 (void) fcntl(f->f_file, F_SETFL, omode);
3522 if (isatty(f->f_file)) {
3523 f->f_type = F_TTY;
3524 untty();
3525 } else
3526 f->f_type = F_FILE;
3528 if ((strcmp(p, ctty) == 0) || (strcmp(p, sysmsg) == 0))
3529 f->f_type = F_CONSOLE;
3530 break;
3532 case '*':
3533 f->f_type = F_WALL;
3534 break;
3536 default:
3537 for (i = 0; i < MAXUNAMES && *p; i++) {
3538 for (q = p; *q && *q != ','; )
3539 q++;
3540 (void) strlcpy(f->f_un.f_uname[i], p, UNAMESZ);
3541 if ((q - p) > UNAMESZ)
3542 f->f_un.f_uname[i][UNAMESZ] = '\0';
3543 else
3544 f->f_un.f_uname[i][q - p] = '\0';
3545 while (*q == ',' || *q == ' ')
3546 q++;
3547 p = q;
3549 f->f_type = F_USERS;
3550 break;
3552 f->f_orig_type = f->f_type;
3557 * Decode a symbolic name to a numeric value
3559 static int
3560 decode(char *name, struct code *codetab)
3562 struct code *c;
3563 char *p;
3564 char buf[40];
3566 if (isdigit(*name))
3567 return (atoi(name));
3569 (void) strncpy(buf, name, sizeof (buf) - 1);
3570 for (p = buf; *p; p++)
3571 if (isupper(*p))
3572 *p = tolower(*p);
3573 for (c = codetab; c->c_name; c++)
3574 if (!(strcmp(buf, c->c_name)))
3575 return (c->c_val);
3577 return (-1);
3580 static int
3581 ismyaddr(struct netbuf *nbp)
3583 int i;
3585 if (nbp == NULL)
3586 return (0);
3588 for (i = 1; i < Ninputs; i++) {
3589 if (same_addr(nbp, Myaddrs[i]))
3590 return (1);
3592 return (0);
3595 static void
3596 getnets(void)
3598 struct nd_hostserv hs;
3599 struct netconfig *ncp;
3600 struct nd_addrlist *nap;
3601 struct netbuf *nbp;
3602 int i, inputs;
3603 void *handle;
3604 char *uap;
3605 pthread_t mythreadno;
3607 if (Debug) {
3608 mythreadno = pthread_self();
3611 if (turnoff) {
3612 DPRINT1(1, "getnets(%u): network is being turned off\n",
3613 mythreadno);
3614 return;
3617 hs.h_host = HOST_SELF;
3618 hs.h_serv = "syslog";
3620 if ((handle = setnetconfig()) == NULL) {
3621 return;
3624 while ((ncp = getnetconfig(handle)) != NULL) {
3625 if (ncp->nc_semantics != NC_TPI_CLTS) {
3626 continue;
3629 if (netdir_getbyname(ncp, &hs, &nap) != 0) {
3630 continue;
3633 if (nap == NULL || nap->n_cnt <= 0) {
3634 DPRINT1(1, "getnets(%u): found no address\n",
3635 mythreadno);
3636 netdir_free((void *)nap, ND_ADDRLIST);
3637 continue;
3640 if (Debug) {
3641 DPRINT2(1, "getnets(%u): found %d addresses",
3642 mythreadno, nap->n_cnt);
3643 DPRINT0(1, ", they are: ");
3644 nbp = nap->n_addrs;
3646 for (i = 0; i < nap->n_cnt; i++) {
3647 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
3648 DPRINT1(1, "%s ", uap);
3649 free(uap);
3651 nbp++;
3654 DPRINT0(1, "\n");
3657 inputs = Ninputs + nap->n_cnt;
3659 Nfd = realloc(Nfd, inputs * sizeof (struct pollfd));
3660 Ncf = realloc(Ncf, inputs * sizeof (struct netconfig));
3661 Myaddrs = realloc(Myaddrs, inputs * sizeof (struct netbuf *));
3662 Udp = realloc(Udp, inputs * sizeof (struct t_unitdata *));
3663 Errp = realloc(Errp, inputs * sizeof (struct t_uderr *));
3666 * all malloc failures here are fatal
3668 if (Nfd == NULL || Ncf == NULL || Myaddrs == NULL ||
3669 Udp == NULL || Errp == NULL) {
3670 MALLOC_FAIL_EXIT;
3673 nbp = nap->n_addrs;
3675 for (i = 0; i < nap->n_cnt; i++, nbp++) {
3676 char ebuf[128];
3678 if (addnet(ncp, nbp) == 0) {
3679 /* no error */
3680 continue;
3683 (void) strcpy(ebuf, "Unable to configure syslog port");
3685 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
3686 size_t l = strlen(ebuf);
3687 (void) snprintf(ebuf + l, sizeof (ebuf) - l,
3688 " for %s", uap);
3691 DPRINT2(1, "getnets(%u): %s",
3692 mythreadno, ebuf);
3694 if (uap) {
3695 free(uap);
3698 logerror(ebuf);
3700 * Here maybe syslogd can quit. However, syslogd
3701 * has been ignoring this error and keep running.
3702 * So we won't break it.
3706 netdir_free((void *)nap, ND_ADDRLIST);
3709 (void) endnetconfig(handle);
3713 * Open the network device, and allocate necessary resources.
3714 * Myaddrs will also be filled, so that we can call ismyaddr() before
3715 * being bound to the network.
3717 static int
3718 addnet(struct netconfig *ncp, struct netbuf *nbp)
3720 int fd;
3721 struct netbuf *bp;
3723 fd = t_open(ncp->nc_device, O_RDWR, NULL);
3725 if (fd < 0) {
3726 return (1);
3729 (void) memcpy(&Ncf[Ninputs], ncp, sizeof (struct netconfig));
3731 /*LINTED*/
3732 Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR);
3734 if (Udp[Ninputs] == NULL) {
3735 (void) t_close(fd);
3736 return (1);
3739 /*LINTED*/
3740 Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR);
3742 if (Errp[Ninputs] == NULL) {
3743 (void) t_close(fd);
3744 (void) t_free((char *)Udp[Ninputs], T_UNITDATA);
3745 return (1);
3748 if ((bp = malloc(sizeof (struct netbuf))) == NULL ||
3749 (bp->buf = malloc(nbp->len)) == NULL) {
3750 MALLOC_FAIL("allocating address buffer");
3751 (void) t_close(fd);
3752 (void) t_free((char *)Udp[Ninputs], T_UNITDATA);
3753 (void) t_free((char *)Errp[Ninputs], T_UDERROR);
3755 if (bp) {
3756 free(bp);
3759 return (1);
3762 bp->len = nbp->len;
3763 (void) memcpy(bp->buf, nbp->buf, nbp->len);
3764 Myaddrs[Ninputs] = bp;
3766 Nfd[Ninputs].fd = fd;
3767 Nfd[Ninputs].events = POLLIN;
3768 Ninputs++;
3769 return (0);
3773 * Allocate UDP buffer to minimize packet loss.
3775 static void
3776 set_udp_buffer(int fd)
3778 struct t_optmgmt req, resp;
3779 struct opthdr *opt;
3780 size_t optsize, bsize = 256 * 1024;
3781 pthread_t mythreadno;
3783 if (Debug) {
3784 mythreadno = pthread_self();
3787 optsize = sizeof (struct opthdr) + sizeof (int);
3788 if ((opt = malloc(optsize)) == NULL) {
3789 MALLOC_FAIL("will have no udp buffer");
3790 return;
3792 opt->level = SOL_SOCKET;
3793 opt->name = SO_RCVBUF;
3794 opt->len = sizeof (int);
3795 *(int *)(opt + 1) = bsize;
3797 req.flags = T_NEGOTIATE;
3798 req.opt.len = optsize;
3799 req.opt.buf = (char *)opt;
3801 resp.flags = 0;
3802 resp.opt.maxlen = optsize;
3803 resp.opt.buf = (char *)opt;
3805 while (t_optmgmt(fd, &req, &resp) == -1 || resp.flags != T_SUCCESS) {
3806 if (t_errno != TSYSERR || errno != ENOBUFS) {
3807 bsize = 0;
3808 break;
3810 bsize >>= 1;
3811 if (bsize < 8192) {
3812 break;
3814 *(int *)(opt + 1) = bsize;
3816 if (bsize == 0) {
3817 logerror("failed to allocate UDP buffer");
3819 DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n",
3820 mythreadno, bsize, fd);
3821 free(opt);
3825 * Attach the network, and allocate UDP buffer for the interface.
3827 static void
3828 bindnet(void)
3830 struct t_bind bind, *bound;
3831 int cnt, i;
3832 char *uap;
3833 pthread_t mythreadno;
3835 if (Debug) {
3836 mythreadno = pthread_self();
3839 cnt = 0;
3841 while (cnt < Ninputs) {
3842 char ebuf[128];
3844 /*LINTED*/
3845 bound = (struct t_bind *)t_alloc(Nfd[cnt].fd, T_BIND, T_ADDR);
3846 bind.addr = *Myaddrs[cnt];
3847 bind.qlen = 0;
3849 if (t_bind(Nfd[cnt].fd, &bind, bound) == 0) {
3850 if (same_addr(&bind.addr, &bound->addr)) {
3851 (void) t_free((char *)bound, T_BIND);
3852 set_udp_buffer(Nfd[cnt].fd);
3853 cnt++;
3854 continue;
3858 /* failed to bind port */
3859 (void) t_free((char *)bound, T_BIND);
3861 (void) strcpy(ebuf, "Unable to bind syslog port");
3863 uap = taddr2uaddr(&Ncf[cnt], Myaddrs[cnt]);
3864 if (uap) {
3865 i = strlen(ebuf);
3866 (void) snprintf(ebuf + i, sizeof (ebuf) - i,
3867 " for %s", uap);
3870 DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n",
3871 mythreadno, uap ? uap : "<unknown>");
3873 if (uap) {
3874 free(uap);
3877 errno = 0;
3878 logerror(ebuf);
3880 (void) t_close(Nfd[cnt].fd);
3881 free(Myaddrs[cnt]->buf);
3882 free(Myaddrs[cnt]);
3883 (void) t_free((char *)Udp[cnt], T_UNITDATA);
3884 (void) t_free((char *)Errp[cnt], T_UDERROR);
3886 for (i = cnt; i < (Ninputs-1); i++) {
3887 Nfd[i] = Nfd[i + 1];
3888 Ncf[i] = Ncf[i + 1];
3889 Myaddrs[i] = Myaddrs[i + 1];
3890 Udp[i] = Udp[i + 1];
3891 Errp[i] = Errp[i + 1];
3894 Ninputs--;
3898 static int
3899 logforward(struct filed *f, char *ebuf, size_t elen)
3901 struct nd_hostserv hs;
3902 struct netbuf *nbp;
3903 struct netconfig *ncp;
3904 struct nd_addrlist *nap;
3905 void *handle;
3906 char *hp;
3908 hp = f->f_un.f_forw.f_hname;
3909 hs.h_host = hp;
3910 hs.h_serv = "syslog";
3912 if ((handle = setnetconfig()) == NULL) {
3913 (void) strlcpy(ebuf,
3914 "unable to rewind the netconfig database", elen);
3915 errno = 0;
3916 return (-1);
3918 nap = (struct nd_addrlist *)NULL;
3919 while ((ncp = getnetconfig(handle)) != NULL) {
3920 if (ncp->nc_semantics == NC_TPI_CLTS) {
3921 if (netdir_getbyname(ncp, &hs, &nap) == 0) {
3922 if (!nap)
3923 continue;
3924 nbp = nap->n_addrs;
3925 break;
3929 if (ncp == NULL) {
3930 (void) endnetconfig(handle);
3931 (void) snprintf(ebuf, elen,
3932 "WARNING: %s could not be resolved", hp);
3933 errno = 0;
3934 return (-1);
3936 if (nap == (struct nd_addrlist *)NULL) {
3937 (void) endnetconfig(handle);
3938 (void) snprintf(ebuf, elen, "unknown host %s", hp);
3939 errno = 0;
3940 return (-1);
3942 /* CSTYLED */
3943 if (ismyaddr(nbp)) { /*lint !e644 */
3944 netdir_free((void *)nap, ND_ADDRLIST);
3945 (void) endnetconfig(handle);
3946 (void) snprintf(ebuf, elen,
3947 "host %s is this host - logging loop", hp);
3948 errno = 0;
3949 return (-1);
3951 f->f_un.f_forw.f_addr.buf = malloc(nbp->len);
3952 if (f->f_un.f_forw.f_addr.buf == NULL) {
3953 netdir_free((void *)nap, ND_ADDRLIST);
3954 (void) endnetconfig(handle);
3955 (void) strlcpy(ebuf, "malloc failed", elen);
3956 return (-1);
3958 bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len);
3959 f->f_un.f_forw.f_addr.len = nbp->len;
3960 f->f_file = t_open(ncp->nc_device, O_RDWR, NULL);
3961 if (f->f_file < 0) {
3962 netdir_free((void *)nap, ND_ADDRLIST);
3963 (void) endnetconfig(handle);
3964 free(f->f_un.f_forw.f_addr.buf);
3965 (void) strlcpy(ebuf, "t_open", elen);
3966 return (-1);
3968 netdir_free((void *)nap, ND_ADDRLIST);
3969 (void) endnetconfig(handle);
3970 if (t_bind(f->f_file, NULL, NULL) < 0) {
3971 (void) strlcpy(ebuf, "t_bind", elen);
3972 free(f->f_un.f_forw.f_addr.buf);
3973 (void) t_close(f->f_file);
3974 return (-1);
3976 return (0);
3979 static int
3980 amiloghost(void)
3982 struct nd_hostserv hs;
3983 struct netconfig *ncp;
3984 struct nd_addrlist *nap;
3985 struct netbuf *nbp;
3986 int i, fd;
3987 void *handle;
3988 char *uap;
3989 struct t_bind bind, *bound;
3990 pthread_t mythreadno;
3992 if (Debug) {
3993 mythreadno = pthread_self();
3997 * we need to know if we are running on the loghost. This is
3998 * checked by binding to the address associated with "loghost"
3999 * and "syslogd" service over the connectionless transport
4001 hs.h_host = "loghost";
4002 hs.h_serv = "syslog";
4004 if ((handle = setnetconfig()) == NULL) {
4005 return (0);
4008 while ((ncp = getnetconfig(handle)) != NULL) {
4009 if (ncp->nc_semantics != NC_TPI_CLTS) {
4010 continue;
4013 if (netdir_getbyname(ncp, &hs, &nap) != 0) {
4014 continue;
4017 if (nap == NULL) {
4018 continue;
4021 nbp = nap->n_addrs;
4023 for (i = 0; i < nap->n_cnt; i++) {
4024 if ((uap = taddr2uaddr(ncp, nbp)) != (char *)NULL) {
4025 DPRINT2(1, "amiloghost(%u): testing %s\n",
4026 mythreadno, uap);
4029 free(uap);
4031 fd = t_open(ncp->nc_device, O_RDWR, NULL);
4033 if (fd < 0) {
4034 netdir_free((void *)nap, ND_ADDRLIST);
4035 (void) endnetconfig(handle);
4036 return (0);
4039 /*LINTED*/
4040 bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
4041 bind.addr = *nbp;
4042 bind.qlen = 0;
4044 if (t_bind(fd, &bind, bound) == 0) {
4045 (void) t_close(fd);
4046 (void) t_free((char *)bound, T_BIND);
4047 netdir_free((void *)nap, ND_ADDRLIST);
4048 (void) endnetconfig(handle);
4049 return (1);
4050 } else {
4051 (void) t_close(fd);
4052 (void) t_free((char *)bound, T_BIND);
4055 nbp++;
4058 netdir_free((void *)nap, ND_ADDRLIST);
4061 (void) endnetconfig(handle);
4062 return (0);
4066 same_addr(struct netbuf *na, struct netbuf *nb)
4068 char *a, *b;
4069 size_t n;
4071 assert(na->buf != NULL && nb->buf != NULL);
4073 if (na->len != nb->len) {
4074 return (0);
4077 a = na->buf;
4078 b = nb->buf;
4079 n = nb->len;
4081 while (n-- > 0) {
4082 if (*a++ != *b++) {
4083 return (0);
4087 return (1);
4091 * allocates a new message structure, initializes it
4092 * and returns a pointer to it
4094 static log_message_t *
4095 new_msg(void)
4097 log_message_t *lm;
4098 pthread_t mythreadno;
4100 if (Debug) {
4101 mythreadno = pthread_self();
4104 if ((lm = malloc(sizeof (log_message_t))) == NULL)
4105 return ((log_message_t *)NULL);
4107 if (pthread_mutex_init(&lm->msg_mutex, NULL) != 0)
4108 return ((log_message_t *)NULL);
4109 lm->refcnt = 0;
4110 lm->pri = 0;
4111 lm->flags = 0;
4112 lm->hlp = NULL;
4113 lm->msg[0] = '\0';
4114 lm->ptr = NULL;
4116 DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno, (void *)lm);
4117 return (lm);
4121 * frees a message structure - should only be called if
4122 * the refcount is 0
4124 static void
4125 free_msg(log_message_t *lm)
4127 pthread_t mythreadno;
4129 if (Debug) {
4130 mythreadno = pthread_self();
4133 assert(lm != NULL && lm->refcnt == 0);
4134 if (lm->hlp != NULL)
4135 freehl(lm->hlp);
4136 DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno, (void *)lm);
4137 free(lm);
4141 * Make sure that the message makes sense in the current locale, and
4142 * does not contain stray control characters.
4144 static void
4145 filter_string(char *mbstr, char *filtered, size_t max)
4147 size_t cs = 0;
4148 size_t mb_cur_max;
4149 unsigned char *p = (unsigned char *)mbstr;
4150 pthread_t mythreadno = 0;
4152 if (Debug) {
4153 mythreadno = pthread_self();
4156 assert(mbstr != NULL && filtered != NULL);
4159 * Since the access to MB_CUR_MAX is expensive (because
4160 * MB_CUR_MAX lives in a global area), it should be
4161 * restrained for the better performance.
4163 mb_cur_max = (size_t)MB_CUR_MAX;
4164 if (mb_cur_max > 1) {
4165 /* multibyte locale */
4166 int mlen;
4167 wchar_t wc;
4169 while (*p != '\0') {
4170 if ((mlen = mbtowc(&wc, (char *)p,
4171 mb_cur_max)) == -1) {
4173 * Invalid byte sequence found.
4175 * try to print one byte
4176 * in ASCII format.
4178 DPRINT2(9, "filter_string(%u): Invalid "
4179 "MB sequence: %ld\n", mythreadno,
4180 wc);
4182 if (!putctrlc(*p++, &filtered, &cs, max)) {
4183 /* not enough buffer */
4184 goto end;
4185 } else {
4186 continue;
4188 } else {
4190 * Since *p is not a null byte here,
4191 * mbtowc should have never returned 0.
4193 * A valid wide character found.
4196 if (wc != L'\t' && iswcntrl(wc)) {
4198 * non-tab, non-newline, and
4199 * control character found.
4201 * try to print this wide character
4202 * in ASCII-format.
4204 char *q = filtered;
4206 DPRINT2(9, "filter_string(%u): MB"
4207 " control character: %ld\n",
4208 mythreadno, wc);
4210 while (mlen--) {
4211 if (!putctrlc(*p++, &filtered,
4212 &cs, max)) {
4214 * not enough buffer in
4215 * filtered
4217 * cancel already
4218 * stored bytes in
4219 * filtered for this
4220 * wide character.
4222 filtered = q;
4223 goto end;
4226 continue;
4227 } else {
4229 * tab, newline, or non-control
4230 * character found.
4232 if (cs + mlen < max) {
4233 /* enough buffer */
4234 cs += mlen;
4235 while (mlen--) {
4236 *filtered++ = *p++;
4238 continue;
4239 } else {
4240 /* not enough buffer */
4241 goto end;
4246 } else {
4247 /* singlebyte locale */
4249 while (*p != '\0') {
4250 if (*p != '\t' && iscntrl(*p)) {
4252 * non-tab, non-newline,
4253 * and control character found.
4255 * try to print this singlebyte character
4256 * in ASCII format.
4258 DPRINT2(9, "filter_string(%u): control "
4259 "character: %d\n", mythreadno, *p);
4261 if (!putctrlc(*p++, &filtered, &cs, max)) {
4262 /* not enough buffer */
4263 goto end;
4264 } else {
4265 continue;
4267 } else if (*p != '\t' && !isprint(*p)) {
4269 * non-tab and non printable character found
4270 * this check is required for the C locale
4272 DPRINT2(9, "filter_string(%u): non-printable "
4273 "character: %d\n", mythreadno, *p);
4274 if (!putctrlc(*p++, &filtered, &cs, max)) {
4275 /* not enough buffer */
4276 goto end;
4277 } else {
4278 continue;
4280 } else {
4282 * tab, newline, non-control character, or
4283 * printable found.
4285 if (cs + 1 < max) {
4286 *filtered++ = *p++;
4287 cs++;
4288 continue;
4289 } else {
4290 /* not enough buffer */
4291 goto end;
4297 end:
4298 *filtered = '\0';
4300 if (cs >= 2 &&
4301 filtered[-2] == '\\' && filtered[-1] == 'n') {
4302 filtered[-2] = '\0';
4306 static char *
4307 alloc_stacks(int numstacks)
4309 size_t pagesize, mapsize;
4310 char *stack_top;
4311 char *addr;
4312 int i;
4314 pagesize = (size_t)sysconf(_SC_PAGESIZE);
4316 * stacksize and redzonesize are global so threads
4317 * can be created elsewhere and refer to the sizes
4319 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
4320 DEFAULT_STACKSIZE, pagesize);
4321 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
4324 * allocate an additional "redzonesize" chunk in addition
4325 * to what we require, so we can create a redzone at the
4326 * bottom of the last stack as well.
4328 mapsize = redzonesize + numstacks * (stacksize + redzonesize);
4329 stack_top = mmap(NULL, mapsize, PROT_READ|PROT_WRITE,
4330 MAP_PRIVATE|MAP_ANON, -1, 0);
4331 if (stack_top == MAP_FAILED)
4332 return (NULL);
4334 addr = stack_top;
4336 * this loop is intentionally <= instead of <, so we can
4337 * protect the redzone at the bottom of the last stack
4339 for (i = 0; i <= numstacks; i++) {
4340 (void) mprotect(addr, redzonesize, PROT_NONE);
4341 addr += stacksize + redzonesize;
4343 return ((char *)(stack_top + redzonesize));
4346 static void
4347 dealloc_stacks(int numstacks)
4349 size_t pagesize, mapsize;
4351 pagesize = (size_t)sysconf(_SC_PAGESIZE);
4353 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
4354 DEFAULT_STACKSIZE, pagesize);
4356 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
4358 mapsize = redzonesize + numstacks * (stacksize + redzonesize);
4359 (void) munmap(cstack_ptr - mapsize, mapsize);
4362 static void
4363 filed_destroy(struct filed *f)
4365 (void) dataq_destroy(&f->f_queue);
4366 (void) pthread_mutex_destroy(&f->filed_mutex);
4369 static void
4370 close_door(void)
4372 pthread_t mythreadno;
4374 if (Debug) {
4375 mythreadno = pthread_self();
4378 (void) fdetach(DoorFileName);
4380 DPRINT2(5, "close_door(%u): detached server() from %s\n",
4381 mythreadno, DoorFileName);
4384 static void
4385 delete_doorfiles(void)
4387 pthread_t mythreadno;
4388 struct stat sb;
4389 int err;
4390 char line[MAXLINE+1];
4392 if (Debug) {
4393 mythreadno = pthread_self();
4397 if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4398 if (unlink(DoorFileName) < 0) {
4399 err = errno;
4400 (void) snprintf(line, sizeof (line),
4401 "unlink() of %s failed - fatal", DoorFileName);
4402 errno = err;
4403 logerror(line);
4404 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4405 "errno=%d\n", mythreadno, line, err);
4406 exit(1);
4409 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4410 mythreadno, DoorFileName);
4413 if (strcmp(DoorFileName, DOORFILE) == 0) {
4414 if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4415 if (unlink(OLD_DOORFILE) < 0) {
4416 err = errno;
4417 (void) snprintf(line, sizeof (line),
4418 "unlink() of %s failed", OLD_DOORFILE);
4419 DPRINT2(5, "delete_doorfiles(%u): %s\n",
4420 mythreadno, line);
4422 if (err != EROFS) {
4423 errno = err;
4424 (void) strlcat(line, " - fatal",
4425 sizeof (line));
4426 logerror(line);
4427 DPRINT3(1, "delete_doorfiles(%u): "
4428 "error: %s, errno=%d\n",
4429 mythreadno, line, err);
4430 exit(1);
4433 DPRINT1(5, "delete_doorfiles(%u): unlink() "
4434 "failure OK on RO file system\n",
4435 mythreadno);
4438 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4439 mythreadno, OLD_DOORFILE);
4443 if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4444 if (unlink(PidFileName) < 0) {
4445 err = errno;
4446 (void) snprintf(line, sizeof (line),
4447 "unlink() of %s failed - fatal", PidFileName);
4448 errno = err;
4449 logerror(line);
4450 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4451 "errno=%d\n", mythreadno, line, err);
4452 exit(1);
4455 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno,
4456 PidFileName);
4459 if (strcmp(PidFileName, PIDFILE) == 0) {
4460 if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4461 if (unlink(OLD_PIDFILE) < 0) {
4462 err = errno;
4463 (void) snprintf(line, sizeof (line),
4464 "unlink() of %s failed", OLD_PIDFILE);
4465 DPRINT2(5, "delete_doorfiles(%u): %s, \n",
4466 mythreadno, line);
4468 if (err != EROFS) {
4469 errno = err;
4470 (void) strlcat(line, " - fatal",
4471 sizeof (line));
4472 logerror(line);
4473 DPRINT3(1, "delete_doorfiles(%u): "
4474 "error: %s, errno=%d\n",
4475 mythreadno, line, err);
4476 exit(1);
4479 DPRINT1(5, "delete_doorfiles(%u): unlink "
4480 "failure OK on RO file system\n",
4481 mythreadno);
4484 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4485 mythreadno, OLD_PIDFILE);
4489 if (DoorFd != -1) {
4490 (void) door_revoke(DoorFd);
4493 DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n",
4494 mythreadno, DoorFd);
4498 /*ARGSUSED*/
4499 static void
4500 signull(int sig, siginfo_t *sip, void *utp)
4502 DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n",
4503 pthread_self());
4505 * Do nothing, as this is a place-holder used in conjunction with
4506 * sigaction()/sigwait() to ensure that the proper disposition is
4507 * given to the signals we handle in main().
4512 * putctrlc returns zero, if failed due to not enough buffer.
4513 * Otherwise, putctrlc returns non-zero.
4515 * c: a byte to print in ASCII format
4516 * **buf: a pointer to the pointer to the output buffer.
4517 * *cl: current length of characters in the output buffer
4518 * max: maximum length of the buffer
4521 static int
4522 putctrlc(int c, char **buf, size_t *cl, size_t max)
4524 char *p = *buf;
4526 if (c == '\n') {
4527 if (*cl + 2 < max) {
4528 *p++ = '\\';
4529 *p++ = 'n';
4530 *cl += 2;
4531 *buf = p;
4532 return (2);
4533 } else {
4534 return (0);
4536 } else if (c < 0200) {
4537 /* ascii control character */
4538 if (*cl + 2 < max) {
4539 *p++ = '^';
4540 *p++ = c ^ 0100;
4541 *cl += 2;
4542 *buf = p;
4543 return (2);
4544 } else {
4545 return (0);
4547 } else {
4548 if (*cl + 4 < max) {
4549 *p++ = '\\';
4550 *p++ = ((c >> 6) & 07) + '0';
4551 *p++ = ((c >> 3) & 07) + '0';
4552 *p++ = (c & 07) + '0';
4553 *cl += 4;
4554 *buf = p;
4555 return (4);
4556 } else {
4557 return (0);
4563 * findnl_bkwd:
4564 * Scans each character in buf until it finds the last newline in buf,
4565 * or the scanned character becomes the last COMPLETE character in buf.
4566 * Returns the number of scanned bytes.
4568 * buf - pointer to a buffer containing the message string
4569 * len - the length of the buffer
4571 size_t
4572 findnl_bkwd(const char *buf, const size_t len)
4574 const char *p;
4575 size_t mb_cur_max;
4576 pthread_t mythreadno;
4578 if (Debug) {
4579 mythreadno = pthread_self();
4582 if (len == 0) {
4583 return (0);
4586 mb_cur_max = MB_CUR_MAX;
4588 if (mb_cur_max == 1) {
4589 /* single-byte locale */
4590 for (p = buf + len - 1; p != buf; p--) {
4591 if (*p == '\n') {
4592 return ((size_t)(p - buf));
4595 return ((size_t)len);
4596 } else {
4597 /* multi-byte locale */
4598 int mlen;
4599 const char *nl;
4600 size_t rem;
4602 p = buf;
4603 nl = NULL;
4604 for (rem = len; rem >= mb_cur_max; ) {
4605 mlen = mblen(p, mb_cur_max);
4606 if (mlen == -1) {
4608 * Invalid character found.
4610 DPRINT1(9, "findnl_bkwd(%u): Invalid MB "
4611 "sequence\n", mythreadno);
4613 * handle as a single byte character.
4615 p++;
4616 rem--;
4617 } else {
4619 * It's guaranteed that *p points to
4620 * the 1st byte of a multibyte character.
4622 if (*p == '\n') {
4623 nl = p;
4625 p += mlen;
4626 rem -= mlen;
4629 if (nl) {
4630 return ((size_t)(nl - buf));
4633 * no newline nor null byte found.
4634 * Also it's guaranteed that *p points to
4635 * the 1st byte of a (multibyte) character
4636 * at this point.
4638 return (len - rem);
4643 * copynl_frwd:
4644 * Scans each character in buf and copies the scanned character to obuf
4645 * until it finds a null byte or a newline, or
4646 * the number of the remaining bytes in obuf gets to exceed obuflen
4647 * if copying the scanned character to obuf.
4648 * Returns the number of scanned bytes.
4650 * obuf - buffer to be copied the scanned character
4651 * obuflen - the size of obuf
4652 * buf - pointer to a buffer containing the message string
4653 * len - the length of the buffer
4655 size_t
4656 copynl_frwd(char *obuf, const size_t obuflen,
4657 const char *buf, const size_t len)
4659 const char *p;
4660 char *q = obuf;
4661 size_t olen = 0;
4662 size_t mb_cur_max;
4663 pthread_t mythreadno;
4665 if (Debug) {
4666 mythreadno = pthread_self();
4669 if (len == 0) {
4670 return (0);
4673 mb_cur_max = MB_CUR_MAX;
4675 if (mb_cur_max == 1) {
4676 /* single-byte locale */
4677 for (p = buf; *p; ) {
4678 if (obuflen > olen + 1) {
4679 if (*p != '\n') {
4680 *q++ = *p++;
4681 olen++;
4682 } else {
4683 *q = '\0';
4684 return ((size_t)(p - buf));
4686 } else {
4687 *q = '\0';
4688 return ((size_t)(p - buf));
4691 *q = '\0';
4692 return ((size_t)(p - buf));
4693 } else {
4694 /* multi-byte locale */
4695 int mlen;
4697 for (p = buf; *p; ) {
4698 mlen = mblen(p, mb_cur_max);
4699 if (mlen == -1) {
4701 * Invalid character found.
4703 DPRINT1(9, "copynl_frwd(%u): Invalid MB "
4704 "sequence\n", mythreadno);
4706 * handle as a single byte character.
4708 if (obuflen > olen + 1) {
4709 *q++ = *p++;
4710 olen++;
4711 } else {
4712 *q = '\0';
4713 return ((size_t)(p - buf));
4715 } else {
4717 * It's guaranteed that *p points to
4718 * the 1st byte of a multibyte character.
4720 if (*p == '\n') {
4721 *q = '\0';
4722 return ((size_t)(p - buf));
4724 if (obuflen > olen + mlen) {
4725 int n;
4726 for (n = 0; n < mlen; n++) {
4727 *q++ = *p++;
4729 olen += mlen;
4730 } else {
4731 *q = '\0';
4732 return ((size_t)(p - buf));
4737 * no newline nor null byte found.
4738 * Also it's guaranteed that *p points to
4739 * the 1st byte of a (multibyte) character
4740 * at this point.
4742 *q = '\0';
4743 return ((size_t)(p - buf));
4748 * copy_frwd:
4749 * Scans each character in buf and copies the scanned character to obuf
4750 * until the number of the remaining bytes in obuf gets to exceed obuflen
4751 * if copying the scanned character to obuf.
4752 * Returns the number of scanned (copied) bytes.
4754 * obuf - buffer to be copied the scanned character
4755 * obuflen - the size of obuf
4756 * buf - pointer to a buffer containing the message string
4757 * len - the length of the buffer
4759 size_t
4760 copy_frwd(char *obuf, const size_t obuflen,
4761 const char *buf, const size_t len)
4763 const char *p;
4764 char *q = obuf;
4765 size_t olen = 0;
4766 size_t mb_cur_max;
4767 pthread_t mythreadno;
4769 if (Debug) {
4770 mythreadno = pthread_self();
4773 if (len == 0) {
4774 return (0);
4777 mb_cur_max = MB_CUR_MAX;
4779 if (mb_cur_max == 1) {
4780 /* single-byte locale */
4781 if (obuflen > len) {
4782 (void) memcpy(obuf, buf, len);
4783 obuf[len] = '\0';
4784 return ((size_t)len);
4785 } else {
4786 (void) memcpy(obuf, buf, obuflen - 1);
4787 obuf[obuflen - 1] = '\0';
4788 return (obuflen - 1);
4790 } else {
4791 /* multi-byte locale */
4792 int mlen;
4794 for (p = buf; *p; ) {
4795 mlen = mblen(p, mb_cur_max);
4796 if (mlen == -1) {
4798 * Invalid character found.
4800 DPRINT1(9, "copy_frwd(%u): Invalid MB "
4801 "sequence\n", mythreadno);
4803 * handle as a single byte character.
4805 if (obuflen > olen + 1) {
4806 *q++ = *p++;
4807 olen++;
4808 } else {
4809 *q = '\0';
4810 return ((size_t)(p - buf));
4812 } else {
4813 if (obuflen > olen + mlen) {
4814 int n;
4815 for (n = 0; n < mlen; n++) {
4816 *q++ = *p++;
4818 olen += mlen;
4819 } else {
4820 *q = '\0';
4821 return ((size_t)(p - buf));
4825 *q = '\0';
4826 return ((size_t)(p - buf));
4831 * properties:
4832 * Get properties from SMF framework.
4834 static void
4835 properties(void)
4837 scf_simple_prop_t *prop;
4838 uint8_t *bool;
4840 if ((prop = scf_simple_prop_get(NULL, NULL, "config",
4841 "log_from_remote")) != NULL) {
4842 if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
4843 if (*bool == 0)
4844 turnoff = 1; /* log_from_remote = false */
4845 else
4846 turnoff = 0; /* log_from_remote = true */
4848 scf_simple_prop_free(prop);
4849 DPRINT1(1, "properties: setting turnoff to %s\n",
4850 turnoff ? "true" : "false");
4855 * close all the input devices.
4857 static void
4858 shutdown_input(void)
4860 int cnt;
4862 shutting_down = 1;
4864 for (cnt = 0; cnt < Ninputs; cnt++) {
4865 (void) t_close(Nfd[cnt].fd);
4868 (void) close(Pfd.fd);
4872 * This is for the one thread that dedicates to resolve the
4873 * hostname. This will get the messages from net_poll() through
4874 * hnlq, and resolve the hostname, and push the messages back
4875 * into the inputq.
4877 /*ARGSUSED*/
4878 static void *
4879 hostname_lookup(void *ap)
4881 char *uap;
4882 log_message_t *mp;
4883 host_info_t *hip;
4884 char failsafe_addr[SYS_NMLN + 1];
4885 pthread_t mythreadno;
4887 if (Debug) {
4888 mythreadno = pthread_self();
4891 DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n",
4892 mythreadno);
4894 for (;;) {
4895 (void) dataq_dequeue(&hnlq, (void **)&mp, 0);
4897 DPRINT3(5, "hostname_lookup(%u): dequeued msg %p"
4898 " from queue %p\n", mythreadno, (void *)mp,
4899 (void *)&hnlq);
4901 hip = (host_info_t *)mp->ptr;
4902 if ((uap = taddr2uaddr(hip->ncp, &hip->addr)) != NULL) {
4903 (void) strlcpy(failsafe_addr, uap, SYS_NMLN);
4904 free(uap);
4905 } else {
4906 (void) strlcpy(failsafe_addr, "<unknown>", SYS_NMLN);
4909 mp->hlp = cvthname(&hip->addr, hip->ncp, failsafe_addr);
4911 if (mp->hlp == NULL) {
4912 mp->hlp = &NullHostName;
4915 free(hip->addr.buf);
4916 free(hip);
4917 mp->ptr = NULL;
4919 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
4920 MALLOC_FAIL("dropping message from remote");
4921 free_msg(mp);
4922 continue;
4925 DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue "
4926 "%p\n", mythreadno, (void *)mp, (void *)&inputq);
4929 /*NOTREACHED*/
4930 return (NULL);
4934 * Does all HUP(re-configuration) process.
4936 static void
4937 reconfigure()
4939 int cnt, loop, drops;
4940 int really_stuck;
4941 int console_stuck = 0;
4942 struct filed *f;
4943 char buf[LINE_MAX];
4944 struct utsname up;
4945 char cbuf[30];
4946 time_t tim;
4947 pthread_t mythreadno;
4949 if (Debug) {
4950 mythreadno = pthread_self();
4953 /* If we get here then we must need to regen */
4954 flushmsg(0);
4956 if (logmymsg(LOG_SYSLOG|LOG_INFO, "syslogd: configuration restart",
4957 ADDDATE, 0) == -1) {
4958 MALLOC_FAIL("dropping message");
4962 * make sure the logmsg thread is not in the waiting state.
4963 * Otherwise, changing hup_state will prevent the logmsg thread
4964 * getting out from the waiting loop.
4967 if (Debug) {
4968 tim = time(NULL);
4969 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()"
4970 " moving to the safe place\n",
4971 mythreadno, ctime_r(&tim, cbuf)+4);
4974 for (loop = 0; loop < LOOP_MAX; loop++) {
4975 /* we don't need the mutex to read */
4976 if (hup_state == HUP_ACCEPTABLE)
4977 break;
4978 (void) sleep(1);
4980 if (hup_state != HUP_ACCEPTABLE) {
4981 goto thread_stuck;
4984 if (Debug) {
4985 tim = time(NULL);
4986 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n",
4987 mythreadno, ctime_r(&tim, cbuf)+4);
4991 * Prevent logging until we are truly done processing the HUP
4993 (void) pthread_mutex_lock(&hup_lock);
4994 hup_state = HUP_INPROGRESS;
4995 (void) pthread_mutex_unlock(&hup_lock);
4998 * We will be going into a critical state. Any error message
4999 * from syslogd needs to be dumped to the console by default
5000 * immediately. Also, those error messages are quened in a temporary
5001 * queue to be able to post into the regular stream later.
5003 disable_errorlog();
5005 if (Debug) {
5006 tim = time(NULL);
5007 DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n",
5008 mythreadno, ctime_r(&tim, cbuf)+4);
5011 /* stop configured threads */
5012 if (shutdown_msg() == -1) {
5014 * No memory, message will be dumped to the console.
5016 MALLOC_FAIL("unable to restart syslogd");
5017 goto out;
5020 /* make sure logmsg() is in suspended state */
5021 for (loop = 0; loop < LOOP_INTERVAL; loop++) {
5022 if (hup_state & HUP_LOGMSG_SUSPENDED)
5023 break;
5024 (void) sleep(1);
5027 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
5028 if (Debug) {
5029 tim = time(NULL);
5030 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not "
5031 "stop. enforcing\n",
5032 mythreadno, ctime_r(&tim, cbuf)+4);
5035 /* probably we have too long input queue, or really stuck */
5036 (void) pthread_mutex_lock(&hup_lock);
5037 hup_state |= HUP_SUSP_LOGMSG_REQD;
5038 (void) pthread_mutex_unlock(&hup_lock);
5040 for (loop = 0; loop < LOOP_MAX; loop++) {
5041 if (hup_state & HUP_LOGMSG_SUSPENDED)
5042 break;
5043 (void) sleep(1);
5045 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
5046 if (Debug) {
5047 tim = time(NULL);
5048 DPRINT2(3, "reconfigure(%u): %.15s: logmsg()"
5049 " does not stop. give up\n",
5050 mythreadno, ctime_r(&tim, cbuf)+4);
5052 logerror("could not suspend logmsg - fatal");
5053 goto thread_stuck;
5057 if (Debug) {
5058 tim = time(NULL);
5059 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n",
5060 mythreadno, ctime_r(&tim, cbuf)+4);
5064 * Will wait for LOOP_MAX secs with watching queue lengths for the
5065 * each logger threads. If they have backlogs, and no change in the
5066 * length of queue found in 30 seconds, those will be counted as
5067 * "really stuck".
5068 * If all running logger threads become "really stuck" state, there
5069 * should be no worth waiting for them to quit.
5070 * In that case, we will go ahead and close out file descriptors to
5071 * have them pull out from hanging system call, and give them a last
5072 * chance(LOOP_INTERVAL sec) to quit.
5075 if (Debug) {
5076 tim = time(NULL);
5077 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be"
5078 " shutdown\n", mythreadno, ctime_r(&tim, cbuf)+4);
5081 cnt = 0;
5082 really_stuck = 0;
5083 while (cnt < (LOOP_MAX/LOOP_INTERVAL) &&
5084 conf_threads > really_stuck) {
5086 /* save initial queue count */
5087 for (f = Files; f < &Files[nlogs]; f++) {
5088 f->f_prev_queue_count = (f->f_type == F_UNUSED) ?
5089 -1 : f->f_queue_count;
5092 for (loop = 0; loop < LOOP_INTERVAL; loop++) {
5093 if (conf_threads == 0)
5094 break;
5095 (void) sleep(1);
5098 if (conf_threads == 0)
5099 break;
5101 if (Debug) {
5102 tim = time(NULL);
5103 DPRINT3(3, "reconfigure(%u): %.15s: "
5104 "%d threads are still alive.\n",
5105 mythreadno, ctime_r(&tim, cbuf)+4,
5106 conf_threads);
5109 really_stuck = 0;
5110 for (f = Files; f < &Files[nlogs]; f++) {
5111 if (f->f_type == F_UNUSED) {
5112 f->f_prev_queue_count = -1;
5113 continue;
5115 if (f->f_prev_queue_count == f->f_queue_count) {
5116 really_stuck++;
5117 f->f_prev_queue_count = 1;
5118 DPRINT2(3, "reconfigure(%u): "
5119 "tid=%d is really stuck.\n",
5120 mythreadno, f->f_thread);
5121 } else {
5122 f->f_prev_queue_count = 0;
5123 DPRINT2(3, "reconfigure(%u): "
5124 "tid=%d is still active.\n",
5125 mythreadno, f->f_thread);
5129 * Here we have one of following values in the
5130 * f_prev_queue_count:
5131 * 0: logger thread is still actively working.
5132 * 1: logger thread is really stuck.
5133 * -1: logger thread has already died.
5136 cnt++;
5139 if (Debug) {
5140 tim = time(NULL);
5141 DPRINT2(3, "reconfigure(%u): %.15s:"
5142 " complete awaiting logit()\n",
5143 mythreadno, ctime_r(&tim, cbuf)+4);
5144 DPRINT3(3, "reconfigure(%u): %d threads alive."
5145 " %d threads stuck\n",
5146 mythreadno, conf_threads, really_stuck);
5150 * Still running? If so, mark it as UNUSED, and close
5151 * the fd so that logger threads can bail out from the loop.
5153 drops = 0;
5154 if (conf_threads) {
5155 for (f = Files; f < &Files[nlogs]; f++) {
5156 if (f->f_type == F_CONSOLE &&
5157 f->f_prev_queue_count == 1) {
5158 /* console is really stuck */
5159 console_stuck = 1;
5161 if (f->f_type == F_USERS || f->f_type == F_WALL ||
5162 f->f_type == F_UNUSED)
5163 continue;
5164 cnt = f->f_queue_count;
5165 drops += (cnt > 0) ? cnt - 1: 0;
5166 f->f_type = F_UNUSED;
5168 if (f->f_orig_type == F_FORW)
5169 (void) t_close(f->f_file);
5170 else
5171 (void) close(f->f_file);
5174 if (Debug) {
5175 tim = time(NULL);
5176 DPRINT1(3, "reconfigure(%u): terminating logit()\n",
5177 mythreadno);
5180 /* last chance to exit */
5181 for (loop = 0; loop < LOOP_MAX; loop++) {
5182 if (conf_threads == 0)
5183 break;
5184 (void) sleep(1);
5187 if (Debug) {
5188 tim = time(NULL);
5189 DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n",
5190 mythreadno, ctime_r(&tim, cbuf)+4,
5191 conf_threads);
5195 if (conf_threads == 0 && drops) {
5196 errno = 0;
5197 logerror("Could not completely output pending messages"
5198 " while preparing re-configuration");
5199 logerror("discarded %d messages and restart configuration.",
5200 drops);
5201 if (Debug) {
5202 tim = time(NULL);
5203 DPRINT3(3, "reconfigure(%u): %.15s: "
5204 "discarded %d messages\n",
5205 mythreadno, ctime_r(&tim, cbuf)+4, drops);
5210 * If all threads still haven't exited
5211 * something is stuck or hosed. We just
5212 * have no option but to exit.
5214 if (conf_threads) {
5215 thread_stuck:
5216 if (Debug) {
5217 tim = time(NULL);
5218 DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n",
5219 mythreadno, ctime_r(&tim, cbuf)+4);
5222 shutdown_input();
5223 delete_doorfiles();
5224 (void) uname(&up);
5226 (void) snprintf(buf, sizeof (buf),
5227 "syslogd(%s): some logger thread(s) "
5228 "are stuck%s; syslogd is shutting down.",
5229 up.nodename,
5230 console_stuck ? " (including the console)" : "");
5232 if (console_stuck) {
5233 FILE *m = popen(MAILCMD, "w");
5235 if (m != NULL) {
5236 (void) fprintf(m, "%s\n", buf);
5237 (void) pclose(m);
5241 disable_errorlog();
5242 logerror(buf);
5243 exit(1);
5246 /* Free up some resources */
5247 if (Files != (struct filed *)&fallback) {
5248 for (f = Files; f < &Files[nlogs]; f++) {
5249 (void) pthread_join(f->f_thread, NULL);
5250 filed_destroy(f);
5252 free(Files);
5255 dealloc_stacks(nlogs);
5257 if (Debug) {
5258 tim = time(NULL);
5259 DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n",
5260 mythreadno, ctime_r(&tim, cbuf)+4);
5263 hnc_init(1); /* purge hostname cache */
5264 conf_init(); /* start reconfigure */
5266 out:;
5267 /* Now should be ready to dispatch error messages from syslogd. */
5268 enable_errorlog();
5270 /* Wake up the log thread */
5272 if (Debug) {
5273 tim = time(NULL);
5274 DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n",
5275 mythreadno, ctime_r(&tim, cbuf)+4);
5278 (void) pthread_mutex_lock(&hup_lock);
5279 hup_state = HUP_COMPLETED;
5280 (void) pthread_cond_signal(&hup_done);
5281 (void) pthread_mutex_unlock(&hup_lock);
5285 * The following function implements simple hostname cache mechanism.
5286 * Host name cache is implemented through hash table bucket chaining method.
5287 * Collisions are handled by bucket chaining.
5289 * hnc_init():
5290 * allocate and initialize the cache. If reinit is set,
5291 * invalidate all cache entries.
5292 * hnc_look():
5293 * It hashes the ipaddress gets the index and walks thru the
5294 * single linked list. if cached entry was found, it will
5295 * put in the head of the list, and return.While going through
5296 * the entries, an entry which has already expired will be invalidated.
5297 * hnc_register():
5298 * Hashes the ipaddress finds the index and puts current entry to the list.
5299 * hnc_unreg():
5300 * invalidate the cachep.
5303 static void
5304 hnc_init(int reinit)
5306 struct hostname_cache **hpp;
5307 pthread_t mythreadno;
5308 int i;
5310 if (Debug) {
5311 mythreadno = pthread_self();
5314 if (reinit) {
5315 (void) pthread_mutex_lock(&hnc_mutex);
5317 for (i = 0; i < hnc_size; i++) {
5318 for (hpp = &hnc_cache[i]; *hpp != NULL; ) {
5319 hnc_unreg(hpp);
5323 (void) pthread_mutex_unlock(&hnc_mutex);
5324 DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n",
5325 mythreadno);
5326 } else {
5328 hnc_cache = calloc(hnc_size, sizeof (struct hostname_cache *));
5330 if (hnc_cache == NULL) {
5331 MALLOC_FAIL("hostname cache");
5332 logerror("hostname cache disabled");
5333 return;
5336 DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry"
5337 " ttl:%d\n", mythreadno, hnc_size, hnc_ttl);
5341 static host_list_t *
5342 hnc_lookup(struct netbuf *nbp, struct netconfig *ncp, int *hindex)
5344 struct hostname_cache **hpp, *hp;
5345 time_t now;
5346 pthread_t mythreadno;
5347 int index;
5349 if (Debug) {
5350 mythreadno = pthread_self();
5353 if (hnc_cache == NULL) {
5354 return (NULL);
5357 (void) pthread_mutex_lock(&hnc_mutex);
5358 now = time(0);
5360 *hindex = index = addr_hash(nbp);
5362 for (hpp = &hnc_cache[index]; (hp = *hpp) != NULL; ) {
5363 DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n",
5364 mythreadno, (void *)hp->h, (void *)hp,
5365 hp->h->hl_hosts[0]);
5367 if (hp->expire < now) {
5368 DPRINT2(9, "hnc_lookup(%u): purge %p\n",
5369 mythreadno, (void *)hp);
5370 hnc_unreg(hpp);
5371 continue;
5374 if (ncp == hp->ncp && same_addr(&hp->addr, nbp)) {
5376 * found!
5377 * Put the entry at the top.
5380 if (hp != hnc_cache[index]) {
5381 /* unlink from active list */
5382 *hpp = (*hpp)->next;
5383 /* push it onto the top */
5384 hp->next = hnc_cache[index];
5385 hnc_cache[index] = hp;
5388 (void) pthread_mutex_lock(&hp->h->hl_mutex);
5389 hp->h->hl_refcnt++;
5390 (void) pthread_mutex_unlock(&hp->h->hl_mutex);
5392 DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n",
5393 mythreadno, (void *)hp->h, (void *)hp,
5394 hp->h->hl_hosts[0]);
5396 (void) pthread_mutex_unlock(&hnc_mutex);
5397 return (hp->h);
5400 hpp = &hp->next;
5403 (void) pthread_mutex_unlock(&hnc_mutex);
5404 return (NULL);
5407 static void
5408 hnc_register(struct netbuf *nbp, struct netconfig *ncp,
5409 host_list_t *h, int hindex)
5411 struct hostname_cache **hpp, **tailp, *hp, *entry;
5412 void *addrbuf;
5413 time_t now;
5414 pthread_t mythreadno;
5415 int i;
5417 if (Debug) {
5418 mythreadno = pthread_self();
5421 if (hnc_cache == NULL) {
5422 return;
5425 if ((addrbuf = malloc(nbp->len)) == NULL) {
5426 MALLOC_FAIL("pushing hostname cache");
5427 return;
5430 if ((entry = malloc(sizeof (struct hostname_cache))) == NULL) {
5431 MALLOC_FAIL("pushing hostname entry");
5432 free(addrbuf);
5433 return;
5436 (void) pthread_mutex_lock(&hnc_mutex);
5438 i = 0;
5440 now = time(0);
5442 * first go through active list, and discard the
5443 * caches which has been invalid. Count number of
5444 * non-expired buckets.
5447 for (hpp = &hnc_cache[hindex]; (hp = *hpp) != NULL; ) {
5448 tailp = hpp;
5450 if (hp->expire < now) {
5451 DPRINT2(9, "hnc_register(%u): discard %p\n",
5452 mythreadno, (void *)hp);
5453 hnc_unreg(hpp);
5454 } else {
5455 i++;
5456 hpp = &hp->next;
5461 * If max limit of chained hash buckets has been used up
5462 * delete the least active element in the chain.
5464 if (i == MAX_BUCKETS) {
5465 hnc_unreg(tailp);
5468 (void) memcpy(addrbuf, nbp->buf, nbp->len);
5469 entry->addr.len = nbp->len;
5470 entry->addr.buf = addrbuf;
5471 entry->ncp = ncp;
5472 entry->h = h;
5473 entry->expire = time(NULL) + hnc_ttl;
5475 /* insert it at the top */
5476 entry->next = hnc_cache[hindex];
5477 hnc_cache[hindex] = entry;
5480 * As far as cache is valid, corresponding host_list must
5481 * also be valid. Increments the refcnt to avoid freeing
5482 * host_list.
5484 h->hl_refcnt++;
5485 DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n",
5486 mythreadno, (void *)entry->h, (void *)entry, entry->h->hl_hosts[0]);
5487 (void) pthread_mutex_unlock(&hnc_mutex);
5490 static void
5491 hnc_unreg(struct hostname_cache **hpp)
5493 struct hostname_cache *hp = *hpp;
5494 pthread_t mythreadno;
5496 if (Debug) {
5497 mythreadno = pthread_self();
5500 DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n",
5501 mythreadno, (void *)hp->h, (void *)hp, hp->h->hl_hosts[0]);
5502 free(hp->addr.buf);
5503 freehl(hp->h);
5505 /* unlink from active list */
5506 *hpp = (*hpp)->next;
5508 free(hp);
5512 * Once this is called, error messages through logerror() will go to
5513 * the console immediately. Also, messages are queued into the tmpq
5514 * to be able to later put them into inputq.
5516 static void
5517 disable_errorlog()
5519 (void) dataq_init(&tmpq);
5521 (void) pthread_mutex_lock(&logerror_lock);
5522 interrorlog = 0;
5523 (void) pthread_mutex_unlock(&logerror_lock);
5527 * Turn internal error messages to regular input stream.
5528 * All pending messages are pulled and pushed into the regular
5529 * input queue.
5531 static void
5532 enable_errorlog()
5534 log_message_t *mp;
5536 (void) pthread_mutex_lock(&logerror_lock);
5537 interrorlog = 1;
5538 (void) pthread_mutex_unlock(&logerror_lock);
5541 * push all the pending messages into inputq.
5543 while (dataq_dequeue(&tmpq, (void **)&mp, 1) == 0) {
5544 (void) dataq_enqueue(&inputq, mp);
5546 (void) dataq_destroy(&tmpq);
5550 * Generate a hash value of the given address and derive
5551 * an index into the hnc_cache hashtable.
5552 * The hashing method is similar to what Java does for strings.
5554 static int
5555 addr_hash(struct netbuf *nbp)
5557 char *uap;
5558 int i;
5559 unsigned long hcode = 0;
5561 uap = nbp->buf;
5563 if (uap == NULL) {
5564 return (0);
5568 * Compute a hashcode of the address string
5570 for (i = 0; i < nbp->len; i++)
5571 hcode = (31 * hcode) + uap[i];
5574 * Scramble the hashcode for better distribution
5576 hcode += ~(hcode << 9);
5577 hcode ^= (hcode >> 14);
5578 hcode += (hcode << 4);
5579 hcode ^= (hcode >> 10);
5581 return ((int)(hcode % hnc_size));