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