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