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