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