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