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