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