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