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