1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2013 Gary Mills
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /*
29 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
30 * All Rights Reserved
31 */
32
33 /*
34 * University Copyright- Copyright (c) 1982, 1986, 1988
35 * The Regents of the University of California
36 * All Rights Reserved
37 *
38 * University Acknowledgment- Portions of this document are derived from
39 * software developed by the University of California, Berkeley, and its
40 * contributors.
41 */
42
43 /*
44 * syslogd -- log system messages
45 *
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.
50 *
51 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
52 * cause it to reconfigure.
53 *
54 * Defined Constants:
55 *
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.
59 *
60 */
61
62 #include <unistd.h>
63 #include <note.h>
64 #include <errno.h>
65 #include <sys/types.h>
66 #include <stdio.h>
67 #include <stdio_ext.h>
68 #include <stdlib.h>
69 #include <ctype.h>
70 #include <signal.h>
71 #include <string.h>
72 #include <strings.h>
73 #include <libscf.h>
74 #include <netconfig.h>
75 #include <netdir.h>
76 #include <pwd.h>
77 #include <sys/socket.h>
78 #include <tiuser.h>
79 #include <utmpx.h>
80 #include <limits.h>
81 #include <pthread.h>
82 #include <fcntl.h>
83 #include <stropts.h>
84 #include <assert.h>
85 #include <sys/statvfs.h>
86
87 #include <sys/param.h>
88 #include <sys/sysmacros.h>
89 #include <sys/syslog.h>
90 #include <sys/strlog.h>
91 #include <sys/stat.h>
92 #include <sys/time.h>
93 #include <sys/utsname.h>
94 #include <sys/poll.h>
95 #include <sys/wait.h>
96 #include <sys/resource.h>
97 #include <sys/mman.h>
98 #include <sys/note.h>
99 #include <door.h>
100
101 #include <wchar.h>
102 #include <locale.h>
103 #include <stdarg.h>
104
105 #include "dataq.h"
106 #include "conf.h"
107 #include "syslogd.h"
108
109 #define DOORFILE "/var/run/syslog_door"
110 #define RELATIVE_DOORFILE "../var/run/syslog_door"
111 #define OLD_DOORFILE "/etc/.syslog_door"
112
113 #define PIDFILE "/var/run/syslog.pid"
114 #define RELATIVE_PIDFILE "../var/run/syslog.pid"
115 #define OLD_PIDFILE "/etc/syslog.pid"
116
117 static char *LogName = "/dev/log";
118 static char *ConfFile = "/etc/syslog.conf";
119 static char ctty[] = "/dev/console";
120 static char sysmsg[] = "/dev/sysmsg";
121 static int DoorFd = -1;
122 static int DoorCreated = 0;
123 static int PidfileCreated = 0;
124 static char *DoorFileName = DOORFILE;
125 static char *PidFileName = PIDFILE;
126
127 /*
128 * configuration file directives
129 */
130
131 static struct code PriNames[] = {
132 "panic", LOG_EMERG,
133 "emerg", LOG_EMERG,
134 "alert", LOG_ALERT,
135 "crit", LOG_CRIT,
136 "err", LOG_ERR,
137 "error", LOG_ERR,
138 "warn", LOG_WARNING,
139 "warning", LOG_WARNING,
140 "notice", LOG_NOTICE,
141 "info", LOG_INFO,
142 "debug", LOG_DEBUG,
143 "none", NOPRI,
144 NULL, -1
145 };
146
147 static struct code FacNames[] = {
148 "kern", LOG_KERN,
149 "user", LOG_USER,
150 "mail", LOG_MAIL,
151 "daemon", LOG_DAEMON,
152 "auth", LOG_AUTH,
153 "security", LOG_AUTH,
154 "mark", LOG_MARK,
155 "syslog", LOG_SYSLOG,
156 "lpr", LOG_LPR,
157 "news", LOG_NEWS,
158 "uucp", LOG_UUCP,
159 "bsdcron", LOG_BSDCRON,
160 "authpriv", LOG_AUTHPRIV,
161 "ftp", LOG_FTP,
162 "ntp", LOG_NTP,
163 "audit", LOG_AUDIT,
164 "console", LOG_CONSOLE,
165 "cron", LOG_CRON,
166 "local0", LOG_LOCAL0,
167 "local1", LOG_LOCAL1,
168 "local2", LOG_LOCAL2,
169 "local3", LOG_LOCAL3,
170 "local4", LOG_LOCAL4,
171 "local5", LOG_LOCAL5,
172 "local6", LOG_LOCAL6,
173 "local7", LOG_LOCAL7,
174 NULL, -1
175 };
176
177 static char *TypeNames[7] = {
178 "UNUSED", "FILE", "TTY", "CONSOLE",
179 "FORW", "USERS", "WALL"
180 };
181
182 /*
183 * we allocate our own thread stacks so we can create them
184 * without the MAP_NORESERVE option. We need to be sure
185 * we have stack space even if the machine runs out of swap
186 */
187
188 #define DEFAULT_STACKSIZE (100 * 1024) /* 100 k stack */
189 #define DEFAULT_REDZONESIZE (8 * 1024) /* 8k redzone */
190
191 static pthread_mutex_t wmp = PTHREAD_MUTEX_INITIALIZER; /* wallmsg lock */
192
193 static pthread_mutex_t cft = PTHREAD_MUTEX_INITIALIZER;
194 static int conf_threads = 0;
195
196 static pthread_mutex_t hup_lock = PTHREAD_MUTEX_INITIALIZER;
197 static pthread_cond_t hup_done = PTHREAD_COND_INITIALIZER;
198
199 static pthread_mutex_t logerror_lock = PTHREAD_MUTEX_INITIALIZER;
200
201 #define HUP_ACCEPTABLE 0x0000 /* can start SIGHUP process */
202 #define HUP_INPROGRESS 0x0001 /* SIGHUP process in progress */
203 #define HUP_COMPLETED 0x0002 /* SIGHUP process completed */
204 #define HUP_SUSP_LOGMSG_REQD 0x1000 /* request to suspend */
205 #define HUP_LOGMSG_SUSPENDED 0x2000 /* logmsg is suspended */
206 static int hup_state = HUP_ACCEPTABLE;
207
208 static size_t stacksize; /* thread stack size */
209 static size_t redzonesize; /* thread stack redzone size */
210 static char *stack_ptr; /* ptr to allocated stacks */
211 static char *cstack_ptr; /* ptr to conf_thr stacks */
212
213 static time_t start_time;
214
215 static pthread_t sys_thread; /* queues messages from us */
216 static pthread_t net_thread; /* queues messages from the net */
217 static pthread_t log_thread; /* message processing thread */
218 static pthread_t hnl_thread; /* hostname lookup thread */
219
220 static dataq_t inputq; /* the input queue */
221 static dataq_t tmpq; /* temporary queue for err msg */
222 static dataq_t hnlq; /* hostname lookup queue */
223
224 static struct filed fallback[2];
225 static struct filed *Files;
226 static int nlogs;
227 static int Debug; /* debug flag */
228 static host_list_t LocalHostName; /* our hostname */
229 static host_list_t NullHostName; /* in case of lookup failure */
230 static int debuglev = 1; /* debug print level */
231 static int interrorlog; /* internal error logging */
232
233 static int MarkInterval = 20; /* interval between marks (mins) */
234 static int Marking = 0; /* non-zero if marking some file */
235 static int Ninputs = 0; /* number of network inputs */
236 static int curalarm = 0; /* current timeout value (secs) */
237 static int sys_msg_count = 0; /* total msgs rcvd from local log */
238 static int sys_init_msg_count = 0; /* initially received */
239 static int net_msg_count = 0; /* total msgs rcvd from net */
240
241 static struct pollfd Pfd; /* Pollfd for local the log device */
242 static struct pollfd *Nfd; /* Array of pollfds for udp ports */
243 static struct netconfig *Ncf;
244 static struct netbuf **Myaddrs;
245 static struct t_unitdata **Udp;
246 static struct t_uderr **Errp;
247 static int turnoff = 0;
248 static int shutting_down;
249
250 /* for managing door server threads */
251 static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
252 static uint_t door_server_cnt = 0;
253 static pthread_attr_t door_thr_attr;
254
255 static struct hostname_cache **hnc_cache;
256 static pthread_mutex_t hnc_mutex = PTHREAD_MUTEX_INITIALIZER;
257 static size_t hnc_size = DEF_HNC_SIZE;
258 static unsigned int hnc_ttl = DEF_HNC_TTL;
259
260 #define DPRINT0(d, m) if ((Debug) && debuglev >= (d)) \
261 (void) fprintf(stderr, m)
262 #define DPRINT1(d, m, a) if ((Debug) && debuglev >= (d)) \
263 (void) fprintf(stderr, m, a)
264 #define DPRINT2(d, m, a, b) if ((Debug) && debuglev >= (d)) \
265 (void) fprintf(stderr, m, a, b)
266 #define DPRINT3(d, m, a, b, c) if ((Debug) && debuglev >= (d)) \
267 (void) fprintf(stderr, m, a, b, c)
268 #define DPRINT4(d, m, a, b, c, e) if ((Debug) && debuglev >= (d)) \
269 (void) fprintf(stderr, m, a, b, c, e)
270 #define MALLOC_FAIL(x) \
271 logerror("malloc failed: " x)
272 #define MALLOC_FAIL_EXIT \
273 logerror("malloc failed - fatal"); \
274 exit(1)
275
276
277 #define MAILCMD "mailx -s \"syslogd shut down\" root"
278
279 /*
280 * Number of seconds to wait before giving up on threads that won't
281 * shutdown: (that's right, 10 minutes!)
282 */
283 #define LOOP_MAX (10 * 60)
284
285 /*
286 * Interval(sec) to check the status of output queue while processing
287 * HUP signal.
288 */
289 #define LOOP_INTERVAL (15)
290
291 int
292 main(int argc, char **argv)
293 {
294 int i;
295 char *pstr;
296 int sig, fd;
297 int tflag = 0, Tflag = 0;
298 sigset_t sigs, allsigs;
299 struct rlimit rlim;
300 char *debugstr;
301 int mcount = 0;
302 struct sigaction act;
303 pthread_t mythreadno = 0;
304 char cbuf [30];
305 struct stat sb;
306
307 #ifdef DEBUG
308 #define DEBUGDIR "/var/tmp"
309 if (chdir(DEBUGDIR))
310 DPRINT2(1, "main(%u): Unable to cd to %s\n", mythreadno,
311 DEBUGDIR);
312 #endif /* DEBUG */
313
314 (void) setlocale(LC_ALL, "");
315
316 if ((debugstr = getenv("SYSLOGD_DEBUG")) != NULL)
317 if ((debuglev = atoi(debugstr)) == 0)
318 debuglev = 1;
319
320 #if ! defined(TEXT_DOMAIN) /* should be defined by cc -D */
321 #define TEXT_DOMAIN "SYS_TEST"
322 #endif
323 (void) textdomain(TEXT_DOMAIN);
324
325 (void) time(&start_time);
326
327 if (lstat("/var/run", &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
328 DoorFileName = OLD_DOORFILE;
329 PidFileName = OLD_PIDFILE;
330 }
331
332 properties();
333
334 while ((i = getopt(argc, argv, "df:p:m:tT")) != EOF) {
335 switch (i) {
336 case 'f': /* configuration file */
337 ConfFile = optarg;
338 break;
339
340 case 'd': /* debug */
341 Debug++;
342 break;
343
344 case 'p': /* path */
345 LogName = optarg;
346 break;
347
348 case 'm': /* mark interval */
349 for (pstr = optarg; *pstr; pstr++) {
350 if (! (isdigit(*pstr))) {
351 (void) fprintf(stderr,
352 "Illegal interval\n");
353 usage();
354 }
355 }
356 MarkInterval = atoi(optarg);
357 if (MarkInterval < 1 || MarkInterval > INT_MAX) {
358 (void) fprintf(stderr,
359 "Interval must be between 1 and %d\n",
360 INT_MAX);
361 usage();
362 }
363 break;
364 case 't': /* turn off remote reception */
365 tflag++;
366 turnoff++;
367 break;
368 case 'T': /* turn on remote reception */
369 Tflag++;
370 turnoff = 0;
371 break;
372 default:
373 usage();
374 }
375 }
376
377 if (optind < argc)
378 usage();
379
380 if (tflag && Tflag) {
381 (void) fprintf(stderr, "specify only one of -t and -T\n");
382 usage();
383 }
384
385 /*
386 * close all fd's except 0-2
387 */
388
389 closefrom(3);
390
391 if (!Debug) {
392 if (fork())
393 return (0);
394 (void) close(0);
395 (void) open("/", 0);
396 (void) dup2(0, 1);
397 (void) dup2(0, 2);
398 untty();
399 }
400
401 if (Debug) {
402 mythreadno = pthread_self();
403 }
404
405 /*
406 * DO NOT call logerror() until tmpq is initialized.
407 */
408 disable_errorlog();
409
410 /*
411 * ensure that file descriptor limit is "high enough"
412 */
413 (void) getrlimit(RLIMIT_NOFILE, &rlim);
414 if (rlim.rlim_cur < rlim.rlim_max)
415 rlim.rlim_cur = rlim.rlim_max;
416 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
417 logerror("Unable to increase file descriptor limit.");
418 (void) enable_extended_FILE_stdio(-1, -1);
419
420 /* block all signals from all threads initially */
421 (void) sigfillset(&allsigs);
422 (void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL);
423
424 DPRINT2(1, "main(%u): Started at time %s", mythreadno,
425 ctime_r(&start_time, cbuf));
426
427 init(); /* read configuration, start threads */
428
429 DPRINT1(1, "main(%u): off & running....\n", mythreadno);
430
431 /* now set up to catch signals we care about */
432
433 (void) sigemptyset(&sigs);
434 (void) sigaddset(&sigs, SIGHUP); /* reconfigure */
435 (void) sigaddset(&sigs, SIGALRM); /* mark & flush timer */
436 (void) sigaddset(&sigs, SIGTERM); /* exit */
437 (void) sigaddset(&sigs, SIGINT); /* exit if debugging */
438 (void) sigaddset(&sigs, SIGQUIT); /* exit if debugging */
439 (void) sigaddset(&sigs, SIGPIPE); /* catch & discard */
440 (void) sigaddset(&sigs, SIGUSR1); /* dump debug stats */
441
442 /*
443 * We must set up to catch these signals, even though sigwait
444 * will get them before the isr does. Setting SA_SIGINFO ensures
445 * that signals will be enqueued.
446 */
447
448 act.sa_flags = SA_SIGINFO;
449 act.sa_sigaction = signull;
450
451 (void) sigaction(SIGHUP, &act, NULL);
452 (void) sigaction(SIGALRM, &act, NULL);
453 (void) sigaction(SIGTERM, &act, NULL);
454 (void) sigaction(SIGINT, &act, NULL);
455 (void) sigaction(SIGQUIT, &act, NULL);
456 (void) sigaction(SIGPIPE, &act, NULL);
457 (void) sigaction(SIGUSR1, &act, NULL);
458
459 /* we now turn into the signal handling thread */
460
461 DPRINT1(2, "main(%u): now handling signals\n", mythreadno);
462 for (;;) {
463 (void) sigwait(&sigs, &sig);
464 DPRINT2(2, "main(%u): received signal %d\n", mythreadno, sig);
465 switch (sig) {
466 case SIGALRM:
467 DPRINT1(1, "main(%u): Got SIGALRM\n",
468 mythreadno);
469 flushmsg(NOCOPY);
470 if (Marking && (++mcount % MARKCOUNT == 0)) {
471 if (logmymsg(LOG_INFO, "-- MARK --",
472 ADDDATE|MARK|NOCOPY, 0) == -1) {
473 MALLOC_FAIL(
474 "dropping MARK message");
475 }
476
477 mcount = 0;
478 }
479 curalarm = MarkInterval * 60 / MARKCOUNT;
480 (void) alarm((unsigned)curalarm);
481 DPRINT2(2, "main(%u): Next alarm in %d "
482 "seconds\n", mythreadno, curalarm);
483 break;
484 case SIGHUP:
485 DPRINT1(1, "main(%u): got SIGHUP - "
486 "reconfiguring\n", mythreadno);
487
488 reconfigure();
489
490 DPRINT1(1, "main(%u): done processing SIGHUP\n",
491 mythreadno);
492 break;
493 case SIGQUIT:
494 case SIGINT:
495 if (!Debug) {
496 /* allow these signals if debugging */
497 break;
498 }
499 /* FALLTHROUGH */
500 case SIGTERM:
501 DPRINT2(1, "main(%u): going down on signal %d\n",
502 mythreadno, sig);
503 (void) alarm(0);
504 flushmsg(0);
505 errno = 0;
506 t_errno = 0;
507 logerror("going down on signal %d", sig);
508 disable_errorlog(); /* force msg to console */
509 (void) shutdown_msg(); /* stop threads */
510 shutdown_input();
511 close_door();
512 delete_doorfiles();
513 return (0);
514 case SIGUSR1: /* secret debug dump mode */
515 /* if in debug mode, use stdout */
516
517 if (Debug) {
518 dumpstats(STDOUT_FILENO);
519 break;
520 }
521 /* otherwise dump to a debug file */
522 if ((fd = open(DEBUGFILE,
523 (O_WRONLY|O_CREAT|O_TRUNC|O_EXCL),
524 0644)) < 0)
525 break;
526 dumpstats(fd);
527 (void) close(fd);
528 break;
529 default:
530 DPRINT2(2, "main(%u): unexpected signal %d\n",
531 mythreadno, sig);
532 break;
533 }
534 }
535 }
536
537 /*
538 * Attempts to open the local log device
539 * and return a file descriptor.
540 */
541 static int
542 openklog(char *name, int mode)
543 {
544 int fd;
545 struct strioctl str;
546 pthread_t mythreadno;
547
548 if (Debug) {
549 mythreadno = pthread_self();
550 }
551
552 if ((fd = open(name, mode)) < 0) {
553 logerror("cannot open %s", name);
554 DPRINT3(1, "openklog(%u): cannot create %s (%d)\n",
555 mythreadno, name, errno);
556 return (-1);
557 }
558 str.ic_cmd = I_CONSLOG;
559 str.ic_timout = 0;
560 str.ic_len = 0;
561 str.ic_dp = NULL;
562 if (ioctl(fd, I_STR, &str) < 0) {
563 logerror("cannot register to log console messages");
564 DPRINT2(1, "openklog(%u): cannot register to log "
565 "console messages (%d)\n", mythreadno, errno);
566 return (-1);
567 }
568 return (fd);
569 }
570
571
572 /*
573 * Open the log device, and pull up all pending messages.
574 */
575 static void
576 prepare_sys_poll()
577 {
578 int nfds, funix;
579
580 if ((funix = openklog(LogName, O_RDONLY)) < 0) {
581 logerror("can't open kernel log device - fatal");
582 exit(1);
583 }
584
585 Pfd.fd = funix;
586 Pfd.events = POLLIN;
587
588 for (;;) {
589 nfds = poll(&Pfd, 1, 0);
590 if (nfds <= 0) {
591 if (sys_init_msg_count > 0)
592 flushmsg(SYNC_FILE);
593 break;
594 }
595
596 if (Pfd.revents & POLLIN) {
597 getkmsg(0);
598 } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
599 logerror("kernel log driver poll error");
600 break;
601 }
602 }
603
604 }
605
606 /*
607 * this thread listens to the local stream log driver for log messages
608 * generated by this host, formats them, and queues them to the logger
609 * thread.
610 */
611 /*ARGSUSED*/
612 static void *
613 sys_poll(void *ap)
614 {
615 int nfds;
616 int timeout;
617 static int klogerrs = 0;
618 pthread_t mythreadno;
619
620 if (Debug) {
621 mythreadno = pthread_self();
622 }
623
624 DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno);
625
626 /*
627 * Try to process as many messages as we can without blocking on poll.
628 * We identify such messages with timeout == 0 and
629 * enqueue them without the SYNC_FILE flag. When no more data is
630 * waiting on the local log device, we set timeout to INFTIM,
631 * and generate a flush message to sync
632 * the previously identified messages out to disk.
633 */
634
635 timeout = INFTIM;
636
637 for (;;) {
638 errno = 0;
639 t_errno = 0;
640
641 nfds = poll(&Pfd, 1, timeout);
642
643 if (nfds <= 0) {
644 if (nfds < 0 && errno != EINTR)
645 logerror("poll");
646 if (timeout == 0)
647 flushmsg(SYNC_FILE);
648 timeout = INFTIM;
649 continue;
650 }
651
652 if (Pfd.revents & POLLIN) {
653 timeout = 0;
654 getkmsg(timeout);
655 continue;
656 }
657
658 if (shutting_down) {
659 pthread_exit(0);
660 }
661
662 if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
663 logerror("kernel log driver poll error");
664 (void) close(Pfd.fd);
665 Pfd.fd = -1;
666 }
667
668 while (Pfd.fd == -1 && klogerrs++ < 10) {
669 Pfd.fd = openklog(LogName, O_RDONLY);
670 }
671 if (klogerrs >= 10) {
672 logerror("can't reopen kernel log device - fatal");
673 exit(1);
674 }
675 if (timeout == 0)
676 flushmsg(SYNC_FILE);
677 timeout = INFTIM;
678 }
679 /*NOTREACHED*/
680 return (NULL);
681 }
682
683 /*
684 * Pull up one message from log driver.
685 */
686 static void
687 getkmsg(int timeout)
688 {
689 int flags = 0, i;
690 char *lastline;
691 struct strbuf ctl, dat;
692 struct log_ctl hdr;
693 char buf[MAXLINE+1];
694 size_t buflen;
695 size_t len;
696 char tmpbuf[MAXLINE+1];
697 pthread_t mythreadno;
698
699 if (Debug) {
700 mythreadno = pthread_self();
701 }
702
703 dat.maxlen = MAXLINE;
704 dat.buf = buf;
705 ctl.maxlen = sizeof (struct log_ctl);
706 ctl.buf = (caddr_t)&hdr;
707
708 while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
709 lastline = &dat.buf[dat.len];
710 *lastline = '\0';
711
712 DPRINT2(5, "getkmsg:(%u): getmsg: dat.len = %d\n",
713 mythreadno, dat.len);
714 buflen = strlen(buf);
715 len = findnl_bkwd(buf, buflen);
716
717 (void) memcpy(tmpbuf, buf, len);
718 tmpbuf[len] = '\0';
719
720 /*
721 * Format sys will enqueue the log message.
722 * Set the sync flag if timeout != 0, which
723 * means that we're done handling all the
724 * initial messages ready during startup.
725 */
726 if (timeout == 0) {
727 formatsys(&hdr, tmpbuf, 0);
728 sys_init_msg_count++;
729 } else {
730 formatsys(&hdr, tmpbuf, 1);
731 }
732 sys_msg_count++;
733
734 if (len != buflen) {
735 /* If anything remains in buf */
736 size_t remlen;
737
738 if (buf[len] == '\n') {
739 /* skip newline */
740 len++;
741 }
742
743 /*
744 * Move the remaining bytes to
745 * the beginnning of buf.
746 */
747
748 remlen = buflen - len;
749 (void) memcpy(buf, &buf[len], remlen);
750 dat.maxlen = MAXLINE - remlen;
751 dat.buf = &buf[remlen];
752 } else {
753 dat.maxlen = MAXLINE;
754 dat.buf = buf;
755 }
756 }
757
758 if (i == 0 && dat.len > 0) {
759 dat.buf[dat.len] = '\0';
760 /*
761 * Format sys will enqueue the log message.
762 * Set the sync flag if timeout != 0, which
763 * means that we're done handling all the
764 * initial messages ready during startup.
765 */
766 DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n",
767 mythreadno, dat.maxlen);
768 DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n",
769 mythreadno, dat.len);
770 DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n",
771 mythreadno, strlen(dat.buf));
772 DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n",
773 mythreadno, dat.buf);
774 DPRINT2(5, "getkmsg(%u): buf len = %d\n",
775 mythreadno, strlen(buf));
776 if (timeout == 0) {
777 formatsys(&hdr, buf, 0);
778 sys_init_msg_count++;
779 } else {
780 formatsys(&hdr, buf, 1);
781 }
782 sys_msg_count++;
783 } else if (i < 0 && errno != EINTR) {
784 if (!shutting_down) {
785 logerror("kernel log driver read error");
786 }
787 (void) close(Pfd.fd);
788 Pfd.fd = -1;
789 }
790 }
791
792 /*
793 * this thread polls all the network interfaces for syslog messages
794 * forwarded to us, tags them with the hostname they are received
795 * from, and queues them to the logger thread.
796 */
797 /*ARGSUSED*/
798 static void *
799 net_poll(void *ap)
800 {
801 int nfds, i;
802 int flags = 0;
803 struct t_unitdata *udp;
804 struct t_uderr *errp;
805 char buf[MAXLINE+1];
806 char *uap;
807 log_message_t *mp;
808 host_info_t *hinfo;
809 pthread_t mythreadno;
810
811 if (Debug) {
812 mythreadno = pthread_self();
813 }
814
815 DPRINT1(1, "net_poll(%u): net_thread started\n", mythreadno);
816
817 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
818
819 for (;;) {
820 errno = 0;
821 t_errno = 0;
822 nfds = poll(Nfd, Ninputs, -1);
823 if (nfds == 0)
824 continue;
825
826 if (nfds < 0) {
827 if (errno != EINTR)
828 logerror("poll");
829 continue;
830 }
831 for (i = 0; nfds > 0 && i < Ninputs; i++) {
832 if ((Nfd[i].revents & POLLIN) == 0) {
833 if (shutting_down) {
834 pthread_exit(0);
835 }
836 if (Nfd[i].revents &
837 (POLLNVAL|POLLHUP|POLLERR)) {
838 logerror("POLLNVAL|POLLHUP|POLLERR");
839 (void) t_close(Nfd[i].fd);
840 Nfd[i].fd = -1;
841 nfds--;
842 }
843 continue;
844 }
845
846 udp = Udp[i];
847 udp->udata.buf = buf;
848 udp->udata.maxlen = MAXLINE;
849 udp->udata.len = 0;
850 flags = 0;
851 if (t_rcvudata(Nfd[i].fd, udp, &flags) < 0) {
852 errp = Errp[i];
853 if (t_errno == TLOOK) {
854 if (t_rcvuderr(Nfd[i].fd, errp) < 0) {
855 if (!shutting_down) {
856 logerror("t_rcvuderr");
857 }
858 (void) t_close(Nfd[i].fd);
859 Nfd[i].fd = -1;
860 }
861 } else {
862 if (!shutting_down) {
863 logerror("t_rcvudata");
864 }
865 (void) t_close(Nfd[i].fd);
866 Nfd[i].fd = -1;
867 }
868 nfds--;
869 if (shutting_down) {
870 pthread_exit(0);
871 }
872 continue;
873 }
874 nfds--;
875
876 if (udp->udata.len == 0) {
877 if (Debug) {
878 uap = NULL;
879 if (udp->addr.len > 0) {
880 uap = taddr2uaddr(&Ncf[i],
881 &udp->addr);
882 }
883 DPRINT2(1, "net_poll(%u):"
884 " received empty packet"
885 " from %s\n", mythreadno,
886 uap ? uap : "<unknown>");
887 if (uap)
888 free(uap);
889 }
890 continue; /* No data */
891 }
892 if (udp->addr.len == 0) {
893 /*
894 * The previous message was larger than
895 * MAXLINE, and T_MORE should have been set.
896 * Further data needs to be discarded as
897 * we've already received MAXLINE.
898 */
899 DPRINT1(1, "net_poll(%u): discarding packet "
900 "exceeds max line size\n", mythreadno);
901 continue;
902 }
903
904 net_msg_count++;
905
906 if ((mp = new_msg()) == NULL) {
907 MALLOC_FAIL("dropping message from "
908 "remote");
909 continue;
910 }
911
912 buf[udp->udata.len] = '\0';
913 formatnet(&udp->udata, mp);
914
915 if (Debug) {
916 uap = taddr2uaddr(&Ncf[i], &udp->addr);
917 DPRINT2(1, "net_poll(%u): received message"
918 " from %s\n", mythreadno,
919 uap ? uap : "<unknown>");
920 free(uap);
921 }
922 if ((hinfo = malloc(sizeof (*hinfo))) == NULL ||
923 (hinfo->addr.buf =
924 malloc(udp->addr.len)) == NULL) {
925 MALLOC_FAIL("dropping message from "
926 "remote");
927 if (hinfo) {
928 free(hinfo);
929 }
930 free_msg(mp);
931 continue;
932 }
933
934 hinfo->ncp = &Ncf[i];
935 hinfo->addr.len = udp->addr.len;
936 (void) memcpy(hinfo->addr.buf, udp->addr.buf,
937 udp->addr.len);
938 mp->ptr = hinfo;
939 if (dataq_enqueue(&hnlq, (void *)mp) == -1) {
940 MALLOC_FAIL("dropping message from "
941 "remote");
942 free_msg(mp);
943 free(hinfo->addr.buf);
944 free(hinfo);
945 continue;
946 }
947 DPRINT3(5, "net_poll(%u): enqueued msg %p "
948 "on queue %p\n", mythreadno, (void *)mp,
949 (void *)&hnlq);
950 }
951 }
952 /*NOTREACHED*/
953 return (NULL);
954 }
955
956 static void
957 usage(void)
958 {
959 (void) fprintf(stderr,
960 "usage: syslogd [-d] [-t|-T] [-mmarkinterval] [-ppath]"
961 " [-fconffile]\n");
962 exit(1);
963 }
964
965 static void
966 untty(void)
967 {
968 if (!Debug)
969 (void) setsid();
970 }
971
972 /*
973 * generate a log message internally. The original version of syslogd
974 * simply called logmsg directly, but because everything is now based
975 * on message passing, we need an internal way to generate and queue
976 * log messages from within syslogd itself.
977 */
978 static int
979 logmymsg(int pri, char *msg, int flags, int pending)
980 {
981 log_message_t *mp;
982 pthread_t mythreadno;
983 dataq_t *qptr;
984
985 if (Debug) {
986 mythreadno = pthread_self();
987 }
988
989 if ((mp = new_msg()) == NULL) {
990 return (-1);
991 }
992
993 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
994 mp->pri = pri;
995 mp->hlp = &LocalHostName;
996 (void) strlcpy(mp->msg, msg, MAXLINE+1);
997 mp->flags = flags;
998 (void) time(&mp->ts);
999
1000 qptr = pending ? &tmpq : &inputq;
1001 if (dataq_enqueue(qptr, (void *)mp) == -1) {
1002 free_msg(mp);
1003 return (-1);
1004 }
1005
1006 DPRINT3(5, "logmymsg(%u): enqueued msg %p on queue %p\n",
1007 mythreadno, (void *)mp, (void *)qptr);
1008 DPRINT2(5, "logmymsg(%u): Message content: %s\n", mythreadno, msg);
1009 return (0);
1010 }
1011
1012 /*
1013 * Generate an internal shutdown message
1014 */
1015 static int
1016 shutdown_msg(void)
1017 {
1018 pthread_t mythreadno;
1019 log_message_t *mp;
1020
1021 if (Debug) {
1022 mythreadno = pthread_self();
1023 }
1024
1025 if ((mp = new_msg()) == NULL) {
1026 return (-1);
1027 }
1028
1029 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
1030 mp->flags = SHUTDOWN;
1031 mp->hlp = &LocalHostName;
1032
1033 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1034 free_msg(mp);
1035 return (-1);
1036 }
1037
1038 DPRINT3(5, "shutdown_msg(%u): enqueued msg %p on queue %p\n",
1039 mythreadno, (void *)mp, (void *)&inputq);
1040 return (0);
1041 }
1042
1043 /*
1044 * Generate an internal flush message
1045 */
1046 static void
1047 flushmsg(int flags)
1048 {
1049 log_message_t *mp;
1050 pthread_t mythreadno;
1051
1052 if (Debug) {
1053 mythreadno = pthread_self();
1054 }
1055
1056 if ((mp = new_msg()) == NULL) {
1057 MALLOC_FAIL("dropping flush msg");
1058 return;
1059 }
1060
1061 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
1062 mp->flags = FLUSHMSG | flags;
1063 mp->hlp = &LocalHostName;
1064
1065 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1066 free_msg(mp);
1067 MALLOC_FAIL("dropping flush msg");
1068 return;
1069 }
1070
1071 DPRINT4(5, "flush_msg(%u): enqueued msg %p on queue %p, flags "
1072 "0x%x\n", mythreadno, (void *)mp, (void *)&inputq, flags);
1073 }
1074
1075 /*
1076 * Do some processing on messages received from the net
1077 */
1078 static void
1079 formatnet(struct netbuf *nbp, log_message_t *mp)
1080 {
1081 char *p;
1082 int pri;
1083 pthread_t mythreadno;
1084
1085 if (Debug) {
1086 mythreadno = pthread_self();
1087 }
1088
1089 DPRINT2(5, "formatnet(%u): called for msg %p\n", mythreadno,
1090 (void *)mp);
1091
1092 mp->flags = NETWORK;
1093 (void) time(&mp->ts);
1094
1095 /* test for special codes */
1096 pri = DEFUPRI;
1097 p = nbp->buf;
1098 DPRINT2(9, "formatnet(%u): Message content:\n>%s<\n", mythreadno,
1099 p);
1100 if (*p == '<' && isdigit(*(p+1))) {
1101 pri = 0;
1102 while (isdigit(*++p))
1103 pri = 10 * pri + (*p - '0');
1104 if (*p == '>')
1105 ++p;
1106 if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
1107 pri = DEFUPRI;
1108 }
1109
1110 mp->pri = pri;
1111 (void) strlcpy(mp->msg, p, MAXLINE+1);
1112 }
1113
1114 /*
1115 * Do some processing on messages generated by this host
1116 * and then enqueue the log message.
1117 */
1118 static void
1119 formatsys(struct log_ctl *lp, char *msg, int sync)
1120 {
1121 char *p, *q;
1122 char line[MAXLINE + 1];
1123 size_t msglen;
1124 log_message_t *mp;
1125 char cbuf[30];
1126 pthread_t mythreadno;
1127
1128 if (Debug) {
1129 mythreadno = pthread_self();
1130 }
1131
1132 DPRINT3(3, "formatsys(%u): log_ctl.mid = %d, log_ctl.sid = %d\n",
1133 mythreadno, lp->mid, lp->sid);
1134 DPRINT2(9, "formatsys(%u): Message Content:\n>%s<\n", mythreadno,
1135 msg);
1136
1137 /* msglen includes the null termination */
1138 msglen = strlen(msg) + 1;
1139
1140 for (p = msg; *p != '\0'; ) {
1141 size_t linelen;
1142 size_t len;
1143
1144 /*
1145 * Allocate a log_message_t structure.
1146 * We should do it here since a single message (msg)
1147 * could be composed of many lines.
1148 */
1149 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
1150
1151 if ((mp = new_msg()) == NULL) {
1152 MALLOC_FAIL("dropping message");
1153 /*
1154 * Should bail out from the loop.
1155 */
1156 break;
1157 }
1158
1159 mp->flags &= ~NETWORK;
1160 mp->hlp = &LocalHostName;
1161 mp->ts = lp->ttime;
1162 if (lp->flags & SL_LOGONLY)
1163 mp->flags |= IGN_CONS;
1164 if (lp->flags & SL_CONSONLY)
1165 mp->flags |= IGN_FILE;
1166
1167 /* extract facility */
1168 if ((lp->pri & LOG_FACMASK) == LOG_KERN) {
1169 (void) sprintf(line, "%.15s ",
1170 ctime_r(&mp->ts, cbuf) + 4);
1171 } else {
1172 (void) sprintf(line, "");
1173 }
1174
1175 linelen = strlen(line);
1176 q = line + linelen;
1177
1178 DPRINT2(5, "formatsys(%u): msglen = %d\n", mythreadno, msglen);
1179 len = copynl_frwd(q, MAXLINE + 1 - linelen, p, msglen);
1180 DPRINT2(5, "formatsys(%u): len (copynl_frwd) = %d\n",
1181 mythreadno, len);
1182
1183 p += len;
1184 msglen -= len;
1185
1186 if (*p == '\n') {
1187 /* skip newline */
1188 p++;
1189 }
1190
1191 if (sync && ((lp->pri & LOG_FACMASK) == LOG_KERN))
1192 mp->flags |= SYNC_FILE; /* fsync file after write */
1193
1194 if (len != 0) {
1195 (void) strlcpy(mp->msg, line, MAXLINE+1);
1196 mp->pri = lp->pri;
1197
1198 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
1199 free_msg(mp);
1200 MALLOC_FAIL("dropping message");
1201 break;
1202 }
1203
1204 DPRINT3(5, "formatsys(%u): sys_thread enqueued msg "
1205 "%p on queue %p\n", mythreadno, (void *)mp,
1206 (void *)&inputq);
1207 } else
1208 free_msg(mp);
1209 }
1210 }
1211
1212 /*
1213 * Log a message to the appropriate log files, users, etc. based on
1214 * the priority.
1215 */
1216 /*ARGSUSED*/
1217 static void *
1218 logmsg(void *ap)
1219 {
1220 struct filed *f;
1221 int fac, prilev, flags, refcnt;
1222 int fake_shutdown, skip_shutdown;
1223 log_message_t *mp, *save_mp;
1224 pthread_t mythreadno;
1225
1226 if (Debug) {
1227 mythreadno = pthread_self();
1228 }
1229
1230 DPRINT1(1, "logmsg(%u): msg dispatcher started\n", mythreadno);
1231
1232 fake_shutdown = skip_shutdown = 0;
1233 save_mp = NULL;
1234 for (;;) {
1235 if (save_mp) {
1236 /*
1237 * If we have set aside a message in order to fake a
1238 * SHUTDOWN, use that message before picking from the
1239 * queue again.
1240 */
1241 mp = save_mp;
1242 save_mp = NULL;
1243 } else {
1244 (void) dataq_dequeue(&inputq, (void **)&mp, 0);
1245 }
1246 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
1247 DPRINT3(5, "logmsg(%u): msg dispatcher dequeued %p from "
1248 "queue %p\n", mythreadno, (void *)mp,
1249 (void *)&inputq);
1250
1251 /*
1252 * In most cases, if the message traffic is low, logmsg() wakes
1253 * up when it receives the SHUTDOWN msg, and will sleep until
1254 * HUP process is complete. However, if the inputq is too
1255 * long, logmsg() may not receive SHUTDOWN before reconfigure()
1256 * releases the logger fds, filed and logit threads. That, in
1257 * turn, will cause logmsg to refer to invalid fileds.
1258 *
1259 * logmsg() needs to respond to the SHUTDOWN message within
1260 * LOOP_INTERVAL seconds when reconfigure() enqueues it. It
1261 * does so in most cases. When it does not respond in time,
1262 * logmsg() needs to be in suspended state immediately, since
1263 * filed may have been invalidated. reconfigure() will set the
1264 * HUP_SUSP_LOGMSG_REQD bit in hup_state and wait another
1265 * LOOP_INTERVAL seconds before proceeding.
1266 *
1267 * When HUP_SUSP_LOGMSG_REQD is set, we will create a fake
1268 * SHUTDOWN message, and dispatch it to the various logit
1269 * threads, and logmsg() itself will suspend. In order to
1270 * ignore the real SHUTDOWN which will arrive later, we keep a
1271 * counter (skip_shutdown) and decrement it when the SHUTDOWN
1272 * message arrives.
1273 */
1274 if ((hup_state & HUP_SUSP_LOGMSG_REQD) &&
1275 (mp->flags & SHUTDOWN) == 0) {
1276 DPRINT1(3, "logmsg(%u): suspend request\n",
1277 mythreadno);
1278
1279 save_mp = mp;
1280
1281 /* create a fake SHUTDOWN msg */
1282 if ((mp = new_msg()) == NULL) {
1283 MALLOC_FAIL("dropping message");
1284 if (mp->flags & SHUTDOWN) {
1285 (void) logerror_to_console(1,
1286 "unable to shutdown "
1287 "logger thread");
1288 }
1289 continue;
1290 }
1291 mp->flags = SHUTDOWN;
1292 mp->hlp = &LocalHostName;
1293 fake_shutdown = 1;
1294 skip_shutdown++;
1295 DPRINT2(3, "logmsg(%u): pending SHUTDOWN %d\n",
1296 mythreadno, skip_shutdown);
1297 }
1298
1299 /*
1300 * is it a shutdown or flush message ?
1301 */
1302 if ((mp->flags & SHUTDOWN) || (mp->flags & FLUSHMSG)) {
1303 (void) pthread_mutex_lock(&mp->msg_mutex);
1304
1305 if ((mp->flags & SHUTDOWN) &&
1306 !fake_shutdown && skip_shutdown > 0) {
1307 skip_shutdown--;
1308 (void) pthread_mutex_unlock(&mp->msg_mutex);
1309 free_msg(mp);
1310 DPRINT2(3, "logmsg(%u): released late "
1311 "arrived SHUTDOWN. pending %d\n",
1312 mythreadno, skip_shutdown);
1313 continue;
1314 }
1315
1316 for (f = Files; f < &Files[nlogs]; f++) {
1317 (void) pthread_mutex_lock(&f->filed_mutex);
1318
1319 if (f->f_type == F_UNUSED) {
1320 (void) pthread_mutex_unlock(
1321 &f->filed_mutex);
1322 continue;
1323 }
1324
1325 f->f_queue_count++;
1326 mp->refcnt++;
1327
1328 if (dataq_enqueue(&f->f_queue,
1329 (void *)mp) == -1) {
1330 f->f_queue_count--;
1331 mp->refcnt--;
1332 (void) pthread_mutex_unlock(
1333 &f->filed_mutex);
1334 MALLOC_FAIL("dropping message");
1335
1336 if (mp->flags & SHUTDOWN) {
1337 (void) logerror_to_console(1,
1338 "unable to shutdown "
1339 "logger thread");
1340 }
1341
1342 continue;
1343 }
1344 DPRINT3(5, "logmsg(%u): enqueued msg %p "
1345 "on queue %p\n", mythreadno,
1346 (void *)mp, (void *)&f->f_queue);
1347 (void) pthread_mutex_unlock(&f->filed_mutex);
1348 }
1349
1350 /*
1351 * flags value needs to be saved because mp may
1352 * have been freed before SHUTDOWN test below.
1353 */
1354 flags = mp->flags;
1355 refcnt = mp->refcnt;
1356
1357 (void) pthread_mutex_unlock(&mp->msg_mutex);
1358 if (refcnt == 0)
1359 free_msg(mp);
1360
1361 if (flags & SHUTDOWN) {
1362 (void) pthread_mutex_lock(&hup_lock);
1363 while (hup_state != HUP_COMPLETED) {
1364 hup_state |= HUP_LOGMSG_SUSPENDED;
1365 (void) pthread_cond_wait(&hup_done,
1366 &hup_lock);
1367 hup_state &= ~HUP_LOGMSG_SUSPENDED;
1368 }
1369 hup_state = HUP_ACCEPTABLE;
1370 (void) pthread_mutex_unlock(&hup_lock);
1371 fake_shutdown = 0;
1372 }
1373 continue;
1374 }
1375
1376 /*
1377 * Check to see if msg looks non-standard.
1378 */
1379 if ((int)strlen(mp->msg) < 16 || mp->msg[3] != ' ' ||
1380 mp->msg[6] != ' ' || mp->msg[9] != ':' ||
1381 mp->msg[12] != ':' || mp->msg[15] != ' ')
1382 mp->flags |= ADDDATE;
1383
1384 /* extract facility and priority level */
1385 fac = (mp->pri & LOG_FACMASK) >> 3;
1386 if (mp->flags & MARK)
1387 fac = LOG_NFACILITIES;
1388 prilev = mp->pri & LOG_PRIMASK;
1389
1390 DPRINT3(3, "logmsg(%u): fac = %d, pri = %d\n",
1391 mythreadno, fac, prilev);
1392
1393 /*
1394 * Because different devices log at different speeds,
1395 * it's important to hold the mutex for the current
1396 * message until it's been enqueued to all log files,
1397 * so the reference count is accurate before any
1398 * of the log threads can decrement it.
1399 */
1400 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mp))
1401 _NOTE(COMPETING_THREADS_NOW)
1402 (void) pthread_mutex_lock(&mp->msg_mutex);
1403
1404 for (f = Files; f < &Files[nlogs]; f++) {
1405 /* skip messages that are incorrect priority */
1406 if (f->f_pmask[fac] < (unsigned)prilev ||
1407 f->f_pmask[fac] == NOPRI)
1408 continue;
1409 if (f->f_queue_count > Q_HIGHWATER_MARK) {
1410 DPRINT4(5, "logmsg(%u): Dropping message "
1411 "%p on file %p, count = %d\n",
1412 mythreadno, (void *)mp, (void *)f,
1413 f->f_queue_count);
1414 continue;
1415 }
1416
1417 /*
1418 * Need to grab filed_mutex before testing the f_type.
1419 * Otherwise logit() may set F_UNUSED after the test
1420 * below, and start pulling out the pending messages.
1421 */
1422
1423 (void) pthread_mutex_lock(&f->filed_mutex);
1424
1425 if (f->f_type == F_UNUSED ||
1426 (f->f_type == F_FILE && (mp->flags & IGN_FILE)) ||
1427 (f->f_type == F_CONSOLE &&
1428 (mp->flags & IGN_CONS))) {
1429 (void) pthread_mutex_unlock(&f->filed_mutex);
1430 continue;
1431 }
1432
1433 f->f_queue_count++;
1434 mp->refcnt++;
1435
1436 if (dataq_enqueue(&f->f_queue, (void *)mp) == -1) {
1437 f->f_queue_count--;
1438 mp->refcnt--;
1439 (void) pthread_mutex_unlock(&f->filed_mutex);
1440 MALLOC_FAIL("dropping message");
1441 continue;
1442 }
1443
1444 DPRINT3(5, "logmsg(%u): enqueued msg %p on queue "
1445 "%p\n", mythreadno, (void *)mp,
1446 (void *)&f->f_queue);
1447 (void) pthread_mutex_unlock(&f->filed_mutex);
1448 }
1449 refcnt = mp->refcnt;
1450 (void) pthread_mutex_unlock(&mp->msg_mutex);
1451 if (refcnt == 0)
1452 free_msg(mp);
1453 }
1454 /*NOTREACHED*/
1455 return (NULL);
1456 }
1457
1458 /*
1459 * function to actually write the log message to the selected file.
1460 * each file has a logger thread that runs this routine. The function
1461 * is called with a pointer to its file structure.
1462 */
1463 static void *
1464 logit(void *ap)
1465 {
1466 struct filed *f = ap;
1467 log_message_t *mp;
1468 int forwardingloop = 0;
1469 const char *errmsg = "logit(%u): %s to %s forwarding loop detected\n";
1470 int i, currofst, prevofst, refcnt;
1471 host_list_t *hlp;
1472
1473 assert(f != NULL);
1474
1475 DPRINT4(5, "logit(%u): logger started for \"%s\" (queue %p, filed "
1476 "%p)\n", f->f_thread, f->f_un.f_fname, (void *)&f->f_queue,
1477 (void *)f);
1478 _NOTE(COMPETING_THREADS_NOW);
1479
1480 while (f->f_type != F_UNUSED) {
1481 (void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
1482 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1483 "%p\n", f->f_thread, (void *)mp, (void *)&f->f_queue);
1484 (void) pthread_mutex_lock(&f->filed_mutex);
1485 assert(f->f_queue_count > 0);
1486 f->f_queue_count--;
1487 (void) pthread_mutex_unlock(&f->filed_mutex);
1488 assert(mp->refcnt > 0);
1489
1490 /*
1491 * is it a shutdown message ?
1492 */
1493 if (mp->flags & SHUTDOWN) {
1494 (void) pthread_mutex_lock(&mp->msg_mutex);
1495 refcnt = --mp->refcnt;
1496 (void) pthread_mutex_unlock(&mp->msg_mutex);
1497 if (refcnt == 0)
1498 free_msg(mp);
1499 break;
1500 }
1501
1502 /*
1503 * Is it a logsync message?
1504 */
1505 if ((mp->flags & (FLUSHMSG | LOGSYNC)) ==
1506 (FLUSHMSG | LOGSYNC)) {
1507 if (f->f_type != F_FILE)
1508 goto out; /* nothing to do */
1509 (void) close(f->f_file);
1510 f->f_file = open64(f->f_un.f_fname,
1511 O_WRONLY|O_APPEND|O_NOCTTY);
1512 if (f->f_file < 0) {
1513 f->f_type = F_UNUSED;
1514 logerror(f->f_un.f_fname);
1515 f->f_stat.errs++;
1516 }
1517 goto out;
1518 }
1519
1520 /*
1521 * If the message flags include both flush and sync,
1522 * then just sync the file out to disk if appropriate.
1523 */
1524 if ((mp->flags & (FLUSHMSG | SYNC_FILE)) ==
1525 (FLUSHMSG | SYNC_FILE)) {
1526 if (f->f_type == F_FILE) {
1527 DPRINT2(5, "logit(%u): got FLUSH|SYNC "
1528 "for filed %p\n", f->f_thread,
1529 (void *)f);
1530 (void) fsync(f->f_file);
1531 }
1532 goto out;
1533 }
1534
1535 /*
1536 * Otherwise if it's a standard flush message, write
1537 * out any saved messages to the file.
1538 */
1539 if ((mp->flags & FLUSHMSG) && (f->f_prevcount > 0)) {
1540 set_flush_msg(f);
1541 writemsg(SAVED, f);
1542 goto out;
1543 }
1544
1545 (void) strlcpy(f->f_current.msg, mp->msg, MAXLINE+1);
1546 (void) strlcpy(f->f_current.host, mp->hlp->hl_hosts[0],
1547 SYS_NMLN);
1548 f->f_current.pri = mp->pri;
1549 f->f_current.flags = mp->flags;
1550 f->f_current.time = mp->ts;
1551 f->f_msgflag &= ~CURRENT_VALID;
1552 hlp = mp->hlp;
1553
1554 prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
1555 currofst = (f->f_current.flags & ADDDATE) ? 0 : 16;
1556
1557 if (f->f_type == F_FORW) {
1558 /*
1559 * Should not forward MARK messages, as they are
1560 * not defined outside of the current system.
1561 */
1562
1563 if (mp->flags & MARK) {
1564 DPRINT1(1, "logit(%u): cannot forward "
1565 "Mark\n", f->f_thread);
1566 goto out;
1567 }
1568
1569 /*
1570 * can not forward message if we do
1571 * not have a host to forward to
1572 */
1573 if (hlp == (host_list_t *)NULL)
1574 goto out;
1575 /*
1576 * a forwarding loop is created on machines
1577 * with multiple interfaces because the
1578 * network address of the sender is different
1579 * to the receiver even though it is the
1580 * same machine. Instead, if the
1581 * hostname the source and target are
1582 * the same the message if thrown away
1583 */
1584 forwardingloop = 0;
1585 for (i = 0; i < hlp->hl_cnt; i++) {
1586 if (strcmp(hlp->hl_hosts[i],
1587 f->f_un.f_forw.f_hname) == 0) {
1588 DPRINT3(1, errmsg, f->f_thread,
1589 f->f_un.f_forw.f_hname,
1590 hlp->hl_hosts[i]);
1591 forwardingloop = 1;
1592 break;
1593 }
1594 }
1595
1596 if (forwardingloop == 1) {
1597 f->f_stat.cantfwd++;
1598 goto out;
1599 }
1600 }
1601
1602 f->f_msgflag |= CURRENT_VALID;
1603
1604 /* check for dup message */
1605 if (f->f_type != F_FORW &&
1606 (f->f_msgflag & OLD_VALID) &&
1607 prevofst == currofst &&
1608 (strcmp(f->f_prevmsg.msg + prevofst,
1609 f->f_current.msg + currofst) == 0) &&
1610 (strcmp(f->f_prevmsg.host,
1611 f->f_current.host) == 0)) {
1612 /* a dup */
1613 DPRINT2(2, "logit(%u): msg is dup - %p\n",
1614 f->f_thread, (void *)mp);
1615 if (currofst == 16) {
1616 (void) strncpy(f->f_prevmsg.msg,
1617 f->f_current.msg, 15); /* update time */
1618 }
1619 f->f_prevcount++;
1620 f->f_stat.dups++;
1621 f->f_stat.total++;
1622 f->f_msgflag &= ~CURRENT_VALID;
1623 } else {
1624 /* new: mark or prior dups exist */
1625 if (f->f_current.flags & MARK || f->f_prevcount > 0) {
1626 if (f->f_prevcount > 0 && f->f_type != F_FORW) {
1627 set_flush_msg(f);
1628 if (f->f_msgflag & OLD_VALID) {
1629 writemsg(SAVED, f);
1630 }
1631 }
1632 if (f->f_msgflag & CURRENT_VALID)
1633 writemsg(CURRENT, f);
1634 if (!(mp->flags & NOCOPY))
1635 copy_msg(f);
1636 if (f->f_current.flags & MARK) {
1637 DPRINT2(2, "logit(%u): msg is "
1638 "mark - %p)\n", f->f_thread,
1639 (void *)mp);
1640 f->f_msgflag &= ~OLD_VALID;
1641 } else {
1642 DPRINT2(2, "logit(%u): saving "
1643 "message - %p\n", f->f_thread,
1644 (void *)mp);
1645 }
1646 f->f_stat.total++;
1647 } else { /* new message */
1648 DPRINT2(2, "logit(%u): msg is new "
1649 "- %p\n", f->f_thread, (void *)mp);
1650 writemsg(CURRENT, f);
1651 if (!(mp->flags & NOCOPY))
1652 copy_msg(f);
1653 f->f_stat.total++;
1654 }
1655 }
1656 /*
1657 * if message refcnt goes to zero after we decrement
1658 * it here, we are the last consumer of the message,
1659 * and we should free it. We need to hold the lock
1660 * between decrementing the count and checking for
1661 * zero so another thread doesn't beat us to it.
1662 */
1663 out:
1664 (void) pthread_mutex_lock(&mp->msg_mutex);
1665 refcnt = --mp->refcnt;
1666 (void) pthread_mutex_unlock(&mp->msg_mutex);
1667 if (refcnt == 0)
1668 free_msg(mp);
1669 }
1670 /* register our exit */
1671
1672 /*
1673 * Pull out all pending messages, if they exist.
1674 */
1675
1676 (void) pthread_mutex_lock(&f->filed_mutex);
1677
1678 while (f->f_queue_count > 0) {
1679 (void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
1680 DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
1681 "%p\n",
1682 f->f_thread, (void *)mp, (void *)&f->f_queue);
1683 (void) pthread_mutex_lock(&mp->msg_mutex);
1684 refcnt = --mp->refcnt;
1685 (void) pthread_mutex_unlock(&mp->msg_mutex);
1686 if (refcnt == 0)
1687 free_msg(mp);
1688 f->f_queue_count--;
1689 }
1690
1691 (void) pthread_mutex_unlock(&f->filed_mutex);
1692
1693 if (f->f_type != F_USERS && f->f_type != F_WALL &&
1694 f->f_type != F_UNUSED) {
1695 if (f->f_type == F_FORW)
1696 (void) t_close(f->f_file);
1697 else
1698 (void) close(f->f_file);
1699 }
1700
1701 /*
1702 * Since f_type may have been changed before this point, we need
1703 * to test orig_type.
1704 */
1705 if (f->f_orig_type == F_FORW) {
1706 free(f->f_un.f_forw.f_addr.buf);
1707 }
1708
1709 f->f_type = F_UNUSED;
1710 (void) pthread_mutex_lock(&cft);
1711 --conf_threads;
1712 (void) pthread_mutex_unlock(&cft);
1713 DPRINT1(5, "logit(%u): logging thread exited\n", f->f_thread);
1714 return (NULL);
1715 }
1716
1717 /*
1718 * change the previous message to a flush message, stating how
1719 * many repeats occurred since the last flush
1720 */
1721 static void
1722 set_flush_msg(struct filed *f)
1723 {
1724 char tbuf[10];
1725 int prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
1726
1727 if (f->f_prevcount == 1)
1728 (void) strncpy(tbuf, "time", sizeof (tbuf));
1729 else
1730 (void) strncpy(tbuf, "times", sizeof (tbuf));
1731
1732 (void) snprintf(f->f_prevmsg.msg+prevofst,
1733 sizeof (f->f_prevmsg.msg) - prevofst,
1734 "last message repeated %d %s", f->f_prevcount, tbuf);
1735 f->f_prevcount = 0;
1736 f->f_msgflag |= OLD_VALID;
1737 }
1738
1739
1740 /*
1741 * the actual writing of the message is broken into a separate function
1742 * because each file has a current and saved message associated with
1743 * it (for duplicate message detection). It is necessary to be able
1744 * to write either the saved message or the current message.
1745 */
1746 static void
1747 writemsg(int selection, struct filed *f)
1748 {
1749 char *cp, *p;
1750 int pri;
1751 int flags;
1752 int l;
1753 time_t ts;
1754 struct t_unitdata ud;
1755 char *eomp, *eomp2, *from, *text, *msg;
1756 char line[MAXLINE*2];
1757 char head[MAXLINE+1];
1758 char tmpbuf[MAXLINE+1];
1759 char cbuf[30];
1760 char *filtered;
1761 char *msgid_start, *msgid_end;
1762 pthread_t mythreadno;
1763 size_t hlen, filter_len;
1764
1765 if (Debug) {
1766 mythreadno = pthread_self();
1767 }
1768
1769 switch (selection) {
1770 default:
1771 case CURRENT: /* print current message */
1772 msg = f->f_current.msg;
1773 from = f->f_current.host;
1774 pri = f->f_current.pri;
1775 flags = f->f_current.flags;
1776 ts = f->f_current.time;
1777 f->f_msgflag &= ~CURRENT_VALID;
1778 break;
1779 case SAVED: /* print saved message */
1780 msg = f->f_prevmsg.msg;
1781 from = f->f_prevmsg.host;
1782 pri = f->f_prevmsg.pri;
1783 flags = f->f_prevmsg.flags;
1784 ts = f->f_prevmsg.time;
1785 f->f_msgflag &= ~OLD_VALID;
1786 break;
1787 }
1788
1789 if (msg[0] == '\0')
1790 return;
1791
1792 cp = line;
1793
1794 if (flags & ADDDATE)
1795 (void) strncpy(cp, ctime_r(&ts, cbuf) + 4, 15);
1796 else
1797 (void) strncpy(cp, msg, 15);
1798
1799 line[15] = '\0';
1800 (void) strcat(cp, " ");
1801 (void) strcat(cp, from);
1802 (void) strcat(cp, " ");
1803 text = cp + strlen(cp);
1804
1805 if (flags & ADDDATE)
1806 (void) strcat(cp, msg);
1807 else
1808 (void) strcat(cp, msg+16);
1809 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
1810
1811 errno = 0;
1812 t_errno = 0;
1813 switch (f->f_type) {
1814 case F_UNUSED:
1815 DPRINT1(1, "writemsg(%u): UNUSED\n", mythreadno);
1816 break;
1817 case F_FORW:
1818 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1819 mythreadno, msg, TypeNames[f->f_type],
1820 f->f_un.f_forw.f_hname);
1821
1822 hlen = snprintf(head, sizeof (head),
1823 "<%d>%.15s ", pri, cp);
1824
1825 DPRINT2(5, "writemsg(%u): head = \"%s\"\n", mythreadno, head);
1826 DPRINT2(5, "writemsg(%u): hlen = %d\n", mythreadno, hlen);
1827
1828 l = strlen(text);
1829 p = text;
1830
1831 DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
1832 DPRINT2(5, "writemsg(%u): strlen(text) = %d\n", mythreadno, l);
1833
1834 (void) strncpy(tmpbuf, head, hlen);
1835
1836 while (l > 0) {
1837 size_t len;
1838
1839 len = copy_frwd(tmpbuf + hlen, sizeof (tmpbuf) - hlen,
1840 p, l);
1841
1842 DPRINT2(5, "writemsg(%u): tmpbuf = \"%s\"\n",
1843 mythreadno, tmpbuf);
1844 DPRINT2(5, "writemsg(%u): len = %d\n", mythreadno,
1845 len);
1846 DPRINT2(5, "writemsg(%u): strlen(tmpbuf) = %d\n",
1847 mythreadno, strlen(tmpbuf));
1848
1849 ud.opt.buf = NULL;
1850 ud.opt.len = 0;
1851 ud.udata.buf = tmpbuf;
1852 ud.udata.len = len + hlen;
1853 ud.addr.maxlen = f->f_un.f_forw.f_addr.maxlen;
1854 ud.addr.buf = f->f_un.f_forw.f_addr.buf;
1855 ud.addr.len = f->f_un.f_forw.f_addr.len;
1856 if (t_sndudata(f->f_file, &ud) < 0) {
1857 if ((hup_state & HUP_INPROGRESS) &&
1858 f->f_type == F_UNUSED) {
1859 break;
1860 }
1861 (void) t_close(f->f_file);
1862 f->f_type = F_UNUSED;
1863 logerror("t_sndudata");
1864
1865 /*
1866 * Since it has already failed, it's not worth
1867 * continuing output from the middle of
1868 * message string.
1869 */
1870 break;
1871 }
1872 p += len;
1873 l -= len;
1874 }
1875 break;
1876 case F_CONSOLE:
1877 case F_TTY:
1878 case F_FILE:
1879 case F_USERS:
1880 case F_WALL:
1881 DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
1882 mythreadno, msg, TypeNames[f->f_type],
1883 ((f->f_type == F_USERS) || (f->f_type == F_WALL)) ?
1884 "" : f->f_un.f_fname);
1885 /*
1886 * filter the string in preparation for writing it
1887 * save the original for possible forwarding.
1888 * In case every byte in cp is a control character,
1889 * allocates large enough buffer for filtered.
1890 */
1891
1892 filter_len = strlen(cp) * 4 + 1;
1893 filtered = (char *)malloc(filter_len);
1894 if (!filtered) {
1895 MALLOC_FAIL("dropping message");
1896 /* seems we can just return */
1897 return;
1898 }
1899 DPRINT3(5, "writemsg(%u): "
1900 "filtered allocated (%p: %d bytes)\n",
1901 mythreadno, (void *)filtered, filter_len);
1902 /* -3 : we may add "\r\n" to ecomp(filtered) later */
1903 filter_string(cp, filtered, filter_len - 3);
1904
1905 DPRINT2(5, "writemsg(%u): strlen(filtered) = %d\n",
1906 mythreadno, strlen(filtered));
1907 /*
1908 * If we're writing to the console, strip out the message ID
1909 * to reduce visual clutter.
1910 */
1911 if ((msgid_start = strstr(filtered, "[ID ")) != NULL &&
1912 (msgid_end = strstr(msgid_start, "] ")) != NULL &&
1913 f->f_type == F_CONSOLE)
1914 (void) strcpy(msgid_start, msgid_end + 2);
1915
1916 eomp = filtered + strlen(filtered);
1917
1918 if ((f->f_type == F_USERS) || (f->f_type == F_WALL)) {
1919 /* CSTYLED */
1920 (void) strcat(eomp, "\r\n"); /*lint !e669*/
1921 /*
1922 * Since wallmsg messes with utmpx we need
1923 * to guarantee single threadedness...
1924 */
1925 (void) pthread_mutex_lock(&wmp);
1926 wallmsg(f, from, filtered);
1927 (void) pthread_mutex_unlock(&wmp);
1928
1929 /*
1930 * The contents of filtered have been copied
1931 * out to the struct walldev. We should free it here.
1932 */
1933
1934 free(filtered);
1935
1936 /* exiting the switch */
1937 break;
1938 } else if (f->f_type != F_FILE) {
1939 /* CSTYLED */
1940 (void) strncpy(eomp, "\r\n", 3); /*lint !e669*/
1941 } else {
1942 if ((eomp2 = strchr(filtered, '\r')) != NULL) {
1943 (void) strncpy(eomp2, "\n", 2);
1944 } else {
1945 /* CSTYLED */
1946 (void) strncpy(eomp, "\n", 2); /*lint !e669*/
1947 }
1948 }
1949 if (write(f->f_file, filtered, strlen(filtered)) < 0) {
1950 int e = errno;
1951
1952 if ((hup_state & HUP_INPROGRESS) &&
1953 f->f_type == F_UNUSED) {
1954 free(filtered);
1955 break;
1956 }
1957 (void) close(f->f_file);
1958 /*
1959 * Check for EBADF on TTY's due
1960 * to vhangup() XXX
1961 */
1962 if (e == EBADF && f->f_type != F_FILE) {
1963 f->f_file = open(f->f_un.f_fname,
1964 O_WRONLY|O_APPEND|O_NOCTTY);
1965 if (f->f_file < 0) {
1966 f->f_type = F_UNUSED;
1967 logerror(f->f_un.f_fname);
1968 f->f_stat.errs++;
1969 }
1970 untty();
1971 } else {
1972 f->f_type = F_UNUSED;
1973 f->f_stat.errs++;
1974 errno = e;
1975 logerror(f->f_un.f_fname);
1976 }
1977 } else if (flags & SYNC_FILE)
1978 if (((pri & LOG_FACMASK) >> 3) == LOG_KERN)
1979 (void) fsync(f->f_file);
1980
1981 DPRINT2(5, "writemsg(%u): freeing filtered (%p)\n",
1982 mythreadno, (void *)filtered);
1983
1984 free(filtered);
1985 break;
1986 }
1987 }
1988
1989 /*
1990 * WALLMSG -- Write a message to the world at large
1991 *
1992 * Write the specified message to either the entire
1993 * world, or a list of approved users.
1994 */
1995 static void
1996 wallmsg(struct filed *f, char *from, char *msg)
1997 {
1998 int i;
1999 size_t len, clen;
2000 char *buf = NULL;
2001 struct utmpx *utxp;
2002 time_t now;
2003 char line[512], dev[100];
2004 char cp[MAXLINE+1];
2005 struct stat statbuf;
2006 walldev_t *w;
2007 char cbuf[30];
2008 pthread_t mythreadno;
2009
2010 if (Debug) {
2011 mythreadno = pthread_self();
2012 }
2013
2014 if (access(UTMPX_FILE, R_OK) != 0 || stat(UTMPX_FILE, &statbuf) != 0) {
2015 logerror(UTMPX_FILE);
2016 return;
2017 } else if (statbuf.st_uid != 0 || (statbuf.st_mode & 07777) != 0644) {
2018 (void) snprintf(line, sizeof (line), "%s %s", UTMPX_FILE,
2019 "not owned by root or not mode 644.\n"
2020 "This file must be owned by root "
2021 "and not writable by\n"
2022 "anyone other than root. This alert is being "
2023 "dropped because of\n"
2024 "this problem.");
2025 logerror(line);
2026 return;
2027 }
2028
2029 if (f->f_type == F_WALL) {
2030 (void) time(&now);
2031 len = snprintf(line, sizeof (line),
2032 "\r\n\7Message from syslogd@%s "
2033 "at %.24s ...\r\n", from, ctime_r(&now, cbuf));
2034 len += strlen(msg + 16);
2035 buf = (char *)malloc(len + 1);
2036 if (!buf) {
2037 MALLOC_FAIL("dropping message");
2038 return;
2039 }
2040 DPRINT3(5, "wallmsg(%u): buf allocated (%p: %d bytes)\n",
2041 mythreadno, (void *)buf, len + 1);
2042 (void) strcpy(buf, line);
2043 (void) strcat(buf, msg + 16);
2044 clen = copy_frwd(cp, sizeof (cp), buf, len);
2045 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2046 mythreadno, clen);
2047 DPRINT2(5, "wallmsg(%u): freeing buf (%p)\n",
2048 mythreadno, (void *)buf);
2049 free(buf);
2050 } else {
2051 clen = copy_frwd(cp, sizeof (cp), msg, strlen(msg));
2052 DPRINT2(5, "wallmsg(%u): clen = %d\n",
2053 mythreadno, clen);
2054 }
2055 /* scan the user login file */
2056 setutxent();
2057 while ((utxp = getutxent()) != NULL) {
2058 /* is this slot used? */
2059 if (utxp->ut_name[0] == '\0' ||
2060 utxp->ut_line[0] == '\0' ||
2061 utxp->ut_type != USER_PROCESS)
2062 continue;
2063 /* should we send the message to this user? */
2064 if (f->f_type == F_USERS) {
2065 for (i = 0; i < MAXUNAMES; i++) {
2066 if (!f->f_un.f_uname[i][0]) {
2067 i = MAXUNAMES;
2068 break;
2069 }
2070 if (strncmp(f->f_un.f_uname[i],
2071 utxp->ut_name, UNAMESZ) == 0)
2072 break;
2073 }
2074 if (i >= MAXUNAMES)
2075 continue;
2076 }
2077
2078 /* compute the device name */
2079 if (utxp->ut_line[0] == '/') {
2080 (void) strncpy(dev, utxp->ut_line, UDEVSZ);
2081 } else {
2082 (void) strcpy(dev, "/dev/");
2083 (void) strncat(dev, utxp->ut_line, UDEVSZ);
2084 }
2085 DPRINT2(1, "wallmsg(%u): write to '%s'\n", mythreadno,
2086 dev);
2087
2088 if ((w = malloc(sizeof (walldev_t))) != NULL) {
2089 int rc;
2090 (void) pthread_attr_init(&w->thread_attr);
2091 (void) pthread_attr_setdetachstate(&w->thread_attr,
2092 PTHREAD_CREATE_DETACHED);
2093 (void) strncpy(w->dev, dev, PATH_MAX);
2094 (void) strncpy(w->msg, cp, MAXLINE+1);
2095 (void) strncpy(w->ut_name, utxp->ut_name,
2096 sizeof (w->ut_name));
2097
2098 if ((rc = pthread_create(&w->thread, &w->thread_attr,
2099 writetodev, (void *) w)) != 0) {
2100 DPRINT2(5, "wallmsg(%u): wallmsg thread "
2101 "create failed rc = %d\n",
2102 mythreadno, rc);
2103 free(w);
2104 break;
2105 }
2106 } else {
2107 MALLOC_FAIL("dropping message to user");
2108 }
2109 }
2110 /* close the user login file */
2111 endutxent();
2112 }
2113
2114 /*
2115 * Each time we need to write to a tty device (a potentially expensive
2116 * or long-running operation) this routine gets called as a new
2117 * detached, unbound thread. This allows writes to many devices
2118 * to proceed nearly in parallel, without having to resort to
2119 * asynchronous I/O or forking.
2120 */
2121 static void *
2122 writetodev(void *ap)
2123 {
2124 walldev_t *w = ap;
2125 int ttyf;
2126 int len;
2127 struct stat statb;
2128 struct passwd pw, *pwp;
2129 char pwbuf[MAXLINE];
2130 pthread_t mythreadno;
2131
2132 if (Debug) {
2133 mythreadno = pthread_self();
2134 }
2135
2136 DPRINT1(1, "writetodev(%u): Device writer thread started\n",
2137 mythreadno);
2138
2139 len = strlen(w->msg);
2140
2141 ttyf = open(w->dev, O_WRONLY|O_NOCTTY|O_NDELAY);
2142 if (ttyf >= 0) {
2143 if (fstat(ttyf, &statb) != 0) {
2144 DPRINT2(1, "writetodev(%u): Can't stat '%s'\n",
2145 mythreadno, w->dev);
2146 errno = 0;
2147 logerror("Can't stat '%s'", w->dev);
2148 } else if (!(statb.st_mode & S_IWRITE)) {
2149 DPRINT2(1, "writetodev(%u): Can't write to "
2150 "'%s'\n", mythreadno, w->dev);
2151 } else if (!isatty(ttyf)) {
2152 DPRINT2(1, "writetodev(%u): '%s' not a tty\n",
2153 mythreadno, w->dev);
2154 /*
2155 * We might hit dtremote here. Don't generate
2156 * error message.
2157 */
2158 } else if (getpwuid_r(statb.st_uid, &pw, pwbuf,
2159 sizeof (pwbuf), &pwp) != 0) {
2160 DPRINT2(1, "writetodev(%u): Can't determine owner "
2161 "of '%s'\n", mythreadno, w->dev);
2162 errno = 0;
2163 logerror("Can't determine owner of '%s'", w->dev);
2164 } else if (strncmp(pw.pw_name, w->ut_name, UNAMESZ) != 0) {
2165 DPRINT2(1, "writetodev(%u): Bad terminal owner '%s'"
2166 "\n", mythreadno, w->dev);
2167 errno = 0;
2168 logerror("%s %s owns '%s' %s %.*s",
2169 "Bad terminal owner;", pw.pw_name, w->dev,
2170 "but utmpx says", UNAMESZ, w->ut_name);
2171 } else if (write(ttyf, w->msg, len) != len) {
2172 DPRINT2(1, "writetodev(%u): Write failed to "
2173 "'%s'\n", mythreadno, w->dev);
2174 errno = 0;
2175 logerror("Write failed to '%s'", w->dev);
2176 }
2177
2178 DPRINT2(1, "writetodev(%u): write to '%s' succeeded\n",
2179 mythreadno, w->dev);
2180
2181 (void) close(ttyf);
2182 } else {
2183 DPRINT2(1, "writetodev(%u): Can't open '%s'\n",
2184 mythreadno, w->dev);
2185 }
2186
2187 (void) pthread_attr_destroy(&w->thread_attr);
2188 free(w);
2189
2190 DPRINT1(1, "writetodev(%u): Device writer thread exiting\n",
2191 mythreadno);
2192
2193 pthread_exit(0);
2194 return (NULL);
2195 /*NOTREACHED*/
2196 }
2197
2198 /*
2199 * Return a printable representation of a host address. If unable to
2200 * look up hostname, format the numeric address for display instead.
2201 *
2202 * First calls hnc_lookup to see if there is valid cache entry for
2203 * given network address. If it failed, cvthname looks up hostname,
2204 * and push the results into the hostname cache.
2205 */
2206 static host_list_t *
2207 cvthname(struct netbuf *nbp, struct netconfig *ncp, char *failsafe_addr)
2208 {
2209 int i;
2210 host_list_t *h;
2211 struct nd_hostservlist *hsp;
2212 struct nd_hostserv *hspp;
2213 pthread_t mythreadno;
2214 int hindex;
2215 char *uap;
2216
2217 if (Debug) {
2218 mythreadno = pthread_self();
2219 }
2220
2221 if (Debug)
2222 uap = taddr2uaddr(ncp, nbp);
2223
2224 DPRINT2(2, "cvthname(%u): looking up hostname for %s\n",
2225 mythreadno, uap ? uap : "<unknown>");
2226
2227 if ((h = hnc_lookup(nbp, ncp, &hindex)) != NULL) {
2228 DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n",
2229 mythreadno, (void *)h, uap ? uap : "<unknown>",
2230 h->hl_hosts[0]);
2231 return (h);
2232 }
2233 DPRINT2(2, "cvthname(%u): No cache found for %s\n",
2234 mythreadno, uap ? uap : "<unknown>");
2235
2236 if (Debug)
2237 free(uap);
2238
2239 if (ncp->nc_semantics != NC_TPI_CLTS) {
2240 return (NULL);
2241 }
2242
2243 /* memory allocation failure here is fatal */
2244 if ((h = malloc(sizeof (host_list_t))) == NULL) {
2245 MALLOC_FAIL("host name conversion");
2246 return (NULL);
2247 }
2248
2249 if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) {
2250 if (hsp->h_cnt <= 0) {
2251 out: netdir_free((void *)hsp, ND_HOSTSERVLIST);
2252 free(h);
2253 return (NULL);
2254 }
2255
2256 hspp = hsp->h_hostservs;
2257 h->hl_cnt = hsp->h_cnt;
2258 h->hl_hosts = (char **)malloc(sizeof (char *) * (h->hl_cnt));
2259 if (h->hl_hosts == NULL) {
2260 MALLOC_FAIL("host name conversion");
2261 goto out;
2262 }
2263
2264 DPRINT2(2, "cvthname(%u): Found %d hostnames\n",
2265 mythreadno, h->hl_cnt);
2266 for (i = 0; i < h->hl_cnt; i++) {
2267 h->hl_hosts[i] = (char *)
2268 malloc(sizeof (char) * (strlen(hspp->h_host) + 1));
2269 if (h->hl_hosts[i] == NULL) {
2270 int j;
2271 for (j = 0; j < i; j++) {
2272 free(h->hl_hosts[j]);
2273 }
2274 free(h->hl_hosts);
2275 MALLOC_FAIL("host name conversion");
2276 goto out;
2277 }
2278 (void) strcpy(h->hl_hosts[i], hspp->h_host);
2279 hspp++;
2280 }
2281 netdir_free((void *)hsp, ND_HOSTSERVLIST);
2282 } else { /* unknown address */
2283 h->hl_cnt = 1;
2284 h->hl_hosts = (char **)malloc(sizeof (char *));
2285 if (h->hl_hosts == NULL) {
2286 free(h);
2287 MALLOC_FAIL("host name conversion");
2288 return (NULL);
2289 }
2290 h->hl_hosts[0] = (char *)malloc(strlen(failsafe_addr) + 3);
2291 if (h->hl_hosts[0] == NULL) {
2292 free(h->hl_hosts);
2293 free(h);
2294 MALLOC_FAIL("host name conversion");
2295 return (NULL);
2296 }
2297 /*LINTED*/
2298 (void) sprintf(h->hl_hosts[0], "[%s]", failsafe_addr);
2299 DPRINT2(1, "cvthname(%u): Hostname lookup failed "
2300 "- using address %s instead\n",
2301 mythreadno, h->hl_hosts[0]);
2302 }
2303
2304 h->hl_refcnt = 1;
2305 if (pthread_mutex_init(&h->hl_mutex, NULL) != 0) {
2306 logerror("pthread_mutex_init failed");
2307 /* This host_list won't be shared by the cache. */
2308 return (h);
2309 }
2310 hnc_register(nbp, ncp, h, hindex);
2311 DPRINT3(2, "cvthname(%u): returning %p for %s\n",
2312 mythreadno, (void *)h, h->hl_hosts[0]);
2313 return (h);
2314 }
2315
2316 /*
2317 * Print syslogd errors some place. Need to be careful here, because
2318 * this routine is called at times when we're not initialized and
2319 * ready to log messages...in this case, fall back to using the console.
2320 */
2321 void
2322 logerror(const char *type, ...)
2323 {
2324 char buf[MAXLINE+1];
2325 pthread_t mythreadno;
2326 int flag;
2327 va_list ap;
2328
2329 if (Debug) {
2330 mythreadno = pthread_self();
2331 }
2332
2333 va_start(ap, type);
2334 logerror_format(type, buf, ap);
2335 va_end(ap);
2336 DPRINT2(1, "logerror(%u): %s\n", mythreadno, buf);
2337
2338 (void) pthread_mutex_lock(&logerror_lock);
2339 if (!interrorlog) {
2340 flag = 0;
2341 if (logerror_to_console(1, buf) == 0) {
2342 /* has written to the console */
2343 flag = IGN_CONS;
2344 }
2345 (void) logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE|flag, 1);
2346 } else {
2347 if (logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE, 0) == -1) {
2348 (void) logerror_to_console(1, buf);
2349 }
2350 }
2351 (void) pthread_mutex_unlock(&logerror_lock);
2352
2353 errno = 0;
2354 t_errno = 0;
2355 }
2356
2357 static void
2358 logerror_format(const char *type, char *buf, va_list ap)
2359 {
2360 char tmpbuf[MAXLINE + 1];
2361 pthread_t mythreadno;
2362
2363 if (Debug) {
2364 mythreadno = pthread_self();
2365 }
2366
2367 (void) vsnprintf(tmpbuf, MAXLINE, type, ap);
2368
2369 if (t_errno == 0 || t_errno == TSYSERR) {
2370 char *errstr;
2371
2372 if (errno == 0) {
2373 (void) snprintf(buf, MAXLINE, "syslogd: %.*s",
2374 MAXLINE, tmpbuf);
2375 } else if ((errstr = strerror(errno)) == (char *)NULL) {
2376 (void) snprintf(buf, MAXLINE, "syslogd: %s: error"
2377 " %d", tmpbuf, errno);
2378 } else {
2379 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
2380 tmpbuf, errstr);
2381 }
2382 } else {
2383 if (t_errno > t_nerr) {
2384 (void) snprintf(buf, MAXLINE, "syslogd: %s:"
2385 " t_error %d", tmpbuf, t_errno);
2386 } else {
2387 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
2388 tmpbuf, t_errlist[t_errno]);
2389 }
2390 }
2391
2392 DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno, buf);
2393 }
2394
2395 static int
2396 logerror_to_console(int nonblock, const char *buf)
2397 {
2398 int cfd, modes;
2399 pthread_t mythreadno;
2400 int ret = 0, len;
2401 char tmpbuf[MAXLINE + 1];
2402
2403 if (Debug) {
2404 mythreadno = pthread_self();
2405 }
2406
2407 DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno, buf);
2408
2409 /*
2410 * must use open here instead of fopen, because
2411 * we need the O_NOCTTY behavior - otherwise we
2412 * could hang the console at boot time
2413 */
2414
2415 modes = (nonblock) ?
2416 O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK :
2417 O_WRONLY|O_APPEND|O_NOCTTY;
2418
2419 if (((cfd = open(sysmsg, modes)) >= 0) ||
2420 ((cfd = open(ctty, modes)) >= 0)) {
2421 (void) snprintf(tmpbuf, MAXLINE, "%s\n", buf);
2422 len = strlen(tmpbuf);
2423 if (write(cfd, tmpbuf, len) != len) {
2424 ret = 1;
2425 }
2426 (void) close(cfd);
2427 } else {
2428 ret = 1;
2429
2430 /* punt */
2431 DPRINT1(1, "logerror_console(%u): can't open console\n",
2432 mythreadno);
2433 }
2434 return (ret);
2435 }
2436
2437 /*
2438 * copy current message to saved message in filed structure.
2439 */
2440 static void
2441 copy_msg(struct filed *f)
2442 {
2443 (void) strlcpy(f->f_prevmsg.msg, f->f_current.msg, MAXLINE+1);
2444 (void) strlcpy(f->f_prevmsg.host, f->f_current.host, SYS_NMLN);
2445 f->f_prevmsg.pri = f->f_current.pri;
2446 f->f_prevmsg.flags = f->f_current.flags;
2447 f->f_prevmsg.time = f->f_current.time;
2448 f->f_msgflag |= OLD_VALID;
2449 }
2450
2451
2452 /*
2453 * function to free a host_list_t struct that was allocated
2454 * out of cvthname(). There is a special case where we don't
2455 * free the hostname list in LocalHostName, because that's
2456 * our own addresses, and we just want to have to look it
2457 * up once and save it. Also don't free it if it's
2458 * NullHostName, because that's a special one we use if
2459 * name service lookup fails.
2460 *
2461 * By having hostname cache, now host_list_t will be shared
2462 * by messages and hostname cache. hl_refcnt is used for
2463 * the purpose.
2464 */
2465 static void
2466 freehl(host_list_t *h)
2467 {
2468 int i, refcnt;
2469 pthread_t mythreadno;
2470
2471 if (Debug) {
2472 mythreadno = pthread_self();
2473 }
2474
2475 DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno, (void *)h);
2476
2477 if (h == NULL || h == &LocalHostName || h == &NullHostName) {
2478 return;
2479 }
2480
2481 (void) pthread_mutex_lock(&h->hl_mutex);
2482 refcnt = --h->hl_refcnt;
2483 (void) pthread_mutex_unlock(&h->hl_mutex);
2484
2485 if (refcnt != 0) {
2486 DPRINT3(5, "freehl(%u): %p has reference %d\n",
2487 mythreadno, (void *)h, refcnt);
2488 return;
2489 }
2490
2491 (void) pthread_mutex_destroy(&h->hl_mutex);
2492
2493 DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno, (void *)h);
2494
2495 for (i = 0; i < h->hl_cnt; i++) {
2496 free(h->hl_hosts[i]);
2497 }
2498
2499 free(h->hl_hosts);
2500 free(h);
2501 }
2502
2503 /*
2504 * Create the door file and the pid file in /var/run. If the filesystem
2505 * containing /etc is writable, create symlinks /etc/.syslog_door and
2506 * /etc/syslog.pid to them. On systems that do not support /var/run, create
2507 * /etc/.syslog_door and /etc/syslog.pid directly.
2508 *
2509 * Note: it is not considered fatal to fail to create the pid file or its
2510 * symlink. Attempts to use them in the usual way will fail, of course, but
2511 * syslogd will function nicely without it (not so for the door file).
2512 */
2513
2514 static void
2515 open_door(void)
2516 {
2517 struct stat buf;
2518 door_info_t info;
2519 char line[MAXLINE+1];
2520 pthread_t mythreadno;
2521 int err;
2522
2523 if (Debug) {
2524 mythreadno = pthread_self();
2525 }
2526
2527 /*
2528 * first see if another syslogd is running by trying
2529 * a door call - if it succeeds, there is already
2530 * a syslogd process active
2531 */
2532
2533 if (!DoorCreated) {
2534 int door;
2535
2536 if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
2537 DPRINT2(5, "open_door(%u): %s opened "
2538 "successfully\n", mythreadno, DoorFileName);
2539
2540 if (door_info(door, &info) >= 0) {
2541 DPRINT2(5, "open_door(%u): "
2542 "door_info:info.di_target = %ld\n",
2543 mythreadno, info.di_target);
2544
2545 if (info.di_target > 0) {
2546 (void) sprintf(line, "syslogd pid %ld"
2547 " already running. Cannot "
2548 "start another syslogd pid %ld",
2549 info.di_target, getpid());
2550 DPRINT2(5, "open_door(%u): error: "
2551 "%s\n", mythreadno, line);
2552 errno = 0;
2553 logerror(line);
2554 exit(1);
2555 }
2556 }
2557
2558 (void) close(door);
2559 } else {
2560 if (lstat(DoorFileName, &buf) < 0) {
2561 err = errno;
2562
2563 DPRINT3(5, "open_door(%u): lstat() of %s "
2564 "failed, errno=%d\n",
2565 mythreadno, DoorFileName, err);
2566
2567 if ((door = creat(DoorFileName, 0644)) < 0) {
2568 err = errno;
2569 (void) snprintf(line, sizeof (line),
2570 "creat() of %s failed - fatal",
2571 DoorFileName);
2572 DPRINT3(1, "open_door(%u): error: %s, "
2573 "errno=%d\n", mythreadno, line,
2574 err);
2575 errno = err;
2576 logerror(line);
2577 delete_doorfiles();
2578 exit(1);
2579 }
2580
2581 (void) fchmod(door,
2582 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
2583
2584 DPRINT2(5, "open_door(%u): creat() of %s "
2585 "succeeded\n", mythreadno,
2586 DoorFileName);
2587
2588 (void) close(door);
2589 }
2590 }
2591
2592 if (strcmp(DoorFileName, DOORFILE) == 0) {
2593 if (lstat(OLD_DOORFILE, &buf) == 0) {
2594 DPRINT2(5, "open_door(%u): lstat() of %s "
2595 "succeeded\n", mythreadno,
2596 OLD_DOORFILE);
2597
2598 if (S_ISDIR(buf.st_mode)) {
2599 (void) snprintf(line, sizeof (line),
2600 "%s is a directory - fatal",
2601 OLD_DOORFILE);
2602 DPRINT2(1, "open_door(%u): error: "
2603 "%s\n", mythreadno, line);
2604 errno = 0;
2605 logerror(line);
2606 delete_doorfiles();
2607 exit(1);
2608 }
2609
2610 DPRINT2(5, "open_door(%u): %s is not a "
2611 "directory\n",
2612 mythreadno, OLD_DOORFILE);
2613
2614 if (unlink(OLD_DOORFILE) < 0) {
2615 err = errno;
2616 (void) snprintf(line, sizeof (line),
2617 "unlink() of %s failed",
2618 OLD_DOORFILE);
2619 DPRINT2(5, "open_door(%u): %s\n",
2620 mythreadno, line);
2621
2622 if (err != EROFS) {
2623 DPRINT3(1, "open_door(%u): "
2624 "error: %s, "
2625 "errno=%d\n",
2626 mythreadno, line, err);
2627 (void) strcat(line, " - fatal");
2628 errno = err;
2629 logerror(line);
2630 delete_doorfiles();
2631 exit(1);
2632 }
2633
2634 DPRINT1(5, "open_door(%u): unlink "
2635 "failure OK on RO file "
2636 "system\n", mythreadno);
2637 }
2638 } else {
2639 DPRINT2(5, "open_door(%u): file %s doesn't "
2640 "exist\n", mythreadno, OLD_DOORFILE);
2641 }
2642
2643 if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
2644 err = errno;
2645 (void) snprintf(line, sizeof (line),
2646 "symlink %s -> %s failed", OLD_DOORFILE,
2647 RELATIVE_DOORFILE);
2648 DPRINT2(5, "open_door(%u): %s\n", mythreadno,
2649 line);
2650
2651 if (err != EROFS) {
2652 DPRINT3(1, "open_door(%u): error: %s, "
2653 "errno=%d\n", mythreadno, line,
2654 err);
2655 errno = err;
2656 (void) strcat(line, " - fatal");
2657 logerror(line);
2658 delete_doorfiles();
2659 exit(1);
2660 }
2661
2662 DPRINT1(5, "open_door(%u): symlink failure OK "
2663 "on RO file system\n", mythreadno);
2664 } else {
2665 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2666 "succeeded\n", mythreadno,
2667 OLD_DOORFILE, RELATIVE_DOORFILE);
2668 }
2669 }
2670
2671 if ((DoorFd = door_create(server, 0,
2672 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
2673 err = errno;
2674 (void) sprintf(line, "door_create() failed - fatal");
2675 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n",
2676 mythreadno, line, err);
2677 errno = err;
2678 logerror(line);
2679 delete_doorfiles();
2680 exit(1);
2681 }
2682 (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
2683 DPRINT2(5, "open_door(%u): door_create() succeeded, "
2684 "DoorFd=%d\n", mythreadno, DoorFd);
2685
2686 DoorCreated = 1;
2687 }
2688
2689 (void) fdetach(DoorFileName); /* just in case... */
2690
2691 (void) door_server_create(door_server_pool);
2692
2693 if (fattach(DoorFd, DoorFileName) < 0) {
2694 err = errno;
2695 (void) snprintf(line, sizeof (line), "fattach() of fd"
2696 " %d to %s failed - fatal", DoorFd, DoorFileName);
2697 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno,
2698 line, err);
2699 errno = err;
2700 logerror(line);
2701 delete_doorfiles();
2702 exit(1);
2703 }
2704
2705 DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno,
2706 DoorFileName);
2707
2708 /*
2709 * create pidfile anyway, so those using it to control
2710 * syslogd (with kill `cat /etc/syslog.pid` perhaps)
2711 * don't get broken.
2712 */
2713
2714 if (!PidfileCreated) {
2715 int pidfd;
2716
2717 PidfileCreated = 1;
2718
2719 if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644))
2720 < 0) {
2721 err = errno;
2722 (void) snprintf(line, sizeof (line),
2723 "open() of %s failed", PidFileName);
2724 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2725 mythreadno, line, err);
2726 errno = err;
2727 logerror(line);
2728 return;
2729 }
2730
2731 (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
2732 (void) sprintf(line, "%ld\n", getpid());
2733
2734 if (write(pidfd, line, strlen(line)) < 0) {
2735 err = errno;
2736 (void) snprintf(line, sizeof (line),
2737 "write to %s on fd %d failed", PidFileName, pidfd);
2738 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
2739 mythreadno, line, err);
2740 errno = err;
2741 logerror(line);
2742 return;
2743 }
2744
2745 (void) close(pidfd);
2746
2747 DPRINT2(5, "open_door(%u): %s created\n",
2748 mythreadno, PidFileName);
2749
2750 if (strcmp(PidFileName, PIDFILE) == 0) {
2751 if (lstat(OLD_PIDFILE, &buf) == 0) {
2752 DPRINT2(5, "open_door(%u): lstat() of %s "
2753 "succeded\n", mythreadno, OLD_PIDFILE);
2754
2755 if (S_ISDIR(buf.st_mode)) {
2756 (void) snprintf(line, sizeof (line),
2757 "file %s is a directory",
2758 OLD_PIDFILE);
2759 DPRINT2(1, "open_door(%u): warning: "
2760 "%s\n", mythreadno, line);
2761 errno = 0;
2762 logerror(line);
2763 return;
2764 }
2765
2766 if (unlink(OLD_PIDFILE) < 0) {
2767 err = errno;
2768 (void) snprintf(line, sizeof (line),
2769 "unlink() of %s failed",
2770 OLD_PIDFILE);
2771 DPRINT2(5, "open_door(%u): %s\n",
2772 mythreadno, line);
2773
2774 if (err != EROFS) {
2775 DPRINT3(1, "open_door (%u): "
2776 "warning: %s, "
2777 "errno=%d\n",
2778 mythreadno, line, err);
2779 errno = err;
2780 logerror(line);
2781 return;
2782 }
2783
2784 DPRINT1(5, "open_door(%u): unlink "
2785 "failure OK on RO file "
2786 "system\n", mythreadno);
2787 }
2788 } else {
2789 DPRINT2(5, "open_door(%u): file %s doesn't "
2790 "exist\n", mythreadno, OLD_PIDFILE);
2791 }
2792
2793 if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) {
2794 err = errno;
2795 (void) snprintf(line, sizeof (line),
2796 "symlink %s -> %s failed", OLD_PIDFILE,
2797 RELATIVE_PIDFILE);
2798 DPRINT2(5, "open_door(%u): %s\n", mythreadno,
2799 line);
2800
2801 if (err != EROFS) {
2802 DPRINT3(1, "open_door(%u): warning: "
2803 "%s, errno=%d\n", mythreadno,
2804 line, err);
2805 errno = err;
2806 logerror(line);
2807 return;
2808 }
2809
2810 DPRINT1(5, "open_door(%u): symlink failure OK "
2811 "on RO file system\n", mythreadno);
2812 return;
2813 }
2814
2815 DPRINT3(5, "open_door(%u): symlink %s -> %s "
2816 "succeeded\n", mythreadno, OLD_PIDFILE,
2817 RELATIVE_PIDFILE);
2818 }
2819 }
2820 }
2821
2822 /*
2823 * the 'server' function that we export via the door. It does
2824 * nothing but return.
2825 */
2826 /*ARGSUSED*/
2827 static void
2828 server(void *cookie, char *argp, size_t arg_size,
2829 door_desc_t *dp, uint_t n)
2830 {
2831 (void) door_return(NULL, 0, NULL, 0);
2832 /* NOTREACHED */
2833 }
2834
2835 /*ARGSUSED*/
2836 static void *
2837 create_door_thr(void *arg)
2838 {
2839 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2840 (void) door_return(NULL, 0, NULL, 0);
2841
2842 /*
2843 * If there is an error in door_return(), it will return here and
2844 * the thread will exit. Hence we need to decrement door_server_cnt.
2845 */
2846 (void) pthread_mutex_lock(&door_server_cnt_lock);
2847 door_server_cnt--;
2848 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2849 return (NULL);
2850 }
2851
2852 /*
2853 * Max number of door server threads for syslogd. Since door is used
2854 * to check the health of syslogd, we don't need large number of
2855 * server threads.
2856 */
2857 #define MAX_DOOR_SERVER_THR 3
2858
2859 /*
2860 * Manage door server thread pool.
2861 */
2862 /*ARGSUSED*/
2863 static void
2864 door_server_pool(door_info_t *dip)
2865 {
2866 (void) pthread_mutex_lock(&door_server_cnt_lock);
2867 if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
2868 pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
2869 door_server_cnt++;
2870 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2871 return;
2872 }
2873
2874 (void) pthread_mutex_unlock(&door_server_cnt_lock);
2875 }
2876
2877 /*
2878 * checkm4 - used to verify that the external utilities that
2879 * syslogd depends on are where we expect them to be.
2880 * Returns 0 if all utilities are found, > 0 if any are missing.
2881 * Also logs errors so user knows what's missing
2882 */
2883 static int
2884 checkm4(void)
2885 {
2886 int notfound = 0;
2887 int saverrno;
2888 pthread_t mythreadno;
2889
2890 if (Debug) {
2891 mythreadno = pthread_self();
2892 }
2893
2894 if (access("/usr/ccs/bin/m4", X_OK) < 0) {
2895 saverrno = errno;
2896 logerror("/usr/ccs/bin/m4");
2897 DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access "
2898 "returned %d\n", mythreadno, saverrno);
2899 notfound++;
2900 }
2901
2902 return (notfound);
2903 }
2904
2905 /*
2906 * INIT -- Initialize syslogd from configuration table, start up
2907 * input and logger threads. This routine is called only once.
2908 */
2909 static void
2910 init(void)
2911 {
2912 struct utsname *up;
2913 pthread_attr_t sys_attr, net_attr, log_attr, hnl_attr;
2914 int nthread;
2915 pthread_t mythreadno;
2916
2917 if (Debug) {
2918 mythreadno = pthread_self();
2919 }
2920
2921 DPRINT1(2, "init(%u): initializing\n", mythreadno);
2922
2923 /* hand-craft a host_list_t entry for our local host name */
2924 if ((up = malloc(sizeof (struct utsname))) == NULL) {
2925 MALLOC_FAIL_EXIT;
2926 }
2927 (void) uname(up);
2928 LocalHostName.hl_cnt = 1;
2929 if ((LocalHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
2930 MALLOC_FAIL_EXIT;
2931 }
2932 if ((LocalHostName.hl_hosts[0] = strdup(up->nodename)) == NULL) {
2933 free(LocalHostName.hl_hosts);
2934 MALLOC_FAIL_EXIT;
2935 }
2936 free(up);
2937 /* also hand craft one for use if name resolution fails */
2938 NullHostName.hl_cnt = 1;
2939 if ((NullHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
2940 MALLOC_FAIL_EXIT;
2941 }
2942 if ((NullHostName.hl_hosts[0] = strdup("name lookup failed")) == NULL) {
2943 MALLOC_FAIL_EXIT;
2944 }
2945
2946 hnc_init(0);
2947
2948 /*
2949 * Note that getnets will allocate network resources, but won't be
2950 * binding UDP port. This is because, there could be a race
2951 * condition between door. If we bind here, one syslogd could grab
2952 * UDP port first, but later another syslogd could take over without
2953 * getting UDP port but grab the door file. The 2nd syslogd could
2954 * continue to run without listening network.
2955 * bindnet() will be called after door was successfully opened.
2956 */
2957 getnets();
2958
2959 /*
2960 * Start up configured theads
2961 */
2962 conf_init();
2963
2964 /*
2965 * allocate thread stacks for the persistant threads
2966 */
2967 nthread = (turnoff == 0) ? 4 : 2;
2968
2969 if ((stack_ptr = alloc_stacks(nthread)) == NULL) {
2970 logerror("alloc_stacks failed - fatal");
2971 exit(1);
2972 }
2973
2974 if (Debug) {
2975 dumpstats(STDOUT_FILENO);
2976 }
2977
2978 (void) dataq_init(&inputq); /* init the input queue */
2979
2980 if (pthread_attr_init(&sys_attr) != 0 ||
2981 pthread_attr_init(&log_attr) != 0 ||
2982 pthread_attr_init(&net_attr) != 0 ||
2983 pthread_attr_init(&hnl_attr) != 0 ||
2984 pthread_attr_init(&door_thr_attr) != 0) {
2985 logerror("pthread_attr_init failed - fatal");
2986 exit(1);
2987 }
2988
2989 (void) pthread_attr_setscope(&sys_attr, PTHREAD_SCOPE_PROCESS);
2990 (void) pthread_attr_setscope(&log_attr, PTHREAD_SCOPE_PROCESS);
2991 (void) pthread_attr_setscope(&net_attr, PTHREAD_SCOPE_PROCESS);
2992 (void) pthread_attr_setscope(&hnl_attr, PTHREAD_SCOPE_PROCESS);
2993 (void) pthread_attr_setscope(&door_thr_attr, PTHREAD_SCOPE_SYSTEM);
2994 (void) pthread_attr_setdetachstate(&door_thr_attr,
2995 PTHREAD_CREATE_DETACHED);
2996
2997 /* 1: logmsg thread */
2998 (void) pthread_attr_setstacksize(&log_attr, stacksize);
2999 (void) pthread_attr_setstackaddr(&log_attr, stack_ptr);
3000 stack_ptr += stacksize + redzonesize;
3001 if (pthread_create(&log_thread, &log_attr, logmsg, NULL) != 0) {
3002 logerror("pthread_create failed - fatal");
3003 exit(1);
3004 }
3005
3006 /*
3007 * open the log device, and pull up all pending message
3008 * from the log driver.
3009 */
3010 prepare_sys_poll();
3011
3012 /*
3013 * Now we can deliver the pending internal error messages.
3014 */
3015 enable_errorlog();
3016
3017 /* 2: sys_poll thread */
3018 (void) pthread_attr_setstacksize(&sys_attr, stacksize);
3019 (void) pthread_attr_setstackaddr(&sys_attr, stack_ptr);
3020 stack_ptr += stacksize + redzonesize;
3021 if (pthread_create(&sys_thread, &sys_attr, sys_poll, NULL) != 0) {
3022 logerror("pthread_create failed - fatal");
3023 exit(1);
3024 }
3025
3026 /*
3027 * We've started the sys_poll() and logmsg() threads. Now we are ready
3028 * to open the door. This cannot happen before spawning sys_poll(),
3029 * because after opening the door, syslog() will no longer take care of
3030 * LOG_CONS. Therefor, we should pull up all pending log messages and
3031 * activate sys_poll() before opening the door, so that log driver
3032 * won't drop messages.
3033 */
3034 open_door();
3035
3036 DPRINT1(1, "init(%u): accepting messages from local system\n",
3037 mythreadno);
3038
3039 if (turnoff == 0) {
3040 /* init the hostname lookup queue */
3041 (void) dataq_init(&hnlq);
3042
3043 /* 3: hostname lookup thread */
3044 (void) pthread_attr_setstacksize(&hnl_attr, stacksize);
3045 (void) pthread_attr_setstackaddr(&hnl_attr, stack_ptr);
3046 stack_ptr += stacksize + redzonesize;
3047 if (pthread_create(&hnl_thread, &hnl_attr,
3048 hostname_lookup, NULL) != 0) {
3049 logerror("pthread_create failed - fatal");
3050 exit(1);
3051 }
3052
3053 /* 4: net_poll thread */
3054 (void) pthread_attr_setstacksize(&net_attr, stacksize);
3055 (void) pthread_attr_setstackaddr(&net_attr, stack_ptr);
3056 stack_ptr += stacksize + redzonesize;
3057
3058 /* grab UDP port */
3059 bindnet();
3060
3061 if (pthread_create(&net_thread, &net_attr, net_poll,
3062 NULL) != 0) {
3063 logerror("pthread_create failed - fatal");
3064 exit(1);
3065 }
3066 DPRINT1(1, "init(%u): accepting messages from remote\n",
3067 mythreadno);
3068 }
3069
3070 (void) pthread_attr_destroy(&sys_attr);
3071 (void) pthread_attr_destroy(&net_attr);
3072 (void) pthread_attr_destroy(&log_attr);
3073 (void) pthread_attr_destroy(&hnl_attr);
3074
3075 curalarm = MarkInterval * 60 / MARKCOUNT;
3076 (void) alarm((unsigned)curalarm);
3077 DPRINT2(2, "init(%u): Next alarm in %d seconds\n",
3078 mythreadno, curalarm);
3079 DPRINT1(1, "init(%u): syslogd: started\n", mythreadno);
3080 }
3081
3082 /*
3083 * will print a bunch of debugging stats on 'fd'
3084 */
3085 static void
3086 dumpstats(int fd)
3087 {
3088 FILE *out;
3089 struct filed *f;
3090 int i;
3091 char users[1024];
3092 char cbuf[30];
3093 char *dashes = "------------------------";
3094 static int conversion_printed;
3095
3096 if ((out = fdopen(fd, "w+")) == NULL)
3097 return;
3098
3099 (void) fprintf(out, "\nSyslogd started: %s",
3100 ctime_r(&start_time, cbuf));
3101 (void) fprintf(out, "Input message count: system %d, network %d\n",
3102 sys_msg_count, net_msg_count);
3103 (void) fprintf(out, "# Outputs: %d\n\n", nlogs);
3104
3105 (void) fprintf(out, "%s priority = [file, facility] %s\n\n",
3106 dashes, dashes);
3107
3108 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3109 (void) fprintf(out, "%d ", i / 10);
3110 }
3111 (void) fprintf(out, "\n");
3112 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3113 (void) fprintf(out, "%d ", i % 10);
3114 }
3115 (void) fprintf(out, "\n");
3116 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3117 (void) fprintf(out, "--");
3118 }
3119 (void) fprintf(out, "\n");
3120
3121 for (f = Files; f < &Files[nlogs]; f++) {
3122 for (i = 0; i < LOG_NFACILITIES + 1; i++) {
3123 if (f->f_pmask[i] == NOPRI)
3124 (void) fprintf(out, "X ");
3125 else
3126 (void) fprintf(out, "%d ",
3127 f->f_pmask[i]);
3128 }
3129 (void) fprintf(out, "%s: ", TypeNames[f->f_type]);
3130 switch (f->f_type) {
3131 case F_FILE:
3132 case F_TTY:
3133 case F_CONSOLE:
3134 (void) fprintf(out, "%s", f->f_un.f_fname);
3135 break;
3136 case F_FORW:
3137 (void) fprintf(out, "%s", f->f_un.f_forw.f_hname);
3138 break;
3139 case F_USERS:
3140 for (i = 0; i < MAXUNAMES &&
3141 *f->f_un.f_uname[i]; i++) {
3142 if (!i)
3143 (void) fprintf(out, "%s",
3144 f->f_un.f_uname[i]);
3145 else
3146 (void) fprintf(out, ", %s",
3147 f->f_un.f_uname[i]);
3148 }
3149 break;
3150 }
3151 (void) fprintf(out, "\n");
3152 }
3153
3154 if (!conversion_printed) {
3155 (void) fprintf(out, "\nFacilities:\n");
3156
3157 for (i = 0; FacNames[i].c_val != -1; i++) {
3158 (void) fprintf(out, " [%02d] %s: %3d\n", i,
3159 FacNames[i].c_name, FacNames[i].c_val);
3160 }
3161
3162 (void) fprintf(out, "\nPriorities:\n");
3163
3164 for (i = 0; PriNames[i].c_val != -1; i++) {
3165 (void) fprintf(out, " [%02d] %s: %3d\n", i,
3166 PriNames[i].c_name, PriNames[i].c_val);
3167 }
3168
3169 conversion_printed = 1;
3170 }
3171
3172 (void) fprintf(out, "\n\n\n\t\tPer File Statistics\n");
3173 (void) fprintf(out, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File");
3174 (void) fprintf(out, "%-24s\t---\t----\t-----\t----\n", "----");
3175 for (f = Files; f < &Files[nlogs]; f++) {
3176 switch (f->f_type) {
3177 case F_FILE:
3178 case F_TTY:
3179 case F_CONSOLE:
3180 (void) fprintf(out, "%-24s", f->f_un.f_fname);
3181 break;
3182 case F_WALL:
3183 (void) fprintf(out, "%-24s", TypeNames[f->f_type]);
3184 break;
3185 case F_FORW:
3186 (void) fprintf(out, "%-24s", f->f_un.f_forw.f_hname);
3187 break;
3188 case F_USERS:
3189 for (i = 0; i < MAXUNAMES &&
3190 *f->f_un.f_uname[i]; i++) {
3191 if (!i)
3192 (void) strcpy(users,
3193 f->f_un.f_uname[i]);
3194 else {
3195 (void) strcat(users, ",");
3196 (void) strcat(users,
3197 f->f_un.f_uname[i]);
3198 }
3199 }
3200 (void) fprintf(out, "%-24s", users);
3201 break;
3202 }
3203 (void) fprintf(out, "\t%d\t%d\t%d\t%d\n",
3204 f->f_stat.total, f->f_stat.dups,
3205 f->f_stat.cantfwd, f->f_stat.errs);
3206 }
3207 (void) fprintf(out, "\n\n");
3208 if (Debug && fd == 1)
3209 return;
3210 (void) fclose(out);
3211 }
3212
3213 /*
3214 * conf_init - This routine is code seperated from the
3215 * init routine in order to be re-callable when we get
3216 * a SIGHUP signal.
3217 */
3218 static void
3219 conf_init(void)
3220 {
3221 char *p;
3222 int i;
3223 struct filed *f;
3224 char *m4argv[4];
3225 int m4argc = 0;
3226 conf_t cf;
3227 pthread_t mythreadno;
3228
3229 if (Debug) {
3230 mythreadno = pthread_self();
3231 }
3232
3233 DPRINT1(2, "conf_init(%u): starting logger threads\n",
3234 mythreadno);
3235
3236 m4argv[m4argc++] = "m4";
3237
3238 if (amiloghost() == 1) {
3239 DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno);
3240 m4argv[m4argc++] = "-DLOGHOST=1";
3241 }
3242
3243 m4argv[m4argc++] = ConfFile;
3244 m4argv[m4argc] = NULL;
3245
3246 /*
3247 * Make sure the configuration file and m4 exist, and then parse
3248 * the configuration file with m4. If any of these fail, resort
3249 * to our hardcoded fallback configuration.
3250 */
3251
3252 if (access(ConfFile, R_OK) == -1) {
3253 DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno,
3254 ConfFile);
3255 logerror("can't open configuration file");
3256 /* CSTYLED */
3257 Files = (struct filed *) &fallback; /*lint !e545 */
3258 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3259 cfline("*.PANIC\t*", 0, &Files[1]);
3260 nlogs = 2;
3261 goto nofile;
3262 }
3263
3264 if (checkm4() != 0 || conf_open(&cf, "/usr/ccs/bin/m4", m4argv) == -1) {
3265 DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno,
3266 ConfFile);
3267 /* CSTYLED */
3268 Files = (struct filed *) &fallback; /*lint !e545 */
3269 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3270 cfline("*.PANIC\t*", 0, &Files[1]);
3271 nlogs = 2;
3272 goto nofile;
3273 }
3274
3275 /* Count the number of lines which are not blanks or comments */
3276 nlogs = 0;
3277 while ((p = conf_read(&cf)) != NULL) {
3278 if (p[0] != '\0' && p[0] != '#')
3279 nlogs++;
3280 }
3281
3282 Files = (struct filed *)malloc(sizeof (struct filed) * nlogs);
3283
3284 if (!Files) {
3285 DPRINT1(1, "conf_init(%u): malloc failed - can't "
3286 "allocate 'Files' array\n", mythreadno);
3287 MALLOC_FAIL("loading minimum configuration");
3288 /* CSTYLED */
3289 Files = (struct filed *) &fallback; /*lint !e545 */
3290 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
3291 cfline("*.PANIC\t*", 0, &Files[1]);
3292 nlogs = 2;
3293 conf_close(&cf);
3294 goto nofile;
3295 }
3296
3297 /*
3298 * Foreach line in the conf table, open that file.
3299 */
3300 conf_rewind(&cf);
3301 f = Files;
3302 i = 0;
3303 while (((p = conf_read(&cf)) != NULL) && (f < &Files[nlogs])) {
3304 i++;
3305 /* check for end-of-section */
3306 if (p[0] == '\0' || p[0] == '#')
3307 continue;
3308
3309 cfline(p, i, f);
3310 if (f->f_type == F_UNUSED)
3311 nlogs--;
3312 else
3313 f++;
3314 }
3315
3316 conf_close(&cf);
3317
3318 /*
3319 * See if marks are to be written to any files. If so, set up a
3320 * timeout for marks.
3321 */
3322 nofile:
3323 Marking = 0;
3324
3325 /*
3326 * allocate thread stacks - one for each logger thread.
3327 */
3328 if ((cstack_ptr = alloc_stacks(nlogs)) == NULL) {
3329 logerror("alloc_stacks failed - fatal");
3330 exit(1);
3331 }
3332
3333 /* And now one thread for each configured file */
3334 for (f = Files; f < &Files[nlogs]; f++) {
3335 if (filed_init(f) != 0) {
3336 logerror("pthread_create failed - fatal");
3337 exit(1);
3338 }
3339
3340 (void) pthread_mutex_lock(&cft);
3341 ++conf_threads;
3342 (void) pthread_mutex_unlock(&cft);
3343
3344 if (f->f_type != F_UNUSED &&
3345 f->f_pmask[LOG_NFACILITIES] != NOPRI)
3346 Marking = 1;
3347 }
3348 }
3349
3350 /*
3351 * filed init - initialize fields in a file descriptor struct
3352 * this is called before multiple threads are running, so no mutex
3353 * needs to be held at this time.
3354 */
3355 static int
3356 filed_init(struct filed *f)
3357 {
3358 pthread_attr_t stack_attr;
3359 pthread_t mythreadno;
3360
3361 if (Debug) {
3362 mythreadno = pthread_self();
3363 }
3364
3365 if (pthread_mutex_init(&f->filed_mutex, NULL) != 0) {
3366 logerror("pthread_mutex_init failed");
3367 return (-1);
3368 }
3369
3370 DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n",
3371 mythreadno, (void *)&f->f_queue);
3372 (void) dataq_init(&f->f_queue);
3373
3374 if (pthread_attr_init(&stack_attr) != 0) {
3375 logerror("pthread_attr_init failed");
3376 return (-1);
3377 }
3378
3379 (void) pthread_attr_setstacksize(&stack_attr, stacksize);
3380 (void) pthread_attr_setstackaddr(&stack_attr, cstack_ptr);
3381 cstack_ptr += stacksize + redzonesize;
3382
3383 f->f_msgflag = 0;
3384 f->f_prevmsg.msg[0] = '\0';
3385 f->f_prevmsg.flags = 0;
3386 f->f_prevmsg.pri = 0;
3387 f->f_prevmsg.host[0] = '\0';
3388
3389 f->f_current.msg[0] = '\0';
3390 f->f_current.flags = 0;
3391 f->f_current.pri = 0;
3392 f->f_current.host[0] = '\0';
3393
3394 f->f_prevcount = 0;
3395
3396 f->f_stat.flag = 0;
3397 f->f_stat.total = 0;
3398 f->f_stat.dups = 0;
3399 f->f_stat.cantfwd = 0;
3400 f->f_stat.errs = 0;
3401
3402 if (pthread_create(&f->f_thread, NULL, logit, (void *)f) != 0) {
3403 logerror("pthread_create failed");
3404 (void) pthread_attr_destroy(&stack_attr);
3405 return (-1);
3406 }
3407
3408 (void) pthread_attr_destroy(&stack_attr);
3409 return (0);
3410 }
3411
3412
3413 /*
3414 * Crack a configuration file line
3415 */
3416 static void
3417 cfline(char *line, int lineno, struct filed *f)
3418 {
3419 char *p;
3420 char *q;
3421 int i;
3422 char *bp;
3423 int pri;
3424 char buf[MAXLINE];
3425 char ebuf[SYS_NMLN+1+40];
3426 mode_t fmode, omode = O_WRONLY|O_APPEND|O_NOCTTY;
3427 struct stat64 sbuf;
3428 pthread_t mythreadno;
3429
3430 if (Debug) {
3431 mythreadno = pthread_self();
3432 }
3433
3434 DPRINT2(1, "cfline(%u): (%s)\n", mythreadno, line);
3435
3436 errno = 0; /* keep errno related stuff out of logerror messages */
3437
3438 /* clear out file entry */
3439 bzero((char *)f, sizeof (*f));
3440 for (i = 0; i <= LOG_NFACILITIES; i++)
3441 f->f_pmask[i] = NOPRI;
3442
3443 /* scan through the list of selectors */
3444 for (p = line; *p && *p != '\t'; ) {
3445
3446 /* find the end of this facility name list */
3447 for (q = p; *q && *q != '\t' && *q++ != '.'; )
3448 continue;
3449
3450 /* collect priority name */
3451 for (bp = buf; *q && !strchr("\t,;", *q); )
3452 *bp++ = *q++;
3453 *bp = '\0';
3454
3455 /* skip cruft */
3456 while (strchr(", ;", *q))
3457 q++;
3458
3459 /* decode priority name */
3460 pri = decode(buf, PriNames);
3461 if (pri < 0) {
3462 logerror("line %d: unknown priority name \"%s\"",
3463 lineno, buf);
3464 return;
3465 }
3466
3467 /* scan facilities */
3468 while (*p && !strchr("\t.;", *p)) {
3469 for (bp = buf; *p && !strchr("\t,;.", *p); )
3470 *bp++ = *p++;
3471 *bp = '\0';
3472 if (*buf == '*')
3473 for (i = 0; i < LOG_NFACILITIES; i++)
3474 f->f_pmask[i] = (uchar_t)pri;
3475 else {
3476 i = decode(buf, FacNames);
3477 if (i < 0) {
3478 logerror("line %d: unknown facility"
3479 " name \"%s\"", lineno, buf);
3480 return;
3481 }
3482 f->f_pmask[i >> 3] = (uchar_t)pri;
3483 }
3484 while (*p == ',' || *p == ' ')
3485 p++;
3486 }
3487
3488 p = q;
3489 }
3490
3491 /* skip to action part */
3492 while (*p == '\t' || *p == ' ')
3493 p++;
3494
3495 switch (*p) {
3496 case '\0':
3497 errno = 0;
3498 logerror("line %d: no action part", lineno);
3499 break;
3500
3501 case '@':
3502 (void) strlcpy(f->f_un.f_forw.f_hname, ++p, SYS_NMLN);
3503 if (logforward(f, ebuf, sizeof (ebuf)) != 0) {
3504 logerror("line %d: %s", lineno, ebuf);
3505 break;
3506 }
3507 f->f_type = F_FORW;
3508 break;
3509
3510 case '/':
3511 (void) strlcpy(f->f_un.f_fname, p, MAXPATHLEN);
3512 if (stat64(p, &sbuf) < 0) {
3513 logerror(p);
3514 break;
3515 }
3516 /*
3517 * don't block trying to open a pipe
3518 * with no reader on the other end
3519 */
3520 fmode = 0; /* reset each pass */
3521 if (S_ISFIFO(sbuf.st_mode))
3522 fmode = O_NONBLOCK;
3523
3524 f->f_file = open64(p, omode|fmode);
3525 if (f->f_file < 0) {
3526 if (fmode && errno == ENXIO) {
3527 errno = 0;
3528 logerror("%s - no reader", p);
3529 } else
3530 logerror(p);
3531 break;
3532 }
3533
3534 /*
3535 * Fifos are initially opened NONBLOCK
3536 * to insure we don't hang, but once
3537 * we are open, we need to change the
3538 * behavior back to blocking, otherwise
3539 * we may get write errors, and the log
3540 * will get closed down the line.
3541 */
3542 if (S_ISFIFO(sbuf.st_mode))
3543 (void) fcntl(f->f_file, F_SETFL, omode);
3544
3545 if (isatty(f->f_file)) {
3546 f->f_type = F_TTY;
3547 untty();
3548 } else
3549 f->f_type = F_FILE;
3550
3551 if ((strcmp(p, ctty) == 0) || (strcmp(p, sysmsg) == 0))
3552 f->f_type = F_CONSOLE;
3553 break;
3554
3555 case '*':
3556 f->f_type = F_WALL;
3557 break;
3558
3559 default:
3560 for (i = 0; i < MAXUNAMES && *p; i++) {
3561 for (q = p; *q && *q != ','; )
3562 q++;
3563 (void) strlcpy(f->f_un.f_uname[i], p, UNAMESZ);
3564 if ((q - p) > UNAMESZ)
3565 f->f_un.f_uname[i][UNAMESZ] = '\0';
3566 else
3567 f->f_un.f_uname[i][q - p] = '\0';
3568 while (*q == ',' || *q == ' ')
3569 q++;
3570 p = q;
3571 }
3572 f->f_type = F_USERS;
3573 break;
3574 }
3575 f->f_orig_type = f->f_type;
3576 }
3577
3578
3579 /*
3580 * Decode a symbolic name to a numeric value
3581 */
3582 static int
3583 decode(char *name, struct code *codetab)
3584 {
3585 struct code *c;
3586 char *p;
3587 char buf[40];
3588
3589 if (isdigit(*name))
3590 return (atoi(name));
3591
3592 (void) strncpy(buf, name, sizeof (buf) - 1);
3593 for (p = buf; *p; p++)
3594 if (isupper(*p))
3595 *p = tolower(*p);
3596 for (c = codetab; c->c_name; c++)
3597 if (!(strcmp(buf, c->c_name)))
3598 return (c->c_val);
3599
3600 return (-1);
3601 }
3602
3603 static int
3604 ismyaddr(struct netbuf *nbp)
3605 {
3606 int i;
3607
3608 if (nbp == NULL)
3609 return (0);
3610
3611 for (i = 1; i < Ninputs; i++) {
3612 if (same_addr(nbp, Myaddrs[i]))
3613 return (1);
3614 }
3615 return (0);
3616 }
3617
3618 static void
3619 getnets(void)
3620 {
3621 struct nd_hostserv hs;
3622 struct netconfig *ncp;
3623 struct nd_addrlist *nap;
3624 struct netbuf *nbp;
3625 int i, inputs;
3626 void *handle;
3627 char *uap;
3628 pthread_t mythreadno;
3629
3630 if (Debug) {
3631 mythreadno = pthread_self();
3632 }
3633
3634 if (turnoff) {
3635 DPRINT1(1, "getnets(%u): network is being turned off\n",
3636 mythreadno);
3637 return;
3638 }
3639
3640 hs.h_host = HOST_SELF;
3641 hs.h_serv = "syslog";
3642
3643 if ((handle = setnetconfig()) == NULL) {
3644 return;
3645 }
3646
3647 while ((ncp = getnetconfig(handle)) != NULL) {
3648 if (ncp->nc_semantics != NC_TPI_CLTS) {
3649 continue;
3650 }
3651
3652 if (netdir_getbyname(ncp, &hs, &nap) != 0) {
3653 continue;
3654 }
3655
3656 if (nap == NULL || nap->n_cnt <= 0) {
3657 DPRINT1(1, "getnets(%u): found no address\n",
3658 mythreadno);
3659 netdir_free((void *)nap, ND_ADDRLIST);
3660 continue;
3661 }
3662
3663 if (Debug) {
3664 DPRINT2(1, "getnets(%u): found %d addresses",
3665 mythreadno, nap->n_cnt);
3666 DPRINT0(1, ", they are: ");
3667 nbp = nap->n_addrs;
3668
3669 for (i = 0; i < nap->n_cnt; i++) {
3670 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
3671 DPRINT1(1, "%s ", uap);
3672 free(uap);
3673 }
3674 nbp++;
3675 }
3676
3677 DPRINT0(1, "\n");
3678 }
3679
3680 inputs = Ninputs + nap->n_cnt;
3681
3682 Nfd = realloc(Nfd, inputs * sizeof (struct pollfd));
3683 Ncf = realloc(Ncf, inputs * sizeof (struct netconfig));
3684 Myaddrs = realloc(Myaddrs, inputs * sizeof (struct netbuf *));
3685 Udp = realloc(Udp, inputs * sizeof (struct t_unitdata *));
3686 Errp = realloc(Errp, inputs * sizeof (struct t_uderr *));
3687
3688 /*
3689 * all malloc failures here are fatal
3690 */
3691 if (Nfd == NULL || Ncf == NULL || Myaddrs == NULL ||
3692 Udp == NULL || Errp == NULL) {
3693 MALLOC_FAIL_EXIT;
3694 }
3695
3696 nbp = nap->n_addrs;
3697
3698 for (i = 0; i < nap->n_cnt; i++, nbp++) {
3699 char ebuf[128];
3700
3701 if (addnet(ncp, nbp) == 0) {
3702 /* no error */
3703 continue;
3704 }
3705
3706 (void) strcpy(ebuf, "Unable to configure syslog port");
3707
3708 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
3709 size_t l = strlen(ebuf);
3710 (void) snprintf(ebuf + l, sizeof (ebuf) - l,
3711 " for %s", uap);
3712 }
3713
3714 DPRINT2(1, "getnets(%u): %s",
3715 mythreadno, ebuf);
3716
3717 if (uap) {
3718 free(uap);
3719 }
3720
3721 logerror(ebuf);
3722 /*
3723 * Here maybe syslogd can quit. However, syslogd
3724 * has been ignoring this error and keep running.
3725 * So we won't break it.
3726 */
3727 }
3728
3729 netdir_free((void *)nap, ND_ADDRLIST);
3730 }
3731
3732 (void) endnetconfig(handle);
3733 }
3734
3735 /*
3736 * Open the network device, and allocate necessary resources.
3737 * Myaddrs will also be filled, so that we can call ismyaddr() before
3738 * being bound to the network.
3739 */
3740 static int
3741 addnet(struct netconfig *ncp, struct netbuf *nbp)
3742 {
3743 int fd;
3744 struct netbuf *bp;
3745
3746 fd = t_open(ncp->nc_device, O_RDWR, NULL);
3747
3748 if (fd < 0) {
3749 return (1);
3750 }
3751
3752 (void) memcpy(&Ncf[Ninputs], ncp, sizeof (struct netconfig));
3753
3754 /*LINTED*/
3755 Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR);
3756
3757 if (Udp[Ninputs] == NULL) {
3758 (void) t_close(fd);
3759 return (1);
3760 }
3761
3762 /*LINTED*/
3763 Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR);
3764
3765 if (Errp[Ninputs] == NULL) {
3766 (void) t_close(fd);
3767 (void) t_free((char *)Udp[Ninputs], T_UNITDATA);
3768 return (1);
3769 }
3770
3771 if ((bp = malloc(sizeof (struct netbuf))) == NULL ||
3772 (bp->buf = malloc(nbp->len)) == NULL) {
3773 MALLOC_FAIL("allocating address buffer");
3774 (void) t_close(fd);
3775 (void) t_free((char *)Udp[Ninputs], T_UNITDATA);
3776 (void) t_free((char *)Errp[Ninputs], T_UDERROR);
3777
3778 if (bp) {
3779 free(bp);
3780 }
3781
3782 return (1);
3783 }
3784
3785 bp->len = nbp->len;
3786 (void) memcpy(bp->buf, nbp->buf, nbp->len);
3787 Myaddrs[Ninputs] = bp;
3788
3789 Nfd[Ninputs].fd = fd;
3790 Nfd[Ninputs].events = POLLIN;
3791 Ninputs++;
3792 return (0);
3793 }
3794
3795 /*
3796 * Allocate UDP buffer to minimize packet loss.
3797 */
3798 static void
3799 set_udp_buffer(int fd)
3800 {
3801 struct t_optmgmt req, resp;
3802 struct opthdr *opt;
3803 size_t optsize, bsize = 256 * 1024;
3804 pthread_t mythreadno;
3805
3806 if (Debug) {
3807 mythreadno = pthread_self();
3808 }
3809
3810 optsize = sizeof (struct opthdr) + sizeof (int);
3811 if ((opt = malloc(optsize)) == NULL) {
3812 MALLOC_FAIL("will have no udp buffer");
3813 return;
3814 }
3815 opt->level = SOL_SOCKET;
3816 opt->name = SO_RCVBUF;
3817 opt->len = sizeof (int);
3818 *(int *)(opt + 1) = bsize;
3819
3820 req.flags = T_NEGOTIATE;
3821 req.opt.len = optsize;
3822 req.opt.buf = (char *)opt;
3823
3824 resp.flags = 0;
3825 resp.opt.maxlen = optsize;
3826 resp.opt.buf = (char *)opt;
3827
3828 while (t_optmgmt(fd, &req, &resp) == -1 || resp.flags != T_SUCCESS) {
3829 if (t_errno != TSYSERR || errno != ENOBUFS) {
3830 bsize = 0;
3831 break;
3832 }
3833 bsize >>= 1;
3834 if (bsize < 8192) {
3835 break;
3836 }
3837 *(int *)(opt + 1) = bsize;
3838 }
3839 if (bsize == 0) {
3840 logerror("failed to allocate UDP buffer");
3841 }
3842 DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n",
3843 mythreadno, bsize, fd);
3844 free(opt);
3845 }
3846
3847 /*
3848 * Attach the network, and allocate UDP buffer for the interface.
3849 */
3850 static void
3851 bindnet(void)
3852 {
3853 struct t_bind bind, *bound;
3854 int cnt, i;
3855 char *uap;
3856 pthread_t mythreadno;
3857
3858 if (Debug) {
3859 mythreadno = pthread_self();
3860 }
3861
3862 cnt = 0;
3863
3864 while (cnt < Ninputs) {
3865 char ebuf[128];
3866
3867 /*LINTED*/
3868 bound = (struct t_bind *)t_alloc(Nfd[cnt].fd, T_BIND, T_ADDR);
3869 bind.addr = *Myaddrs[cnt];
3870 bind.qlen = 0;
3871
3872 if (t_bind(Nfd[cnt].fd, &bind, bound) == 0) {
3873 if (same_addr(&bind.addr, &bound->addr)) {
3874 (void) t_free((char *)bound, T_BIND);
3875 set_udp_buffer(Nfd[cnt].fd);
3876 cnt++;
3877 continue;
3878 }
3879 }
3880
3881 /* failed to bind port */
3882 (void) t_free((char *)bound, T_BIND);
3883
3884 (void) strcpy(ebuf, "Unable to bind syslog port");
3885
3886 uap = taddr2uaddr(&Ncf[cnt], Myaddrs[cnt]);
3887 if (uap) {
3888 i = strlen(ebuf);
3889 (void) snprintf(ebuf + i, sizeof (ebuf) - i,
3890 " for %s", uap);
3891 }
3892
3893 DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n",
3894 mythreadno, uap ? uap : "<unknown>");
3895
3896 if (uap) {
3897 free(uap);
3898 }
3899
3900 errno = 0;
3901 logerror(ebuf);
3902
3903 (void) t_close(Nfd[cnt].fd);
3904 free(Myaddrs[cnt]->buf);
3905 free(Myaddrs[cnt]);
3906 (void) t_free((char *)Udp[cnt], T_UNITDATA);
3907 (void) t_free((char *)Errp[cnt], T_UDERROR);
3908
3909 for (i = cnt; i < (Ninputs-1); i++) {
3910 Nfd[i] = Nfd[i + 1];
3911 Ncf[i] = Ncf[i + 1];
3912 Myaddrs[i] = Myaddrs[i + 1];
3913 Udp[i] = Udp[i + 1];
3914 Errp[i] = Errp[i + 1];
3915 }
3916
3917 Ninputs--;
3918 }
3919 }
3920
3921 static int
3922 logforward(struct filed *f, char *ebuf, size_t elen)
3923 {
3924 struct nd_hostserv hs;
3925 struct netbuf *nbp;
3926 struct netconfig *ncp;
3927 struct nd_addrlist *nap;
3928 void *handle;
3929 char *hp;
3930
3931 hp = f->f_un.f_forw.f_hname;
3932 hs.h_host = hp;
3933 hs.h_serv = "syslog";
3934
3935 if ((handle = setnetconfig()) == NULL) {
3936 (void) strlcpy(ebuf,
3937 "unable to rewind the netconfig database", elen);
3938 errno = 0;
3939 return (-1);
3940 }
3941 nap = (struct nd_addrlist *)NULL;
3942 while ((ncp = getnetconfig(handle)) != NULL) {
3943 if (ncp->nc_semantics == NC_TPI_CLTS) {
3944 if (netdir_getbyname(ncp, &hs, &nap) == 0) {
3945 if (!nap)
3946 continue;
3947 nbp = nap->n_addrs;
3948 break;
3949 }
3950 }
3951 }
3952 if (ncp == NULL) {
3953 (void) endnetconfig(handle);
3954 (void) snprintf(ebuf, elen,
3955 "WARNING: %s could not be resolved", hp);
3956 errno = 0;
3957 return (-1);
3958 }
3959 if (nap == (struct nd_addrlist *)NULL) {
3960 (void) endnetconfig(handle);
3961 (void) snprintf(ebuf, elen, "unknown host %s", hp);
3962 errno = 0;
3963 return (-1);
3964 }
3965 /* CSTYLED */
3966 if (ismyaddr(nbp)) { /*lint !e644 */
3967 netdir_free((void *)nap, ND_ADDRLIST);
3968 (void) endnetconfig(handle);
3969 (void) snprintf(ebuf, elen,
3970 "host %s is this host - logging loop", hp);
3971 errno = 0;
3972 return (-1);
3973 }
3974 f->f_un.f_forw.f_addr.buf = malloc(nbp->len);
3975 if (f->f_un.f_forw.f_addr.buf == NULL) {
3976 netdir_free((void *)nap, ND_ADDRLIST);
3977 (void) endnetconfig(handle);
3978 (void) strlcpy(ebuf, "malloc failed", elen);
3979 return (-1);
3980 }
3981 bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len);
3982 f->f_un.f_forw.f_addr.len = nbp->len;
3983 f->f_file = t_open(ncp->nc_device, O_RDWR, NULL);
3984 if (f->f_file < 0) {
3985 netdir_free((void *)nap, ND_ADDRLIST);
3986 (void) endnetconfig(handle);
3987 free(f->f_un.f_forw.f_addr.buf);
3988 (void) strlcpy(ebuf, "t_open", elen);
3989 return (-1);
3990 }
3991 netdir_free((void *)nap, ND_ADDRLIST);
3992 (void) endnetconfig(handle);
3993 if (t_bind(f->f_file, NULL, NULL) < 0) {
3994 (void) strlcpy(ebuf, "t_bind", elen);
3995 free(f->f_un.f_forw.f_addr.buf);
3996 (void) t_close(f->f_file);
3997 return (-1);
3998 }
3999 return (0);
4000 }
4001
4002 static int
4003 amiloghost(void)
4004 {
4005 struct nd_hostserv hs;
4006 struct netconfig *ncp;
4007 struct nd_addrlist *nap;
4008 struct netbuf *nbp;
4009 int i, fd;
4010 void *handle;
4011 char *uap;
4012 struct t_bind bind, *bound;
4013 pthread_t mythreadno;
4014
4015 if (Debug) {
4016 mythreadno = pthread_self();
4017 }
4018
4019 /*
4020 * we need to know if we are running on the loghost. This is
4021 * checked by binding to the address associated with "loghost"
4022 * and "syslogd" service over the connectionless transport
4023 */
4024 hs.h_host = "loghost";
4025 hs.h_serv = "syslog";
4026
4027 if ((handle = setnetconfig()) == NULL) {
4028 return (0);
4029 }
4030
4031 while ((ncp = getnetconfig(handle)) != NULL) {
4032 if (ncp->nc_semantics != NC_TPI_CLTS) {
4033 continue;
4034 }
4035
4036 if (netdir_getbyname(ncp, &hs, &nap) != 0) {
4037 continue;
4038 }
4039
4040 if (nap == NULL) {
4041 continue;
4042 }
4043
4044 nbp = nap->n_addrs;
4045
4046 for (i = 0; i < nap->n_cnt; i++) {
4047 if ((uap = taddr2uaddr(ncp, nbp)) != (char *)NULL) {
4048 DPRINT2(1, "amiloghost(%u): testing %s\n",
4049 mythreadno, uap);
4050 }
4051
4052 free(uap);
4053
4054 fd = t_open(ncp->nc_device, O_RDWR, NULL);
4055
4056 if (fd < 0) {
4057 netdir_free((void *)nap, ND_ADDRLIST);
4058 (void) endnetconfig(handle);
4059 return (0);
4060 }
4061
4062 /*LINTED*/
4063 bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
4064 bind.addr = *nbp;
4065 bind.qlen = 0;
4066
4067 if (t_bind(fd, &bind, bound) == 0) {
4068 (void) t_close(fd);
4069 (void) t_free((char *)bound, T_BIND);
4070 netdir_free((void *)nap, ND_ADDRLIST);
4071 (void) endnetconfig(handle);
4072 return (1);
4073 } else {
4074 (void) t_close(fd);
4075 (void) t_free((char *)bound, T_BIND);
4076 }
4077
4078 nbp++;
4079 }
4080
4081 netdir_free((void *)nap, ND_ADDRLIST);
4082 }
4083
4084 (void) endnetconfig(handle);
4085 return (0);
4086 }
4087
4088 int
4089 same_addr(struct netbuf *na, struct netbuf *nb)
4090 {
4091 char *a, *b;
4092 size_t n;
4093
4094 assert(na->buf != NULL && nb->buf != NULL);
4095
4096 if (na->len != nb->len) {
4097 return (0);
4098 }
4099
4100 a = na->buf;
4101 b = nb->buf;
4102 n = nb->len;
4103
4104 while (n-- > 0) {
4105 if (*a++ != *b++) {
4106 return (0);
4107 }
4108 }
4109
4110 return (1);
4111 }
4112
4113 /*
4114 * allocates a new message structure, initializes it
4115 * and returns a pointer to it
4116 */
4117 static log_message_t *
4118 new_msg(void)
4119 {
4120 log_message_t *lm;
4121 pthread_t mythreadno;
4122
4123 if (Debug) {
4124 mythreadno = pthread_self();
4125 }
4126
4127 if ((lm = malloc(sizeof (log_message_t))) == NULL)
4128 return ((log_message_t *)NULL);
4129
4130 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lm))
4131
4132 if (pthread_mutex_init(&lm->msg_mutex, NULL) != 0)
4133 return ((log_message_t *)NULL);
4134 lm->refcnt = 0;
4135 lm->pri = 0;
4136 lm->flags = 0;
4137 lm->hlp = NULL;
4138 lm->msg[0] = '\0';
4139 lm->ptr = NULL;
4140
4141 DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno, (void *)lm);
4142 return (lm);
4143 }
4144
4145 /*
4146 * frees a message structure - should only be called if
4147 * the refcount is 0
4148 */
4149 static void
4150 free_msg(log_message_t *lm)
4151 {
4152 pthread_t mythreadno;
4153
4154 if (Debug) {
4155 mythreadno = pthread_self();
4156 }
4157
4158 assert(lm != NULL && lm->refcnt == 0);
4159 if (lm->hlp != NULL)
4160 freehl(lm->hlp);
4161 DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno, (void *)lm);
4162 free(lm);
4163 }
4164
4165 /*
4166 * Make sure that the message makes sense in the current locale, and
4167 * does not contain stray control characters.
4168 */
4169 static void
4170 filter_string(char *mbstr, char *filtered, size_t max)
4171 {
4172 size_t cs = 0;
4173 size_t mb_cur_max;
4174 unsigned char *p = (unsigned char *)mbstr;
4175 pthread_t mythreadno = 0;
4176
4177 if (Debug) {
4178 mythreadno = pthread_self();
4179 }
4180
4181 assert(mbstr != NULL && filtered != NULL);
4182
4183 /*
4184 * Since the access to MB_CUR_MAX is expensive (because
4185 * MB_CUR_MAX lives in a global area), it should be
4186 * restrained for the better performance.
4187 */
4188 mb_cur_max = (size_t)MB_CUR_MAX;
4189 if (mb_cur_max > 1) {
4190 /* multibyte locale */
4191 int mlen;
4192 wchar_t wc;
4193
4194 while (*p != '\0') {
4195 if ((mlen = mbtowc(&wc, (char *)p,
4196 mb_cur_max)) == -1) {
4197 /*
4198 * Invalid byte sequence found.
4199 *
4200 * try to print one byte
4201 * in ASCII format.
4202 */
4203 DPRINT2(9, "filter_string(%u): Invalid "
4204 "MB sequence: %ld\n", mythreadno,
4205 wc);
4206
4207 if (!putctrlc(*p++, &filtered, &cs, max)) {
4208 /* not enough buffer */
4209 goto end;
4210 } else {
4211 continue;
4212 }
4213 } else {
4214 /*
4215 * Since *p is not a null byte here,
4216 * mbtowc should have never returned 0.
4217 *
4218 * A valid wide character found.
4219 */
4220
4221 if (wc != L'\t' && iswcntrl(wc)) {
4222 /*
4223 * non-tab, non-newline, and
4224 * control character found.
4225 *
4226 * try to print this wide character
4227 * in ASCII-format.
4228 */
4229 char *q = filtered;
4230
4231 DPRINT2(9, "filter_string(%u): MB"
4232 " control character: %ld\n",
4233 mythreadno, wc);
4234
4235 while (mlen--) {
4236 if (!putctrlc(*p++, &filtered,
4237 &cs, max)) {
4238 /*
4239 * not enough buffer in
4240 * filtered
4241 *
4242 * cancel already
4243 * stored bytes in
4244 * filtered for this
4245 * wide character.
4246 */
4247 filtered = q;
4248 goto end;
4249 }
4250 }
4251 continue;
4252 } else {
4253 /*
4254 * tab, newline, or non-control
4255 * character found.
4256 */
4257 if (cs + mlen < max) {
4258 /* enough buffer */
4259 cs += mlen;
4260 while (mlen--) {
4261 *filtered++ = *p++;
4262 }
4263 continue;
4264 } else {
4265 /* not enough buffer */
4266 goto end;
4267 }
4268 }
4269 }
4270 }
4271 } else {
4272 /* singlebyte locale */
4273
4274 while (*p != '\0') {
4275 if (*p != '\t' && iscntrl(*p)) {
4276 /*
4277 * non-tab, non-newline,
4278 * and control character found.
4279 *
4280 * try to print this singlebyte character
4281 * in ASCII format.
4282 */
4283 DPRINT2(9, "filter_string(%u): control "
4284 "character: %d\n", mythreadno, *p);
4285
4286 if (!putctrlc(*p++, &filtered, &cs, max)) {
4287 /* not enough buffer */
4288 goto end;
4289 } else {
4290 continue;
4291 }
4292 } else if (*p != '\t' && !isprint(*p)) {
4293 /*
4294 * non-tab and non printable character found
4295 * this check is required for the C locale
4296 */
4297 DPRINT2(9, "filter_string(%u): non-printable "
4298 "character: %d\n", mythreadno, *p);
4299 if (!putctrlc(*p++, &filtered, &cs, max)) {
4300 /* not enough buffer */
4301 goto end;
4302 } else {
4303 continue;
4304 }
4305 } else {
4306 /*
4307 * tab, newline, non-control character, or
4308 * printable found.
4309 */
4310 if (cs + 1 < max) {
4311 *filtered++ = *p++;
4312 cs++;
4313 continue;
4314 } else {
4315 /* not enough buffer */
4316 goto end;
4317 }
4318 }
4319 }
4320 }
4321
4322 end:
4323 *filtered = '\0';
4324
4325 if (cs >= 2 &&
4326 filtered[-2] == '\\' && filtered[-1] == 'n') {
4327 filtered[-2] = '\0';
4328 }
4329 }
4330
4331 static char *
4332 alloc_stacks(int numstacks)
4333 {
4334 size_t pagesize, mapsize;
4335 char *stack_top;
4336 char *addr;
4337 int i;
4338
4339 pagesize = (size_t)sysconf(_SC_PAGESIZE);
4340 /*
4341 * stacksize and redzonesize are global so threads
4342 * can be created elsewhere and refer to the sizes
4343 */
4344 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
4345 DEFAULT_STACKSIZE, pagesize);
4346 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
4347
4348 /*
4349 * allocate an additional "redzonesize" chunk in addition
4350 * to what we require, so we can create a redzone at the
4351 * bottom of the last stack as well.
4352 */
4353 mapsize = redzonesize + numstacks * (stacksize + redzonesize);
4354 stack_top = mmap(NULL, mapsize, PROT_READ|PROT_WRITE,
4355 MAP_PRIVATE|MAP_ANON, -1, 0);
4356 if (stack_top == MAP_FAILED)
4357 return (NULL);
4358
4359 addr = stack_top;
4360 /*
4361 * this loop is intentionally <= instead of <, so we can
4362 * protect the redzone at the bottom of the last stack
4363 */
4364 for (i = 0; i <= numstacks; i++) {
4365 (void) mprotect(addr, redzonesize, PROT_NONE);
4366 addr += stacksize + redzonesize;
4367 }
4368 return ((char *)(stack_top + redzonesize));
4369 }
4370
4371 static void
4372 dealloc_stacks(int numstacks)
4373 {
4374 size_t pagesize, mapsize;
4375
4376 pagesize = (size_t)sysconf(_SC_PAGESIZE);
4377
4378 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
4379 DEFAULT_STACKSIZE, pagesize);
4380
4381 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
4382
4383 mapsize = redzonesize + numstacks * (stacksize + redzonesize);
4384 (void) munmap(cstack_ptr - mapsize, mapsize);
4385 }
4386
4387 static void
4388 filed_destroy(struct filed *f)
4389 {
4390 (void) dataq_destroy(&f->f_queue);
4391 (void) pthread_mutex_destroy(&f->filed_mutex);
4392 }
4393
4394 static void
4395 close_door(void)
4396 {
4397 pthread_t mythreadno;
4398
4399 if (Debug) {
4400 mythreadno = pthread_self();
4401 }
4402
4403 (void) fdetach(DoorFileName);
4404
4405 DPRINT2(5, "close_door(%u): detached server() from %s\n",
4406 mythreadno, DoorFileName);
4407 }
4408
4409 static void
4410 delete_doorfiles(void)
4411 {
4412 pthread_t mythreadno;
4413 struct stat sb;
4414 int err;
4415 char line[MAXLINE+1];
4416
4417 if (Debug) {
4418 mythreadno = pthread_self();
4419 }
4420
4421
4422 if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4423 if (unlink(DoorFileName) < 0) {
4424 err = errno;
4425 (void) snprintf(line, sizeof (line),
4426 "unlink() of %s failed - fatal", DoorFileName);
4427 errno = err;
4428 logerror(line);
4429 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4430 "errno=%d\n", mythreadno, line, err);
4431 exit(1);
4432 }
4433
4434 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4435 mythreadno, DoorFileName);
4436 }
4437
4438 if (strcmp(DoorFileName, DOORFILE) == 0) {
4439 if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4440 if (unlink(OLD_DOORFILE) < 0) {
4441 err = errno;
4442 (void) snprintf(line, sizeof (line),
4443 "unlink() of %s failed", OLD_DOORFILE);
4444 DPRINT2(5, "delete_doorfiles(%u): %s\n",
4445 mythreadno, line);
4446
4447 if (err != EROFS) {
4448 errno = err;
4449 (void) strlcat(line, " - fatal",
4450 sizeof (line));
4451 logerror(line);
4452 DPRINT3(1, "delete_doorfiles(%u): "
4453 "error: %s, errno=%d\n",
4454 mythreadno, line, err);
4455 exit(1);
4456 }
4457
4458 DPRINT1(5, "delete_doorfiles(%u): unlink() "
4459 "failure OK on RO file system\n",
4460 mythreadno);
4461 }
4462
4463 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4464 mythreadno, OLD_DOORFILE);
4465 }
4466 }
4467
4468 if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4469 if (unlink(PidFileName) < 0) {
4470 err = errno;
4471 (void) snprintf(line, sizeof (line),
4472 "unlink() of %s failed - fatal", PidFileName);
4473 errno = err;
4474 logerror(line);
4475 DPRINT3(1, "delete_doorfiles(%u): error: %s, "
4476 "errno=%d\n", mythreadno, line, err);
4477 exit(1);
4478 }
4479
4480 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno,
4481 PidFileName);
4482 }
4483
4484 if (strcmp(PidFileName, PIDFILE) == 0) {
4485 if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
4486 if (unlink(OLD_PIDFILE) < 0) {
4487 err = errno;
4488 (void) snprintf(line, sizeof (line),
4489 "unlink() of %s failed", OLD_PIDFILE);
4490 DPRINT2(5, "delete_doorfiles(%u): %s, \n",
4491 mythreadno, line);
4492
4493 if (err != EROFS) {
4494 errno = err;
4495 (void) strlcat(line, " - fatal",
4496 sizeof (line));
4497 logerror(line);
4498 DPRINT3(1, "delete_doorfiles(%u): "
4499 "error: %s, errno=%d\n",
4500 mythreadno, line, err);
4501 exit(1);
4502 }
4503
4504 DPRINT1(5, "delete_doorfiles(%u): unlink "
4505 "failure OK on RO file system\n",
4506 mythreadno);
4507 }
4508
4509 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
4510 mythreadno, OLD_PIDFILE);
4511 }
4512 }
4513
4514 if (DoorFd != -1) {
4515 (void) door_revoke(DoorFd);
4516 }
4517
4518 DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n",
4519 mythreadno, DoorFd);
4520 }
4521
4522
4523 /*ARGSUSED*/
4524 static void
4525 signull(int sig, siginfo_t *sip, void *utp)
4526 {
4527 DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n",
4528 pthread_self());
4529 /*
4530 * Do nothing, as this is a place-holder used in conjunction with
4531 * sigaction()/sigwait() to ensure that the proper disposition is
4532 * given to the signals we handle in main().
4533 */
4534 }
4535
4536 /*
4537 * putctrlc returns zero, if failed due to not enough buffer.
4538 * Otherwise, putctrlc returns non-zero.
4539 *
4540 * c: a byte to print in ASCII format
4541 * **buf: a pointer to the pointer to the output buffer.
4542 * *cl: current length of characters in the output buffer
4543 * max: maximum length of the buffer
4544 */
4545
4546 static int
4547 putctrlc(int c, char **buf, size_t *cl, size_t max)
4548 {
4549 char *p = *buf;
4550
4551 if (c == '\n') {
4552 if (*cl + 2 < max) {
4553 *p++ = '\\';
4554 *p++ = 'n';
4555 *cl += 2;
4556 *buf = p;
4557 return (2);
4558 } else {
4559 return (0);
4560 }
4561 } else if (c < 0200) {
4562 /* ascii control character */
4563 if (*cl + 2 < max) {
4564 *p++ = '^';
4565 *p++ = c ^ 0100;
4566 *cl += 2;
4567 *buf = p;
4568 return (2);
4569 } else {
4570 return (0);
4571 }
4572 } else {
4573 if (*cl + 4 < max) {
4574 *p++ = '\\';
4575 *p++ = ((c >> 6) & 07) + '0';
4576 *p++ = ((c >> 3) & 07) + '0';
4577 *p++ = (c & 07) + '0';
4578 *cl += 4;
4579 *buf = p;
4580 return (4);
4581 } else {
4582 return (0);
4583 }
4584 }
4585 }
4586
4587 /*
4588 * findnl_bkwd:
4589 * Scans each character in buf until it finds the last newline in buf,
4590 * or the scanned character becomes the last COMPLETE character in buf.
4591 * Returns the number of scanned bytes.
4592 *
4593 * buf - pointer to a buffer containing the message string
4594 * len - the length of the buffer
4595 */
4596 size_t
4597 findnl_bkwd(const char *buf, const size_t len)
4598 {
4599 const char *p;
4600 size_t mb_cur_max;
4601 pthread_t mythreadno;
4602
4603 if (Debug) {
4604 mythreadno = pthread_self();
4605 }
4606
4607 if (len == 0) {
4608 return (0);
4609 }
4610
4611 mb_cur_max = MB_CUR_MAX;
4612
4613 if (mb_cur_max == 1) {
4614 /* single-byte locale */
4615 for (p = buf + len - 1; p != buf; p--) {
4616 if (*p == '\n') {
4617 return ((size_t)(p - buf));
4618 }
4619 }
4620 return ((size_t)len);
4621 } else {
4622 /* multi-byte locale */
4623 int mlen;
4624 const char *nl;
4625 size_t rem;
4626
4627 p = buf;
4628 nl = NULL;
4629 for (rem = len; rem >= mb_cur_max; ) {
4630 mlen = mblen(p, mb_cur_max);
4631 if (mlen == -1) {
4632 /*
4633 * Invalid character found.
4634 */
4635 DPRINT1(9, "findnl_bkwd(%u): Invalid MB "
4636 "sequence\n", mythreadno);
4637 /*
4638 * handle as a single byte character.
4639 */
4640 p++;
4641 rem--;
4642 } else {
4643 /*
4644 * It's guaranteed that *p points to
4645 * the 1st byte of a multibyte character.
4646 */
4647 if (*p == '\n') {
4648 nl = p;
4649 }
4650 p += mlen;
4651 rem -= mlen;
4652 }
4653 }
4654 if (nl) {
4655 return ((size_t)(nl - buf));
4656 }
4657 /*
4658 * no newline nor null byte found.
4659 * Also it's guaranteed that *p points to
4660 * the 1st byte of a (multibyte) character
4661 * at this point.
4662 */
4663 return (len - rem);
4664 }
4665 }
4666
4667 /*
4668 * copynl_frwd:
4669 * Scans each character in buf and copies the scanned character to obuf
4670 * until it finds a null byte or a newline, or
4671 * the number of the remaining bytes in obuf gets to exceed obuflen
4672 * if copying the scanned character to obuf.
4673 * Returns the number of scanned bytes.
4674 *
4675 * obuf - buffer to be copied the scanned character
4676 * obuflen - the size of obuf
4677 * buf - pointer to a buffer containing the message string
4678 * len - the length of the buffer
4679 */
4680 size_t
4681 copynl_frwd(char *obuf, const size_t obuflen,
4682 const char *buf, const size_t len)
4683 {
4684 const char *p;
4685 char *q = obuf;
4686 size_t olen = 0;
4687 size_t mb_cur_max;
4688 pthread_t mythreadno;
4689
4690 if (Debug) {
4691 mythreadno = pthread_self();
4692 }
4693
4694 if (len == 0) {
4695 return (0);
4696 }
4697
4698 mb_cur_max = MB_CUR_MAX;
4699
4700 if (mb_cur_max == 1) {
4701 /* single-byte locale */
4702 for (p = buf; *p; ) {
4703 if (obuflen > olen + 1) {
4704 if (*p != '\n') {
4705 *q++ = *p++;
4706 olen++;
4707 } else {
4708 *q = '\0';
4709 return ((size_t)(p - buf));
4710 }
4711 } else {
4712 *q = '\0';
4713 return ((size_t)(p - buf));
4714 }
4715 }
4716 *q = '\0';
4717 return ((size_t)(p - buf));
4718 } else {
4719 /* multi-byte locale */
4720 int mlen;
4721
4722 for (p = buf; *p; ) {
4723 mlen = mblen(p, mb_cur_max);
4724 if (mlen == -1) {
4725 /*
4726 * Invalid character found.
4727 */
4728 DPRINT1(9, "copynl_frwd(%u): Invalid MB "
4729 "sequence\n", mythreadno);
4730 /*
4731 * handle as a single byte character.
4732 */
4733 if (obuflen > olen + 1) {
4734 *q++ = *p++;
4735 olen++;
4736 } else {
4737 *q = '\0';
4738 return ((size_t)(p - buf));
4739 }
4740 } else {
4741 /*
4742 * It's guaranteed that *p points to
4743 * the 1st byte of a multibyte character.
4744 */
4745 if (*p == '\n') {
4746 *q = '\0';
4747 return ((size_t)(p - buf));
4748 }
4749 if (obuflen > olen + mlen) {
4750 int n;
4751 for (n = 0; n < mlen; n++) {
4752 *q++ = *p++;
4753 }
4754 olen += mlen;
4755 } else {
4756 *q = '\0';
4757 return ((size_t)(p - buf));
4758 }
4759 }
4760 }
4761 /*
4762 * no newline nor null byte found.
4763 * Also it's guaranteed that *p points to
4764 * the 1st byte of a (multibyte) character
4765 * at this point.
4766 */
4767 *q = '\0';
4768 return ((size_t)(p - buf));
4769 }
4770 }
4771
4772 /*
4773 * copy_frwd:
4774 * Scans each character in buf and copies the scanned character to obuf
4775 * until the number of the remaining bytes in obuf gets to exceed obuflen
4776 * if copying the scanned character to obuf.
4777 * Returns the number of scanned (copied) bytes.
4778 *
4779 * obuf - buffer to be copied the scanned character
4780 * obuflen - the size of obuf
4781 * buf - pointer to a buffer containing the message string
4782 * len - the length of the buffer
4783 */
4784 size_t
4785 copy_frwd(char *obuf, const size_t obuflen,
4786 const char *buf, const size_t len)
4787 {
4788 const char *p;
4789 char *q = obuf;
4790 size_t olen = 0;
4791 size_t mb_cur_max;
4792 pthread_t mythreadno;
4793
4794 if (Debug) {
4795 mythreadno = pthread_self();
4796 }
4797
4798 if (len == 0) {
4799 return (0);
4800 }
4801
4802 mb_cur_max = MB_CUR_MAX;
4803
4804 if (mb_cur_max == 1) {
4805 /* single-byte locale */
4806 if (obuflen > len) {
4807 (void) memcpy(obuf, buf, len);
4808 obuf[len] = '\0';
4809 return ((size_t)len);
4810 } else {
4811 (void) memcpy(obuf, buf, obuflen - 1);
4812 obuf[obuflen - 1] = '\0';
4813 return (obuflen - 1);
4814 }
4815 } else {
4816 /* multi-byte locale */
4817 int mlen;
4818
4819 for (p = buf; *p; ) {
4820 mlen = mblen(p, mb_cur_max);
4821 if (mlen == -1) {
4822 /*
4823 * Invalid character found.
4824 */
4825 DPRINT1(9, "copy_frwd(%u): Invalid MB "
4826 "sequence\n", mythreadno);
4827 /*
4828 * handle as a single byte character.
4829 */
4830 if (obuflen > olen + 1) {
4831 *q++ = *p++;
4832 olen++;
4833 } else {
4834 *q = '\0';
4835 return ((size_t)(p - buf));
4836 }
4837 } else {
4838 if (obuflen > olen + mlen) {
4839 int n;
4840 for (n = 0; n < mlen; n++) {
4841 *q++ = *p++;
4842 }
4843 olen += mlen;
4844 } else {
4845 *q = '\0';
4846 return ((size_t)(p - buf));
4847 }
4848 }
4849 }
4850 *q = '\0';
4851 return ((size_t)(p - buf));
4852 }
4853 }
4854
4855 /*
4856 * properties:
4857 * Get properties from SMF framework.
4858 */
4859 static void
4860 properties(void)
4861 {
4862 scf_simple_prop_t *prop;
4863 uint8_t *bool;
4864
4865 if ((prop = scf_simple_prop_get(NULL, NULL, "config",
4866 "log_from_remote")) != NULL) {
4867 if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
4868 if (*bool == 0)
4869 turnoff = 1; /* log_from_remote = false */
4870 else
4871 turnoff = 0; /* log_from_remote = true */
4872 }
4873 scf_simple_prop_free(prop);
4874 DPRINT1(1, "properties: setting turnoff to %s\n",
4875 turnoff ? "true" : "false");
4876 }
4877 }
4878
4879 /*
4880 * close all the input devices.
4881 */
4882 static void
4883 shutdown_input(void)
4884 {
4885 int cnt;
4886
4887 shutting_down = 1;
4888
4889 for (cnt = 0; cnt < Ninputs; cnt++) {
4890 (void) t_close(Nfd[cnt].fd);
4891 }
4892
4893 (void) close(Pfd.fd);
4894 }
4895
4896 /*
4897 * This is for the one thread that dedicates to resolve the
4898 * hostname. This will get the messages from net_poll() through
4899 * hnlq, and resolve the hostname, and push the messages back
4900 * into the inputq.
4901 */
4902 /*ARGSUSED*/
4903 static void *
4904 hostname_lookup(void *ap)
4905 {
4906 char *uap;
4907 log_message_t *mp;
4908 host_info_t *hip;
4909 char failsafe_addr[SYS_NMLN + 1];
4910 pthread_t mythreadno;
4911
4912 if (Debug) {
4913 mythreadno = pthread_self();
4914 }
4915
4916 DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n",
4917 mythreadno);
4918
4919 for (;;) {
4920 (void) dataq_dequeue(&hnlq, (void **)&mp, 0);
4921
4922 DPRINT3(5, "hostname_lookup(%u): dequeued msg %p"
4923 " from queue %p\n", mythreadno, (void *)mp,
4924 (void *)&hnlq);
4925
4926 hip = (host_info_t *)mp->ptr;
4927 if ((uap = taddr2uaddr(hip->ncp, &hip->addr)) != NULL) {
4928 (void) strlcpy(failsafe_addr, uap, SYS_NMLN);
4929 free(uap);
4930 } else {
4931 (void) strlcpy(failsafe_addr, "<unknown>", SYS_NMLN);
4932 }
4933
4934 mp->hlp = cvthname(&hip->addr, hip->ncp, failsafe_addr);
4935
4936 if (mp->hlp == NULL) {
4937 mp->hlp = &NullHostName;
4938 }
4939
4940 free(hip->addr.buf);
4941 free(hip);
4942 mp->ptr = NULL;
4943
4944 if (dataq_enqueue(&inputq, (void *)mp) == -1) {
4945 MALLOC_FAIL("dropping message from remote");
4946 free_msg(mp);
4947 continue;
4948 }
4949
4950 DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue "
4951 "%p\n", mythreadno, (void *)mp, (void *)&inputq);
4952 }
4953
4954 /*NOTREACHED*/
4955 return (NULL);
4956 }
4957
4958 /*
4959 * Does all HUP(re-configuration) process.
4960 */
4961 static void
4962 reconfigure()
4963 {
4964 int cnt, loop, drops;
4965 int really_stuck;
4966 int console_stuck = 0;
4967 struct filed *f;
4968 char buf[LINE_MAX];
4969 struct utsname up;
4970 char cbuf[30];
4971 time_t tim;
4972 pthread_t mythreadno;
4973
4974 if (Debug) {
4975 mythreadno = pthread_self();
4976 }
4977
4978 /* If we get here then we must need to regen */
4979 flushmsg(0);
4980
4981 if (logmymsg(LOG_SYSLOG|LOG_INFO, "syslogd: configuration restart",
4982 ADDDATE, 0) == -1) {
4983 MALLOC_FAIL("dropping message");
4984 }
4985
4986 /*
4987 * make sure the logmsg thread is not in the waiting state.
4988 * Otherwise, changing hup_state will prevent the logmsg thread
4989 * getting out from the waiting loop.
4990 */
4991
4992 if (Debug) {
4993 tim = time(NULL);
4994 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()"
4995 " moving to the safe place\n",
4996 mythreadno, ctime_r(&tim, cbuf)+4);
4997 }
4998
4999 for (loop = 0; loop < LOOP_MAX; loop++) {
5000 /* we don't need the mutex to read */
5001 if (hup_state == HUP_ACCEPTABLE)
5002 break;
5003 (void) sleep(1);
5004 }
5005 if (hup_state != HUP_ACCEPTABLE) {
5006 goto thread_stuck;
5007 }
5008
5009 if (Debug) {
5010 tim = time(NULL);
5011 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n",
5012 mythreadno, ctime_r(&tim, cbuf)+4);
5013 }
5014
5015 /*
5016 * Prevent logging until we are truly done processing the HUP
5017 */
5018 (void) pthread_mutex_lock(&hup_lock);
5019 hup_state = HUP_INPROGRESS;
5020 (void) pthread_mutex_unlock(&hup_lock);
5021
5022 /*
5023 * We will be going into a critical state. Any error message
5024 * from syslogd needs to be dumped to the console by default
5025 * immediately. Also, those error messages are quened in a temporary
5026 * queue to be able to post into the regular stream later.
5027 */
5028 disable_errorlog();
5029
5030 if (Debug) {
5031 tim = time(NULL);
5032 DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n",
5033 mythreadno, ctime_r(&tim, cbuf)+4);
5034 }
5035
5036 /* stop configured threads */
5037 if (shutdown_msg() == -1) {
5038 /*
5039 * No memory, message will be dumped to the console.
5040 */
5041 MALLOC_FAIL("unable to restart syslogd");
5042 goto out;
5043 }
5044
5045 /* make sure logmsg() is in suspended state */
5046 for (loop = 0; loop < LOOP_INTERVAL; loop++) {
5047 if (hup_state & HUP_LOGMSG_SUSPENDED)
5048 break;
5049 (void) sleep(1);
5050 }
5051
5052 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
5053 if (Debug) {
5054 tim = time(NULL);
5055 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not "
5056 "stop. enforcing\n",
5057 mythreadno, ctime_r(&tim, cbuf)+4);
5058 }
5059
5060 /* probably we have too long input queue, or really stuck */
5061 (void) pthread_mutex_lock(&hup_lock);
5062 hup_state |= HUP_SUSP_LOGMSG_REQD;
5063 (void) pthread_mutex_unlock(&hup_lock);
5064
5065 for (loop = 0; loop < LOOP_MAX; loop++) {
5066 if (hup_state & HUP_LOGMSG_SUSPENDED)
5067 break;
5068 (void) sleep(1);
5069 }
5070 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
5071 if (Debug) {
5072 tim = time(NULL);
5073 DPRINT2(3, "reconfigure(%u): %.15s: logmsg()"
5074 " does not stop. give up\n",
5075 mythreadno, ctime_r(&tim, cbuf)+4);
5076 }
5077 logerror("could not suspend logmsg - fatal");
5078 goto thread_stuck;
5079 }
5080 }
5081
5082 if (Debug) {
5083 tim = time(NULL);
5084 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n",
5085 mythreadno, ctime_r(&tim, cbuf)+4);
5086 }
5087
5088 /*
5089 * Will wait for LOOP_MAX secs with watching queue lengths for the
5090 * each logger threads. If they have backlogs, and no change in the
5091 * length of queue found in 30 seconds, those will be counted as
5092 * "really stuck".
5093 * If all running logger threads become "really stuck" state, there
5094 * should be no worth waiting for them to quit.
5095 * In that case, we will go ahead and close out file descriptors to
5096 * have them pull out from hanging system call, and give them a last
5097 * chance(LOOP_INTERVAL sec) to quit.
5098 */
5099
5100 if (Debug) {
5101 tim = time(NULL);
5102 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be"
5103 " shutdown\n", mythreadno, ctime_r(&tim, cbuf)+4);
5104 }
5105
5106 cnt = 0;
5107 really_stuck = 0;
5108 while (cnt < (LOOP_MAX/LOOP_INTERVAL) &&
5109 conf_threads > really_stuck) {
5110
5111 /* save initial queue count */
5112 for (f = Files; f < &Files[nlogs]; f++) {
5113 f->f_prev_queue_count = (f->f_type == F_UNUSED) ?
5114 -1 : f->f_queue_count;
5115 }
5116
5117 for (loop = 0; loop < LOOP_INTERVAL; loop++) {
5118 if (conf_threads == 0)
5119 break;
5120 (void) sleep(1);
5121 }
5122
5123 if (conf_threads == 0)
5124 break;
5125
5126 if (Debug) {
5127 tim = time(NULL);
5128 DPRINT3(3, "reconfigure(%u): %.15s: "
5129 "%d threads are still alive.\n",
5130 mythreadno, ctime_r(&tim, cbuf)+4,
5131 conf_threads);
5132 }
5133
5134 really_stuck = 0;
5135 for (f = Files; f < &Files[nlogs]; f++) {
5136 if (f->f_type == F_UNUSED) {
5137 f->f_prev_queue_count = -1;
5138 continue;
5139 }
5140 if (f->f_prev_queue_count == f->f_queue_count) {
5141 really_stuck++;
5142 f->f_prev_queue_count = 1;
5143 DPRINT2(3, "reconfigure(%u): "
5144 "tid=%d is really stuck.\n",
5145 mythreadno, f->f_thread);
5146 } else {
5147 f->f_prev_queue_count = 0;
5148 DPRINT2(3, "reconfigure(%u): "
5149 "tid=%d is still active.\n",
5150 mythreadno, f->f_thread);
5151 }
5152 }
5153 /*
5154 * Here we have one of following values in the
5155 * f_prev_queue_count:
5156 * 0: logger thread is still actively working.
5157 * 1: logger thread is really stuck.
5158 * -1: logger thread has already died.
5159 */
5160
5161 cnt++;
5162 }
5163
5164 if (Debug) {
5165 tim = time(NULL);
5166 DPRINT2(3, "reconfigure(%u): %.15s:"
5167 " complete awaiting logit()\n",
5168 mythreadno, ctime_r(&tim, cbuf)+4);
5169 DPRINT3(3, "reconfigure(%u): %d threads alive."
5170 " %d threads stuck\n",
5171 mythreadno, conf_threads, really_stuck);
5172 }
5173
5174 /*
5175 * Still running? If so, mark it as UNUSED, and close
5176 * the fd so that logger threads can bail out from the loop.
5177 */
5178 drops = 0;
5179 if (conf_threads) {
5180 for (f = Files; f < &Files[nlogs]; f++) {
5181 if (f->f_type == F_CONSOLE &&
5182 f->f_prev_queue_count == 1) {
5183 /* console is really stuck */
5184 console_stuck = 1;
5185 }
5186 if (f->f_type == F_USERS || f->f_type == F_WALL ||
5187 f->f_type == F_UNUSED)
5188 continue;
5189 cnt = f->f_queue_count;
5190 drops += (cnt > 0) ? cnt - 1: 0;
5191 f->f_type = F_UNUSED;
5192
5193 if (f->f_orig_type == F_FORW)
5194 (void) t_close(f->f_file);
5195 else
5196 (void) close(f->f_file);
5197 }
5198
5199 if (Debug) {
5200 tim = time(NULL);
5201 DPRINT1(3, "reconfigure(%u): terminating logit()\n",
5202 mythreadno);
5203 }
5204
5205 /* last chance to exit */
5206 for (loop = 0; loop < LOOP_MAX; loop++) {
5207 if (conf_threads == 0)
5208 break;
5209 (void) sleep(1);
5210 }
5211
5212 if (Debug) {
5213 tim = time(NULL);
5214 DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n",
5215 mythreadno, ctime_r(&tim, cbuf)+4,
5216 conf_threads);
5217 }
5218 }
5219
5220 if (conf_threads == 0 && drops) {
5221 errno = 0;
5222 logerror("Could not completely output pending messages"
5223 " while preparing re-configuration");
5224 logerror("discarded %d messages and restart configuration.",
5225 drops);
5226 if (Debug) {
5227 tim = time(NULL);
5228 DPRINT3(3, "reconfigure(%u): %.15s: "
5229 "discarded %d messages\n",
5230 mythreadno, ctime_r(&tim, cbuf)+4, drops);
5231 }
5232 }
5233
5234 /*
5235 * If all threads still haven't exited
5236 * something is stuck or hosed. We just
5237 * have no option but to exit.
5238 */
5239 if (conf_threads) {
5240 thread_stuck:
5241 if (Debug) {
5242 tim = time(NULL);
5243 DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n",
5244 mythreadno, ctime_r(&tim, cbuf)+4);
5245 }
5246
5247 shutdown_input();
5248 delete_doorfiles();
5249 (void) uname(&up);
5250
5251 (void) snprintf(buf, sizeof (buf),
5252 "syslogd(%s): some logger thread(s) "
5253 "are stuck%s; syslogd is shutting down.",
5254 up.nodename,
5255 console_stuck ? " (including the console)" : "");
5256
5257 if (console_stuck) {
5258 FILE *m = popen(MAILCMD, "w");
5259
5260 if (m != NULL) {
5261 (void) fprintf(m, "%s\n", buf);
5262 (void) pclose(m);
5263 }
5264 }
5265
5266 disable_errorlog();
5267 logerror(buf);
5268 exit(1);
5269 }
5270
5271 /* Free up some resources */
5272 if (Files != (struct filed *)&fallback) {
5273 for (f = Files; f < &Files[nlogs]; f++) {
5274 (void) pthread_join(f->f_thread, NULL);
5275 filed_destroy(f);
5276 }
5277 free(Files);
5278 }
5279
5280 dealloc_stacks(nlogs);
5281
5282 if (Debug) {
5283 tim = time(NULL);
5284 DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n",
5285 mythreadno, ctime_r(&tim, cbuf)+4);
5286 }
5287
5288 hnc_init(1); /* purge hostname cache */
5289 conf_init(); /* start reconfigure */
5290
5291 out:;
5292 /* Now should be ready to dispatch error messages from syslogd. */
5293 enable_errorlog();
5294
5295 /* Wake up the log thread */
5296
5297 if (Debug) {
5298 tim = time(NULL);
5299 DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n",
5300 mythreadno, ctime_r(&tim, cbuf)+4);
5301 }
5302
5303 (void) pthread_mutex_lock(&hup_lock);
5304 hup_state = HUP_COMPLETED;
5305 (void) pthread_cond_signal(&hup_done);
5306 (void) pthread_mutex_unlock(&hup_lock);
5307 }
5308
5309 /*
5310 * The following function implements simple hostname cache mechanism.
5311 * Host name cache is implemented through hash table bucket chaining method.
5312 * Collisions are handled by bucket chaining.
5313 *
5314 * hnc_init():
5315 * allocate and initialize the cache. If reinit is set,
5316 * invalidate all cache entries.
5317 * hnc_look():
5318 * It hashes the ipaddress gets the index and walks thru the
5319 * single linked list. if cached entry was found, it will
5320 * put in the head of the list, and return.While going through
5321 * the entries, an entry which has already expired will be invalidated.
5322 * hnc_register():
5323 * Hashes the ipaddress finds the index and puts current entry to the list.
5324 * hnc_unreg():
5325 * invalidate the cachep.
5326 */
5327
5328 static void
5329 hnc_init(int reinit)
5330 {
5331 struct hostname_cache **hpp;
5332 pthread_t mythreadno;
5333 int i;
5334
5335 if (Debug) {
5336 mythreadno = pthread_self();
5337 }
5338
5339 if (reinit) {
5340 (void) pthread_mutex_lock(&hnc_mutex);
5341
5342 for (i = 0; i < hnc_size; i++) {
5343 for (hpp = &hnc_cache[i]; *hpp != NULL; ) {
5344 hnc_unreg(hpp);
5345 }
5346 }
5347
5348 (void) pthread_mutex_unlock(&hnc_mutex);
5349 DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n",
5350 mythreadno);
5351 } else {
5352
5353 hnc_cache = calloc(hnc_size, sizeof (struct hostname_cache *));
5354
5355 if (hnc_cache == NULL) {
5356 MALLOC_FAIL("hostname cache");
5357 logerror("hostname cache disabled");
5358 return;
5359 }
5360
5361 DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry"
5362 " ttl:%d\n", mythreadno, hnc_size, hnc_ttl);
5363 }
5364 }
5365
5366 static host_list_t *
5367 hnc_lookup(struct netbuf *nbp, struct netconfig *ncp, int *hindex)
5368 {
5369 struct hostname_cache **hpp, *hp;
5370 time_t now;
5371 pthread_t mythreadno;
5372 int index;
5373
5374 if (Debug) {
5375 mythreadno = pthread_self();
5376 }
5377
5378 if (hnc_cache == NULL) {
5379 return (NULL);
5380 }
5381
5382 (void) pthread_mutex_lock(&hnc_mutex);
5383 now = time(0);
5384
5385 *hindex = index = addr_hash(nbp);
5386
5387 for (hpp = &hnc_cache[index]; (hp = *hpp) != NULL; ) {
5388 DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n",
5389 mythreadno, (void *)hp->h, (void *)hp,
5390 hp->h->hl_hosts[0]);
5391
5392 if (hp->expire < now) {
5393 DPRINT2(9, "hnc_lookup(%u): purge %p\n",
5394 mythreadno, (void *)hp);
5395 hnc_unreg(hpp);
5396 continue;
5397 }
5398
5399 if (ncp == hp->ncp && same_addr(&hp->addr, nbp)) {
5400 /*
5401 * found!
5402 * Put the entry at the top.
5403 */
5404
5405 if (hp != hnc_cache[index]) {
5406 /* unlink from active list */
5407 *hpp = (*hpp)->next;
5408 /* push it onto the top */
5409 hp->next = hnc_cache[index];
5410 hnc_cache[index] = hp;
5411 }
5412
5413 (void) pthread_mutex_lock(&hp->h->hl_mutex);
5414 hp->h->hl_refcnt++;
5415 (void) pthread_mutex_unlock(&hp->h->hl_mutex);
5416
5417 DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n",
5418 mythreadno, (void *)hp->h, (void *)hp,
5419 hp->h->hl_hosts[0]);
5420
5421 (void) pthread_mutex_unlock(&hnc_mutex);
5422 return (hp->h);
5423 }
5424
5425 hpp = &hp->next;
5426 }
5427
5428 (void) pthread_mutex_unlock(&hnc_mutex);
5429 return (NULL);
5430 }
5431
5432 static void
5433 hnc_register(struct netbuf *nbp, struct netconfig *ncp,
5434 host_list_t *h, int hindex)
5435 {
5436 struct hostname_cache **hpp, **tailp, *hp, *entry;
5437 void *addrbuf;
5438 time_t now;
5439 pthread_t mythreadno;
5440 int i;
5441
5442 if (Debug) {
5443 mythreadno = pthread_self();
5444 }
5445
5446 if (hnc_cache == NULL) {
5447 return;
5448 }
5449
5450 if ((addrbuf = malloc(nbp->len)) == NULL) {
5451 MALLOC_FAIL("pushing hostname cache");
5452 return;
5453 }
5454
5455 if ((entry = malloc(sizeof (struct hostname_cache))) == NULL) {
5456 MALLOC_FAIL("pushing hostname entry");
5457 free(addrbuf);
5458 return;
5459 }
5460
5461 (void) pthread_mutex_lock(&hnc_mutex);
5462
5463 i = 0;
5464
5465 now = time(0);
5466 /*
5467 * first go through active list, and discard the
5468 * caches which has been invalid. Count number of
5469 * non-expired buckets.
5470 */
5471
5472 for (hpp = &hnc_cache[hindex]; (hp = *hpp) != NULL; ) {
5473 tailp = hpp;
5474
5475 if (hp->expire < now) {
5476 DPRINT2(9, "hnc_register(%u): discard %p\n",
5477 mythreadno, (void *)hp);
5478 hnc_unreg(hpp);
5479 } else {
5480 i++;
5481 hpp = &hp->next;
5482 }
5483 }
5484
5485 /*
5486 * If max limit of chained hash buckets has been used up
5487 * delete the least active element in the chain.
5488 */
5489 if (i == MAX_BUCKETS) {
5490 hnc_unreg(tailp);
5491 }
5492
5493 (void) memcpy(addrbuf, nbp->buf, nbp->len);
5494 entry->addr.len = nbp->len;
5495 entry->addr.buf = addrbuf;
5496 entry->ncp = ncp;
5497 entry->h = h;
5498 entry->expire = time(NULL) + hnc_ttl;
5499
5500 /* insert it at the top */
5501 entry->next = hnc_cache[hindex];
5502 hnc_cache[hindex] = entry;
5503
5504 /*
5505 * As far as cache is valid, corresponding host_list must
5506 * also be valid. Increments the refcnt to avoid freeing
5507 * host_list.
5508 */
5509 h->hl_refcnt++;
5510 DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n",
5511 mythreadno, (void *)entry->h, (void *)entry, entry->h->hl_hosts[0]);
5512 (void) pthread_mutex_unlock(&hnc_mutex);
5513 }
5514
5515 static void
5516 hnc_unreg(struct hostname_cache **hpp)
5517 {
5518 struct hostname_cache *hp = *hpp;
5519 pthread_t mythreadno;
5520
5521 if (Debug) {
5522 mythreadno = pthread_self();
5523 }
5524
5525 DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n",
5526 mythreadno, (void *)hp->h, (void *)hp, hp->h->hl_hosts[0]);
5527 free(hp->addr.buf);
5528 freehl(hp->h);
5529
5530 /* unlink from active list */
5531 *hpp = (*hpp)->next;
5532
5533 free(hp);
5534 }
5535
5536 /*
5537 * Once this is called, error messages through logerror() will go to
5538 * the console immediately. Also, messages are queued into the tmpq
5539 * to be able to later put them into inputq.
5540 */
5541 static void
5542 disable_errorlog()
5543 {
5544 (void) dataq_init(&tmpq);
5545
5546 (void) pthread_mutex_lock(&logerror_lock);
5547 interrorlog = 0;
5548 (void) pthread_mutex_unlock(&logerror_lock);
5549 }
5550
5551 /*
5552 * Turn internal error messages to regular input stream.
5553 * All pending messages are pulled and pushed into the regular
5554 * input queue.
5555 */
5556 static void
5557 enable_errorlog()
5558 {
5559 log_message_t *mp;
5560
5561 (void) pthread_mutex_lock(&logerror_lock);
5562 interrorlog = 1;
5563 (void) pthread_mutex_unlock(&logerror_lock);
5564
5565 /*
5566 * push all the pending messages into inputq.
5567 */
5568 while (dataq_dequeue(&tmpq, (void **)&mp, 1) == 0) {
5569 (void) dataq_enqueue(&inputq, mp);
5570 }
5571 (void) dataq_destroy(&tmpq);
5572 }
5573
5574 /*
5575 * Generate a hash value of the given address and derive
5576 * an index into the hnc_cache hashtable.
5577 * The hashing method is similar to what Java does for strings.
5578 */
5579 static int
5580 addr_hash(struct netbuf *nbp)
5581 {
5582 char *uap;
5583 int i;
5584 unsigned long hcode = 0;
5585
5586 uap = nbp->buf;
5587
5588 if (uap == NULL) {
5589 return (0);
5590 }
5591
5592 /*
5593 * Compute a hashcode of the address string
5594 */
5595 for (i = 0; i < nbp->len; i++)
5596 hcode = (31 * hcode) + uap[i];
5597
5598 /*
5599 * Scramble the hashcode for better distribution
5600 */
5601 hcode += ~(hcode << 9);
5602 hcode ^= (hcode >> 14);
5603 hcode += (hcode << 4);
5604 hcode ^= (hcode >> 10);
5605
5606 return ((int)(hcode % hnc_size));
5607 }