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