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