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, *hnc_active, *hnc_freeq; 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 char *uap; 2191 2192 if (Debug) { 2193 mythreadno = pthread_self(); 2194 } 2195 2196 if (Debug) 2197 uap = taddr2uaddr(ncp, nbp); 2198 2199 DPRINT2(2, "cvthname(%u): looking up hostname for %s\n", 2200 mythreadno, uap ? uap : "<unknown>"); 2201 2202 if ((h = hnc_lookup(nbp, ncp)) != NULL) { 2203 DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n", 2204 mythreadno, h, uap ? uap : "<unknown>", 2205 h->hl_hosts[0]); 2206 return (h); 2207 } 2208 DPRINT2(2, "cvthname(%u): No cache found for %s\n", 2209 mythreadno, uap ? uap : "<unknown>"); 2210 2211 if (Debug) 2212 free(uap); 2213 2214 if (ncp->nc_semantics != NC_TPI_CLTS) { 2215 return (NULL); 2216 } 2217 2218 /* memory allocation failure here is fatal */ 2219 if ((h = malloc(sizeof (host_list_t))) == NULL) { 2220 MALLOC_FAIL("host name conversion"); 2221 return (NULL); 2222 } 2223 2224 if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) { 2225 if (hsp->h_cnt <= 0) { 2226 out: netdir_free((void *)hsp, ND_HOSTSERVLIST); 2227 free(h); 2228 return (NULL); 2229 } 2230 2231 hspp = hsp->h_hostservs; 2232 h->hl_cnt = hsp->h_cnt; 2233 h->hl_hosts = (char **)malloc(sizeof (char *) * (h->hl_cnt)); 2234 if (h->hl_hosts == NULL) { 2235 MALLOC_FAIL("host name conversion"); 2236 goto out; 2237 } 2238 2239 DPRINT2(2, "cvthname(%u): Found %d hostnames\n", 2240 mythreadno, h->hl_cnt); 2241 for (i = 0; i < h->hl_cnt; i++) { 2242 h->hl_hosts[i] = (char *) 2243 malloc(sizeof (char) * (strlen(hspp->h_host) + 1)); 2244 if (h->hl_hosts[i] == NULL) { 2245 int j; 2246 for (j = 0; j < i; j++) { 2247 free(h->hl_hosts[j]); 2248 } 2249 free(h->hl_hosts); 2250 MALLOC_FAIL("host name conversion"); 2251 goto out; 2252 } 2253 (void) strcpy(h->hl_hosts[i], hspp->h_host); 2254 hspp++; 2255 } 2256 netdir_free((void *)hsp, ND_HOSTSERVLIST); 2257 } else { /* unknown address */ 2258 h->hl_cnt = 1; 2259 h->hl_hosts = (char **)malloc(sizeof (char *)); 2260 if (h->hl_hosts == NULL) { 2261 free(h); 2262 MALLOC_FAIL("host name conversion"); 2263 return (NULL); 2264 } 2265 h->hl_hosts[0] = (char *)malloc(strlen(failsafe_addr) + 3); 2266 if (h->hl_hosts[0] == NULL) { 2267 free(h->hl_hosts); 2268 free(h); 2269 MALLOC_FAIL("host name conversion"); 2270 return (NULL); 2271 } 2272 (void) sprintf(h->hl_hosts[0], "[%s]", failsafe_addr); 2273 DPRINT2(1, "cvthname(%u): Hostname lookup failed " 2274 "- using address %s instead\n", 2275 mythreadno, h->hl_hosts[0]); 2276 } 2277 2278 h->hl_refcnt = 1; 2279 if (pthread_mutex_init(&h->hl_mutex, NULL) != 0) { 2280 logerror("pthread_mutex_init failed"); 2281 /* This host_list won't be shared by the cache. */ 2282 return (h); 2283 } 2284 hnc_register(nbp, ncp, h); 2285 DPRINT3(2, "cvthname(%u): returning %p for %s\n", 2286 mythreadno, h, h->hl_hosts[0]); 2287 return (h); 2288 } 2289 2290 /* 2291 * Print syslogd errors some place. Need to be careful here, because 2292 * this routine is called at times when we're not initialized and 2293 * ready to log messages...in this case, fall back to using the console. 2294 */ 2295 void 2296 logerror(const char *type, ...) 2297 { 2298 char buf[MAXLINE+1]; 2299 pthread_t mythreadno; 2300 int flag; 2301 va_list ap; 2302 2303 if (Debug) { 2304 mythreadno = pthread_self(); 2305 } 2306 2307 va_start(ap, type); 2308 logerror_format(type, buf, ap); 2309 va_end(ap); 2310 DPRINT2(1, "logerror(%u): %s\n", mythreadno, buf); 2311 2312 pthread_mutex_lock(&logerror_lock); 2313 if (!interrorlog) { 2314 flag = 0; 2315 if (logerror_to_console(1, buf) == 0) { 2316 /* has written to the console */ 2317 flag = IGN_CONS; 2318 } 2319 (void) logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE|flag, 1); 2320 } else { 2321 if (logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE, 0) == -1) { 2322 (void) logerror_to_console(1, buf); 2323 } 2324 } 2325 pthread_mutex_unlock(&logerror_lock); 2326 2327 errno = 0; 2328 t_errno = 0; 2329 } 2330 2331 static void 2332 logerror_format(const char *type, char *buf, va_list ap) 2333 { 2334 char tmpbuf[MAXLINE + 1]; 2335 pthread_t mythreadno; 2336 2337 if (Debug) { 2338 mythreadno = pthread_self(); 2339 } 2340 2341 (void) vsnprintf(tmpbuf, MAXLINE, type, ap); 2342 2343 if (t_errno == 0 || t_errno == TSYSERR) { 2344 char *errstr; 2345 2346 if (errno == 0) { 2347 (void) snprintf(buf, MAXLINE, "syslogd: %.*s", 2348 MAXLINE, tmpbuf); 2349 } else if ((errstr = strerror(errno)) == (char *)NULL) { 2350 (void) snprintf(buf, MAXLINE, "syslogd: %s: error" 2351 " %d", tmpbuf, errno); 2352 } else { 2353 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s", 2354 tmpbuf, errstr); 2355 } 2356 } else { 2357 if (t_errno > t_nerr) { 2358 (void) snprintf(buf, MAXLINE, "syslogd: %s:" 2359 " t_error %d", tmpbuf, t_errno); 2360 } else { 2361 (void) snprintf(buf, MAXLINE, "syslogd: %s: %s", 2362 tmpbuf, t_errlist[t_errno]); 2363 } 2364 } 2365 2366 DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno, buf); 2367 } 2368 2369 static int 2370 logerror_to_console(int nonblock, const char *buf) 2371 { 2372 int cfd, modes; 2373 pthread_t mythreadno; 2374 int ret = 0, len; 2375 char tmpbuf[MAXLINE + 1]; 2376 2377 if (Debug) { 2378 mythreadno = pthread_self(); 2379 } 2380 2381 DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno, buf); 2382 2383 /* 2384 * must use open here instead of fopen, because 2385 * we need the O_NOCTTY behavior - otherwise we 2386 * could hang the console at boot time 2387 */ 2388 2389 modes = (nonblock) ? 2390 O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK : 2391 O_WRONLY|O_APPEND|O_NOCTTY; 2392 2393 if (((cfd = open(sysmsg, modes)) >= 0) || 2394 ((cfd = open(ctty, modes)) >= 0)) { 2395 (void) snprintf(tmpbuf, MAXLINE, "%s\n", buf); 2396 len = strlen(tmpbuf); 2397 if (write(cfd, tmpbuf, len) != len) { 2398 ret = 1; 2399 } 2400 (void) close(cfd); 2401 } else { 2402 ret = 1; 2403 2404 /* punt */ 2405 DPRINT1(1, "logerror_console(%u): can't open console\n", 2406 mythreadno); 2407 } 2408 return (ret); 2409 } 2410 2411 /* 2412 * copy current message to saved message in filed structure. 2413 */ 2414 static void 2415 copy_msg(struct filed *f) 2416 { 2417 (void) strlcpy(f->f_prevmsg.msg, f->f_current.msg, MAXLINE+1); 2418 (void) strlcpy(f->f_prevmsg.host, f->f_current.host, SYS_NMLN); 2419 f->f_prevmsg.pri = f->f_current.pri; 2420 f->f_prevmsg.flags = f->f_current.flags; 2421 f->f_prevmsg.time = f->f_current.time; 2422 f->f_msgflag |= OLD_VALID; 2423 } 2424 2425 2426 /* 2427 * function to free a host_list_t struct that was allocated 2428 * out of cvthname(). There is a special case where we don't 2429 * free the hostname list in LocalHostName, because that's 2430 * our own addresses, and we just want to have to look it 2431 * up once and save it. Also don't free it if it's 2432 * NullHostName, because that's a special one we use if 2433 * name service lookup fails. 2434 * 2435 * By having hostname cache, now host_list_t will be shared 2436 * by messages and hostname cache. hl_refcnt is used for 2437 * the purpose. 2438 */ 2439 static void 2440 freehl(host_list_t *h) 2441 { 2442 int i, refcnt; 2443 pthread_t mythreadno; 2444 2445 if (Debug) { 2446 mythreadno = pthread_self(); 2447 } 2448 2449 DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno, h); 2450 2451 if (h == NULL || h == &LocalHostName || h == &NullHostName) { 2452 return; 2453 } 2454 2455 pthread_mutex_lock(&h->hl_mutex); 2456 refcnt = --h->hl_refcnt; 2457 pthread_mutex_unlock(&h->hl_mutex); 2458 2459 if (refcnt != 0) { 2460 DPRINT3(5, "freehl(%u): %p has reference %d\n", 2461 mythreadno, h, refcnt); 2462 return; 2463 } 2464 2465 pthread_mutex_destroy(&h->hl_mutex); 2466 2467 DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno, h); 2468 2469 for (i = 0; i < h->hl_cnt; i++) { 2470 free(h->hl_hosts[i]); 2471 } 2472 2473 free(h->hl_hosts); 2474 free(h); 2475 } 2476 2477 /* 2478 * Create the door file and the pid file in /var/run. If the filesystem 2479 * containing /etc is writable, create symlinks /etc/.syslog_door and 2480 * /etc/syslog.pid to them. On systems that do not support /var/run, create 2481 * /etc/.syslog_door and /etc/syslog.pid directly. 2482 * 2483 * Note: it is not considered fatal to fail to create the pid file or its 2484 * symlink. Attempts to use them in the usual way will fail, of course, but 2485 * syslogd will function nicely without it (not so for the door file). 2486 */ 2487 2488 static void 2489 open_door(void) 2490 { 2491 struct stat buf; 2492 door_info_t info; 2493 char line[MAXLINE+1]; 2494 pthread_t mythreadno; 2495 int err; 2496 2497 if (Debug) { 2498 mythreadno = pthread_self(); 2499 } 2500 2501 /* 2502 * first see if another syslogd is running by trying 2503 * a door call - if it succeeds, there is already 2504 * a syslogd process active 2505 */ 2506 2507 if (!DoorCreated) { 2508 int door; 2509 2510 if ((door = open(DoorFileName, O_RDONLY)) >= 0) { 2511 DPRINT2(5, "open_door(%u): %s opened " 2512 "successfully\n", mythreadno, DoorFileName); 2513 2514 if (door_info(door, &info) >= 0) { 2515 DPRINT2(5, "open_door(%u): " 2516 "door_info:info.di_target = %ld\n", 2517 mythreadno, info.di_target); 2518 2519 if (info.di_target > 0) { 2520 (void) sprintf(line, "syslogd pid %ld" 2521 " already running. Cannot " 2522 "start another syslogd pid %ld", 2523 info.di_target, getpid()); 2524 DPRINT2(5, "open_door(%u): error: " 2525 "%s\n", mythreadno, line); 2526 errno = 0; 2527 logerror(line); 2528 exit(1); 2529 } 2530 } 2531 2532 (void) close(door); 2533 } else { 2534 if (lstat(DoorFileName, &buf) < 0) { 2535 err = errno; 2536 2537 DPRINT3(5, "open_door(%u): lstat() of %s " 2538 "failed, errno=%d\n", 2539 mythreadno, DoorFileName, err); 2540 2541 if ((door = creat(DoorFileName, 0644)) < 0) { 2542 err = errno; 2543 (void) sprintf(line, "creat() of %s " 2544 "failed - fatal", DoorFileName); 2545 DPRINT3(1, "open_door(%u): error: %s, " 2546 "errno=%d\n", mythreadno, line, 2547 err); 2548 errno = err; 2549 logerror(line); 2550 delete_doorfiles(); 2551 exit(1); 2552 } 2553 2554 (void) fchmod(door, 2555 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 2556 2557 DPRINT2(5, "open_door(%u): creat() of %s " 2558 "succeeded\n", mythreadno, 2559 DoorFileName); 2560 2561 (void) close(door); 2562 } 2563 } 2564 2565 if (strcmp(DoorFileName, DOORFILE) == 0) { 2566 if (lstat(OLD_DOORFILE, &buf) == 0) { 2567 DPRINT2(5, "open_door(%u): lstat() of %s " 2568 "succeeded\n", mythreadno, 2569 OLD_DOORFILE); 2570 2571 if (S_ISDIR(buf.st_mode)) { 2572 (void) sprintf(line, "%s is a " 2573 "directory - fatal", 2574 OLD_DOORFILE); 2575 DPRINT2(1, "open_door(%u): error: " 2576 "%s\n", mythreadno, line); 2577 errno = 0; 2578 logerror(line); 2579 delete_doorfiles(); 2580 exit(1); 2581 } 2582 2583 DPRINT2(5, "open_door(%u): %s is not a " 2584 "directory\n", 2585 mythreadno, OLD_DOORFILE); 2586 2587 if (unlink(OLD_DOORFILE) < 0) { 2588 err = errno; 2589 (void) sprintf(line, "unlink() of %s " 2590 "failed", OLD_DOORFILE); 2591 DPRINT2(5, "open_door(%u): %s\n", 2592 mythreadno, line); 2593 2594 if (err != EROFS) { 2595 DPRINT3(1, "open_door(%u): " 2596 "error: %s, " 2597 "errno=%d\n", 2598 mythreadno, line, err); 2599 (void) strcat(line, " - fatal"); 2600 errno = err; 2601 logerror(line); 2602 delete_doorfiles(); 2603 exit(1); 2604 } 2605 2606 DPRINT1(5, "open_door(%u): unlink " 2607 "failure OK on RO file " 2608 "system\n", mythreadno); 2609 } 2610 } else { 2611 DPRINT2(5, "open_door(%u): file %s doesn't " 2612 "exist\n", mythreadno, OLD_DOORFILE); 2613 } 2614 2615 if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) { 2616 err = errno; 2617 (void) sprintf(line, "symlink %s -> %s " 2618 "failed", OLD_DOORFILE, 2619 RELATIVE_DOORFILE); 2620 DPRINT2(5, "open_door(%u): %s\n", mythreadno, 2621 line); 2622 2623 if (err != EROFS) { 2624 DPRINT3(1, "open_door(%u): error: %s, " 2625 "errno=%d\n", mythreadno, line, 2626 err); 2627 errno = err; 2628 (void) strcat(line, " - fatal"); 2629 logerror(line); 2630 delete_doorfiles(); 2631 exit(1); 2632 } 2633 2634 DPRINT1(5, "open_door(%u): symlink failure OK " 2635 "on RO file system\n", mythreadno); 2636 } else { 2637 DPRINT3(5, "open_door(%u): symlink %s -> %s " 2638 "succeeded\n", mythreadno, 2639 OLD_DOORFILE, RELATIVE_DOORFILE); 2640 } 2641 } 2642 2643 if ((DoorFd = door_create(server, 0, 2644 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 2645 err = errno; 2646 (void) sprintf(line, "door_create() failed - fatal"); 2647 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", 2648 mythreadno, line, err); 2649 errno = err; 2650 logerror(line); 2651 delete_doorfiles(); 2652 exit(1); 2653 } 2654 (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); 2655 DPRINT2(5, "open_door(%u): door_create() succeeded, " 2656 "DoorFd=%d\n", mythreadno, DoorFd); 2657 2658 DoorCreated = 1; 2659 } 2660 2661 (void) fdetach(DoorFileName); /* just in case... */ 2662 2663 if (fattach(DoorFd, DoorFileName) < 0) { 2664 err = errno; 2665 (void) sprintf(line, "fattach() of fd" 2666 " %d to %s failed - fatal", 2667 DoorFd, DoorFileName); 2668 DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno, 2669 line, err); 2670 errno = err; 2671 logerror(line); 2672 delete_doorfiles(); 2673 exit(1); 2674 } 2675 2676 DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno, 2677 DoorFileName); 2678 2679 /* 2680 * create pidfile anyway, so those using it to control 2681 * syslogd (with kill `cat /etc/syslog.pid` perhaps) 2682 * don't get broken. 2683 */ 2684 2685 if (!PidfileCreated) { 2686 int pidfd; 2687 2688 PidfileCreated = 1; 2689 2690 if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644)) 2691 < 0) { 2692 err = errno; 2693 (void) sprintf(line, "open() of %s failed", 2694 PidFileName); 2695 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n", 2696 mythreadno, line, err); 2697 errno = err; 2698 logerror(line); 2699 return; 2700 } 2701 2702 (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 2703 (void) sprintf(line, "%ld\n", getpid()); 2704 2705 if (write(pidfd, line, strlen(line)) < 0) { 2706 err = errno; 2707 (void) sprintf(line, "write to %s on fd %d failed", 2708 PidFileName, pidfd); 2709 DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n", 2710 mythreadno, line, err); 2711 errno = err; 2712 logerror(line); 2713 return; 2714 } 2715 2716 (void) close(pidfd); 2717 2718 DPRINT2(5, "open_door(%u): %s created\n", 2719 mythreadno, PidFileName); 2720 2721 if (strcmp(PidFileName, PIDFILE) == 0) { 2722 if (lstat(OLD_PIDFILE, &buf) == 0) { 2723 DPRINT2(5, "open_door(%u): lstat() of %s " 2724 "succeded\n", mythreadno, OLD_PIDFILE); 2725 2726 if (S_ISDIR(buf.st_mode)) { 2727 (void) sprintf(line, "file %s is a " 2728 "directory", 2729 OLD_PIDFILE); 2730 DPRINT2(1, "open_door(%u): warning: " 2731 "%s\n", mythreadno, line); 2732 errno = 0; 2733 logerror(line); 2734 return; 2735 } 2736 2737 if (unlink(OLD_PIDFILE) < 0) { 2738 err = errno; 2739 (void) sprintf(line, "unlink() " 2740 "of %s failed", OLD_PIDFILE); 2741 DPRINT2(5, "open_door(%u): %s\n", 2742 mythreadno, line); 2743 2744 if (err != EROFS) { 2745 DPRINT3(1, "open_door (%u): " 2746 "warning: %s, " 2747 "errno=%d\n", 2748 mythreadno, line, err); 2749 errno = err; 2750 logerror(line); 2751 return; 2752 } 2753 2754 DPRINT1(5, "open_door(%u): unlink " 2755 "failure OK on RO file " 2756 "system\n", mythreadno); 2757 } 2758 } else { 2759 DPRINT2(5, "open_door(%u): file %s doesn't " 2760 "exist\n", mythreadno, OLD_PIDFILE); 2761 } 2762 2763 if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) { 2764 err = errno; 2765 (void) sprintf(line, "symlink %s -> %s " 2766 "failed", OLD_PIDFILE, 2767 RELATIVE_PIDFILE); 2768 DPRINT2(5, "open_door(%u): %s\n", mythreadno, 2769 line); 2770 2771 if (err != EROFS) { 2772 DPRINT3(1, "open_door(%u): warning: " 2773 "%s, errno=%d\n", mythreadno, 2774 line, err); 2775 errno = err; 2776 logerror(line); 2777 return; 2778 } 2779 2780 DPRINT1(5, "open_door(%u): symlink failure OK " 2781 "on RO file system\n", mythreadno); 2782 return; 2783 } 2784 2785 DPRINT3(5, "open_door(%u): symlink %s -> %s " 2786 "succeeded\n", mythreadno, OLD_PIDFILE, 2787 RELATIVE_PIDFILE); 2788 } 2789 } 2790 } 2791 2792 /* 2793 * the 'server' function that we export via the door. It does 2794 * nothing but return. 2795 */ 2796 /*ARGSUSED*/ 2797 static void 2798 server(void *cookie, char *argp, size_t arg_size, 2799 door_desc_t *dp, uint_t n) 2800 { 2801 (void) door_return(NULL, 0, NULL, 0); 2802 /* NOTREACHED */ 2803 } 2804 2805 /* 2806 * checkm4 - used to verify that the external utilities that 2807 * syslogd depends on are where we expect them to be. 2808 * Returns 0 if all utilities are found, > 0 if any are missing. 2809 * Also logs errors so user knows what's missing 2810 */ 2811 static int 2812 checkm4(void) 2813 { 2814 int notfound = 0; 2815 int saverrno; 2816 pthread_t mythreadno; 2817 2818 if (Debug) { 2819 mythreadno = pthread_self(); 2820 } 2821 2822 if (access("/usr/ccs/bin/m4", X_OK) < 0) { 2823 saverrno = errno; 2824 logerror("/usr/ccs/bin/m4"); 2825 DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access " 2826 "returned %d\n", mythreadno, saverrno); 2827 notfound++; 2828 } 2829 2830 return (notfound); 2831 } 2832 2833 /* 2834 * INIT -- Initialize syslogd from configuration table, start up 2835 * input and logger threads. This routine is called only once. 2836 */ 2837 static void 2838 init(void) 2839 { 2840 struct utsname *up; 2841 pthread_attr_t sys_attr, net_attr, log_attr, hnl_attr; 2842 int nthread; 2843 pthread_t mythreadno; 2844 2845 if (Debug) { 2846 mythreadno = pthread_self(); 2847 } 2848 2849 DPRINT1(2, "init(%u): initializing\n", mythreadno); 2850 2851 /* hand-craft a host_list_t entry for our local host name */ 2852 if ((up = malloc(sizeof (struct utsname))) == NULL) { 2853 MALLOC_FAIL_EXIT; 2854 } 2855 (void) uname(up); 2856 LocalHostName.hl_cnt = 1; 2857 if ((LocalHostName.hl_hosts = malloc(sizeof (char *))) == NULL) { 2858 MALLOC_FAIL_EXIT; 2859 } 2860 if ((LocalHostName.hl_hosts[0] = strdup(up->nodename)) == NULL) { 2861 free(LocalHostName.hl_hosts); 2862 MALLOC_FAIL_EXIT; 2863 } 2864 free(up); 2865 /* also hand craft one for use if name resolution fails */ 2866 NullHostName.hl_cnt = 1; 2867 if ((NullHostName.hl_hosts = malloc(sizeof (char *))) == NULL) { 2868 MALLOC_FAIL_EXIT; 2869 } 2870 if ((NullHostName.hl_hosts[0] = strdup("name lookup failed")) == NULL) { 2871 MALLOC_FAIL_EXIT; 2872 } 2873 2874 hnc_init(0); 2875 2876 /* 2877 * Note that getnets will allocate network resources, but won't be 2878 * binding UDP port. This is because, there could be a race 2879 * condition between door. If we bind here, one syslogd could grab 2880 * UDP port first, but later another syslogd could take over without 2881 * getting UDP port but grab the door file. The 2nd syslogd could 2882 * continue to run without listening network. 2883 * bindnet() will be called after door was successfully opened. 2884 */ 2885 getnets(); 2886 2887 /* 2888 * Start up configured theads 2889 */ 2890 conf_init(); 2891 2892 /* 2893 * allocate thread stacks for the persistant threads 2894 */ 2895 nthread = (turnoff == 0) ? 4 : 2; 2896 2897 if ((stack_ptr = alloc_stacks(nthread)) == NULL) { 2898 logerror("alloc_stacks failed - fatal"); 2899 exit(1); 2900 } 2901 2902 if (Debug) { 2903 dumpstats(STDOUT_FILENO); 2904 } 2905 2906 (void) dataq_init(&inputq); /* init the input queue */ 2907 2908 if (pthread_attr_init(&sys_attr) != 0 || 2909 pthread_attr_init(&log_attr) != 0 || 2910 pthread_attr_init(&net_attr) != 0 || 2911 pthread_attr_init(&hnl_attr) != 0) { 2912 logerror("pthread_attr_init failed - fatal"); 2913 exit(1); 2914 } 2915 2916 (void) pthread_attr_setscope(&sys_attr, PTHREAD_SCOPE_PROCESS); 2917 (void) pthread_attr_setscope(&log_attr, PTHREAD_SCOPE_PROCESS); 2918 (void) pthread_attr_setscope(&net_attr, PTHREAD_SCOPE_PROCESS); 2919 (void) pthread_attr_setscope(&hnl_attr, PTHREAD_SCOPE_PROCESS); 2920 2921 /* 1: logmsg thread */ 2922 (void) pthread_attr_setstacksize(&log_attr, stacksize); 2923 (void) pthread_attr_setstackaddr(&log_attr, stack_ptr); 2924 stack_ptr += stacksize + redzonesize; 2925 if (pthread_create(&log_thread, &log_attr, logmsg, NULL) != 0) { 2926 logerror("pthread_create failed - fatal"); 2927 exit(1); 2928 } 2929 2930 /* 2931 * open the log device, and pull up all pending message 2932 * from the log driver. 2933 */ 2934 prepare_sys_poll(); 2935 2936 /* 2937 * Now we can deliver the pending internal error messages. 2938 */ 2939 enable_errorlog(); 2940 2941 /* 2: sys_poll thread */ 2942 (void) pthread_attr_setstacksize(&sys_attr, stacksize); 2943 (void) pthread_attr_setstackaddr(&sys_attr, stack_ptr); 2944 stack_ptr += stacksize + redzonesize; 2945 if (pthread_create(&sys_thread, &sys_attr, sys_poll, NULL) != 0) { 2946 logerror("pthread_create failed - fatal"); 2947 exit(1); 2948 } 2949 2950 /* 2951 * We've started the sys_poll() and logmsg() threads. Now we are ready 2952 * to open the door. This cannot happen before spawning sys_poll(), 2953 * because after opening the door, syslog() will no longer take care of 2954 * LOG_CONS. Therefor, we should pull up all pending log messages and 2955 * activate sys_poll() before opening the door, so that log driver 2956 * won't drop messages. 2957 */ 2958 open_door(); 2959 2960 DPRINT1(1, "init(%u): accepting messages from local system\n", 2961 mythreadno); 2962 2963 if (turnoff == 0) { 2964 /* init the hostname lookup queue */ 2965 (void) dataq_init(&hnlq); 2966 2967 /* 3: hostname lookup thread */ 2968 (void) pthread_attr_setstacksize(&hnl_attr, stacksize); 2969 (void) pthread_attr_setstackaddr(&hnl_attr, stack_ptr); 2970 stack_ptr += stacksize + redzonesize; 2971 if (pthread_create(&hnl_thread, &hnl_attr, 2972 hostname_lookup, NULL) != 0) { 2973 logerror("pthread_create failed - fatal"); 2974 exit(1); 2975 } 2976 2977 /* 4: net_poll thread */ 2978 (void) pthread_attr_setstacksize(&net_attr, stacksize); 2979 (void) pthread_attr_setstackaddr(&net_attr, stack_ptr); 2980 stack_ptr += stacksize + redzonesize; 2981 2982 /* grab UDP port */ 2983 bindnet(); 2984 2985 if (pthread_create(&net_thread, &net_attr, net_poll, 2986 NULL) != 0) { 2987 logerror("pthread_create failed - fatal"); 2988 exit(1); 2989 } 2990 DPRINT1(1, "init(%u): accepting messages from remote\n", 2991 mythreadno); 2992 } 2993 2994 (void) pthread_attr_destroy(&sys_attr); 2995 (void) pthread_attr_destroy(&net_attr); 2996 (void) pthread_attr_destroy(&log_attr); 2997 (void) pthread_attr_destroy(&hnl_attr); 2998 2999 curalarm = MarkInterval * 60 / MARKCOUNT; 3000 (void) alarm((unsigned)curalarm); 3001 DPRINT2(2, "init(%u): Next alarm in %d seconds\n", 3002 mythreadno, curalarm); 3003 DPRINT1(1, "init(%u): syslogd: started\n", mythreadno); 3004 } 3005 3006 /* 3007 * will print a bunch of debugging stats on 'fd' 3008 */ 3009 static void 3010 dumpstats(int fd) 3011 { 3012 FILE *out; 3013 struct filed *f; 3014 int i; 3015 char users[1024]; 3016 char cbuf[30]; 3017 char *dashes = "------------------------"; 3018 static int conversion_printed; 3019 3020 if ((out = fdopen(fd, "w+")) == NULL) 3021 return; 3022 3023 (void) fprintf(out, "\n syslogd: version %s\n", Version); 3024 (void) fprintf(out, " Started: %s", ctime_r(&start_time, cbuf)); 3025 (void) fprintf(out, "Input message count: system %d, network %d\n", 3026 sys_msg_count, net_msg_count); 3027 (void) fprintf(out, "# Outputs: %d\n\n", nlogs); 3028 3029 (void) fprintf(out, "%s priority = [file, facility] %s\n\n", 3030 dashes, dashes); 3031 3032 for (i = 0; i < LOG_NFACILITIES + 1; i++) { 3033 (void) fprintf(out, "%d ", i / 10); 3034 } 3035 (void) fprintf(out, "\n"); 3036 for (i = 0; i < LOG_NFACILITIES + 1; i++) { 3037 (void) fprintf(out, "%d ", i % 10); 3038 } 3039 (void) fprintf(out, "\n"); 3040 for (i = 0; i < LOG_NFACILITIES + 1; i++) { 3041 (void) fprintf(out, "--"); 3042 } 3043 (void) fprintf(out, "\n"); 3044 3045 for (f = Files; f < &Files[nlogs]; f++) { 3046 for (i = 0; i < LOG_NFACILITIES + 1; i++) { 3047 if (f->f_pmask[i] == NOPRI) 3048 (void) fprintf(out, "X "); 3049 else 3050 (void) fprintf(out, "%d ", 3051 f->f_pmask[i]); 3052 } 3053 (void) fprintf(out, "%s: ", TypeNames[f->f_type]); 3054 switch (f->f_type) { 3055 case F_FILE: 3056 case F_TTY: 3057 case F_CONSOLE: 3058 (void) fprintf(out, "%s", f->f_un.f_fname); 3059 break; 3060 case F_FORW: 3061 (void) fprintf(out, "%s", f->f_un.f_forw.f_hname); 3062 break; 3063 case F_USERS: 3064 for (i = 0; i < MAXUNAMES && 3065 *f->f_un.f_uname[i]; i++) { 3066 if (!i) 3067 (void) fprintf(out, "%s", 3068 f->f_un.f_uname[i]); 3069 else 3070 (void) fprintf(out, ", %s", 3071 f->f_un.f_uname[i]); 3072 } 3073 break; 3074 } 3075 (void) fprintf(out, "\n"); 3076 } 3077 3078 if (!conversion_printed) { 3079 fprintf(out, "\nFacilities:\n"); 3080 3081 for (i = 0; FacNames[i].c_val != -1; i++) { 3082 fprintf(out, " [%02d] %s: %3d\n", i, 3083 FacNames[i].c_name, FacNames[i].c_val); 3084 } 3085 3086 fprintf(out, "\nPriorities:\n"); 3087 3088 for (i = 0; PriNames[i].c_val != -1; i++) { 3089 fprintf(out, " [%02d] %s: %3d\n", i, 3090 PriNames[i].c_name, PriNames[i].c_val); 3091 } 3092 3093 conversion_printed = 1; 3094 } 3095 3096 (void) fprintf(out, "\n\n\n\t\tPer File Statistics\n"); 3097 (void) fprintf(out, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File"); 3098 (void) fprintf(out, "%-24s\t---\t----\t-----\t----\n", "----"); 3099 for (f = Files; f < &Files[nlogs]; f++) { 3100 switch (f->f_type) { 3101 case F_FILE: 3102 case F_TTY: 3103 case F_CONSOLE: 3104 (void) fprintf(out, "%-24s", f->f_un.f_fname); 3105 break; 3106 case F_WALL: 3107 (void) fprintf(out, "%-24s", TypeNames[f->f_type]); 3108 break; 3109 case F_FORW: 3110 (void) fprintf(out, "%-24s", f->f_un.f_forw.f_hname); 3111 break; 3112 case F_USERS: 3113 for (i = 0; i < MAXUNAMES && 3114 *f->f_un.f_uname[i]; i++) { 3115 if (!i) 3116 (void) strcpy(users, 3117 f->f_un.f_uname[i]); 3118 else { 3119 (void) strcat(users, ","); 3120 (void) strcat(users, 3121 f->f_un.f_uname[i]); 3122 } 3123 } 3124 (void) fprintf(out, "%-24s", users); 3125 break; 3126 } 3127 (void) fprintf(out, "\t%d\t%d\t%d\t%d\n", 3128 f->f_stat.total, f->f_stat.dups, 3129 f->f_stat.cantfwd, f->f_stat.errs); 3130 } 3131 (void) fprintf(out, "\n\n"); 3132 if (Debug && fd == 1) 3133 return; 3134 (void) fclose(out); 3135 } 3136 3137 /* 3138 * conf_init - This routine is code seperated from the 3139 * init routine in order to be re-callable when we get 3140 * a SIGHUP signal. 3141 */ 3142 static void 3143 conf_init(void) 3144 { 3145 char *p; 3146 int i; 3147 struct filed *f; 3148 char *m4argv[4]; 3149 int m4argc = 0; 3150 conf_t cf; 3151 pthread_t mythreadno; 3152 3153 if (Debug) { 3154 mythreadno = pthread_self(); 3155 } 3156 3157 DPRINT1(2, "conf_init(%u): starting logger threads\n", 3158 mythreadno); 3159 3160 m4argv[m4argc++] = "m4"; 3161 3162 if (amiloghost() == 1) { 3163 DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno); 3164 m4argv[m4argc++] = "-DLOGHOST=1"; 3165 } 3166 3167 m4argv[m4argc++] = ConfFile; 3168 m4argv[m4argc] = NULL; 3169 3170 /* 3171 * Make sure the configuration file and m4 exist, and then parse 3172 * the configuration file with m4. If any of these fail, resort 3173 * to our hardcoded fallback configuration. 3174 */ 3175 3176 if (access(ConfFile, R_OK) == -1) { 3177 DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno, 3178 ConfFile); 3179 logerror("can't open configuration file"); 3180 /* CSTYLED */ 3181 Files = (struct filed *) &fallback; /*lint !e545 */ 3182 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]); 3183 cfline("*.PANIC\t*", 0, &Files[1]); 3184 nlogs = 2; 3185 goto nofile; 3186 } 3187 3188 if (checkm4() != 0 || conf_open(&cf, "/usr/ccs/bin/m4", m4argv) == -1) { 3189 DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno, 3190 ConfFile); 3191 /* CSTYLED */ 3192 Files = (struct filed *) &fallback; /*lint !e545 */ 3193 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]); 3194 cfline("*.PANIC\t*", 0, &Files[1]); 3195 nlogs = 2; 3196 goto nofile; 3197 } 3198 3199 /* Count the number of lines which are not blanks or comments */ 3200 nlogs = 0; 3201 while ((p = conf_read(&cf)) != NULL) { 3202 if (p[0] != '\0' && p[0] != '#') 3203 nlogs++; 3204 } 3205 3206 Files = (struct filed *)malloc(sizeof (struct filed) * nlogs); 3207 3208 if (!Files) { 3209 DPRINT1(1, "conf_init(%u): malloc failed - can't " 3210 "allocate 'Files' array\n", mythreadno); 3211 MALLOC_FAIL("loading minimum configuration"); 3212 /* CSTYLED */ 3213 Files = (struct filed *) &fallback; /*lint !e545 */ 3214 cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]); 3215 cfline("*.PANIC\t*", 0, &Files[1]); 3216 nlogs = 2; 3217 conf_close(&cf); 3218 goto nofile; 3219 } 3220 3221 /* 3222 * Foreach line in the conf table, open that file. 3223 */ 3224 conf_rewind(&cf); 3225 f = Files; 3226 i = 0; 3227 while (((p = conf_read(&cf)) != NULL) && (f < &Files[nlogs])) { 3228 i++; 3229 /* check for end-of-section */ 3230 if (p[0] == '\0' || p[0] == '#') 3231 continue; 3232 3233 cfline(p, i, f); 3234 if (f->f_type == F_UNUSED) 3235 nlogs--; 3236 else 3237 f++; 3238 } 3239 3240 conf_close(&cf); 3241 3242 /* 3243 * See if marks are to be written to any files. If so, set up a 3244 * timeout for marks. 3245 */ 3246 nofile: 3247 Marking = 0; 3248 3249 /* 3250 * allocate thread stacks - one for each logger thread. 3251 */ 3252 if ((cstack_ptr = alloc_stacks(nlogs)) == NULL) { 3253 logerror("alloc_stacks failed - fatal"); 3254 exit(1); 3255 } 3256 3257 /* And now one thread for each configured file */ 3258 for (f = Files; f < &Files[nlogs]; f++) { 3259 if (filed_init(f) != 0) { 3260 logerror("pthread_create failed - fatal"); 3261 exit(1); 3262 } 3263 3264 pthread_mutex_lock(&cft); 3265 ++conf_threads; 3266 pthread_mutex_unlock(&cft); 3267 3268 if (f->f_type != F_UNUSED && 3269 f->f_pmask[LOG_NFACILITIES] != NOPRI) 3270 Marking = 1; 3271 } 3272 } 3273 3274 /* 3275 * filed init - initialize fields in a file descriptor struct 3276 * this is called before multiple threads are running, so no mutex 3277 * needs to be held at this time. 3278 */ 3279 static int 3280 filed_init(struct filed *f) 3281 { 3282 pthread_attr_t stack_attr; 3283 pthread_t mythreadno; 3284 3285 if (Debug) { 3286 mythreadno = pthread_self(); 3287 } 3288 3289 if (pthread_mutex_init(&f->filed_mutex, NULL) != 0) { 3290 logerror("pthread_mutex_init failed"); 3291 return (-1); 3292 } 3293 3294 DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n", 3295 mythreadno, &f->f_queue); 3296 (void) dataq_init(&f->f_queue); 3297 3298 if (pthread_attr_init(&stack_attr) != 0) { 3299 logerror("pthread_attr_init failed"); 3300 return (-1); 3301 } 3302 3303 (void) pthread_attr_setstacksize(&stack_attr, stacksize); 3304 (void) pthread_attr_setstackaddr(&stack_attr, cstack_ptr); 3305 cstack_ptr += stacksize + redzonesize; 3306 3307 f->f_msgflag = 0; 3308 f->f_prevmsg.msg[0] = '\0'; 3309 f->f_prevmsg.flags = 0; 3310 f->f_prevmsg.pri = 0; 3311 f->f_prevmsg.host[0] = '\0'; 3312 3313 f->f_current.msg[0] = '\0'; 3314 f->f_current.flags = 0; 3315 f->f_current.pri = 0; 3316 f->f_current.host[0] = '\0'; 3317 3318 f->f_prevcount = 0; 3319 3320 f->f_stat.flag = 0; 3321 f->f_stat.total = 0; 3322 f->f_stat.dups = 0; 3323 f->f_stat.cantfwd = 0; 3324 f->f_stat.errs = 0; 3325 3326 if (pthread_create(&f->f_thread, NULL, logit, (void *)f) != 0) { 3327 logerror("pthread_create failed"); 3328 pthread_attr_destroy(&stack_attr); 3329 return (-1); 3330 } 3331 3332 pthread_attr_destroy(&stack_attr); 3333 return (0); 3334 } 3335 3336 3337 /* 3338 * Crack a configuration file line 3339 */ 3340 static void 3341 cfline(char *line, int lineno, struct filed *f) 3342 { 3343 char *p; 3344 char *q; 3345 int i; 3346 char *bp; 3347 int pri; 3348 char buf[MAXLINE]; 3349 char ebuf[SYS_NMLN+1+40]; 3350 mode_t fmode, omode = O_WRONLY|O_APPEND|O_NOCTTY; 3351 struct stat64 sbuf; 3352 pthread_t mythreadno; 3353 3354 if (Debug) { 3355 mythreadno = pthread_self(); 3356 } 3357 3358 DPRINT2(1, "cfline(%u): (%s)\n", mythreadno, line); 3359 3360 errno = 0; /* keep errno related stuff out of logerror messages */ 3361 3362 /* clear out file entry */ 3363 bzero((char *)f, sizeof (*f)); 3364 for (i = 0; i <= LOG_NFACILITIES; i++) 3365 f->f_pmask[i] = NOPRI; 3366 3367 /* scan through the list of selectors */ 3368 for (p = line; *p && *p != '\t'; ) { 3369 3370 /* find the end of this facility name list */ 3371 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 3372 continue; 3373 3374 /* collect priority name */ 3375 for (bp = buf; *q && !strchr("\t,;", *q); ) 3376 *bp++ = *q++; 3377 *bp = '\0'; 3378 3379 /* skip cruft */ 3380 while (strchr(", ;", *q)) 3381 q++; 3382 3383 /* decode priority name */ 3384 pri = decode(buf, PriNames); 3385 if (pri < 0) { 3386 logerror("line %d: unknown priority name \"%s\"", 3387 lineno, buf); 3388 return; 3389 } 3390 3391 /* scan facilities */ 3392 while (*p && !strchr("\t.;", *p)) { 3393 for (bp = buf; *p && !strchr("\t,;.", *p); ) 3394 *bp++ = *p++; 3395 *bp = '\0'; 3396 if (*buf == '*') 3397 for (i = 0; i < LOG_NFACILITIES; i++) 3398 f->f_pmask[i] = (uchar_t)pri; 3399 else { 3400 i = decode(buf, FacNames); 3401 if (i < 0) { 3402 logerror("line %d: unknown facility" 3403 " name \"%s\"", lineno, buf); 3404 return; 3405 } 3406 f->f_pmask[i >> 3] = (uchar_t)pri; 3407 } 3408 while (*p == ',' || *p == ' ') 3409 p++; 3410 } 3411 3412 p = q; 3413 } 3414 3415 /* skip to action part */ 3416 while (*p == '\t' || *p == ' ') 3417 p++; 3418 3419 switch (*p) { 3420 case '\0': 3421 errno = 0; 3422 logerror("line %d: no action part", lineno); 3423 break; 3424 3425 case '@': 3426 (void) strlcpy(f->f_un.f_forw.f_hname, ++p, SYS_NMLN); 3427 if (logforward(f, ebuf) != 0) { 3428 logerror("line %d: %s", lineno, ebuf); 3429 break; 3430 } 3431 f->f_type = F_FORW; 3432 break; 3433 3434 case '/': 3435 (void) strlcpy(f->f_un.f_fname, p, MAXPATHLEN); 3436 if (stat64(p, &sbuf) < 0) { 3437 logerror(p); 3438 break; 3439 } 3440 /* 3441 * don't block trying to open a pipe 3442 * with no reader on the other end 3443 */ 3444 fmode = 0; /* reset each pass */ 3445 if (S_ISFIFO(sbuf.st_mode)) 3446 fmode = O_NONBLOCK; 3447 3448 f->f_file = open64(p, omode|fmode); 3449 if (f->f_file < 0) { 3450 if (fmode && errno == ENXIO) { 3451 errno = 0; 3452 logerror("%s - no reader", p); 3453 } else 3454 logerror(p); 3455 break; 3456 } 3457 3458 /* 3459 * Fifos are initially opened NONBLOCK 3460 * to insure we don't hang, but once 3461 * we are open, we need to change the 3462 * behavior back to blocking, otherwise 3463 * we may get write errors, and the log 3464 * will get closed down the line. 3465 */ 3466 if (S_ISFIFO(sbuf.st_mode)) 3467 (void) fcntl(f->f_file, F_SETFL, omode); 3468 3469 if (isatty(f->f_file)) { 3470 f->f_type = F_TTY; 3471 untty(); 3472 } else 3473 f->f_type = F_FILE; 3474 3475 if ((strcmp(p, ctty) == 0) || (strcmp(p, sysmsg) == 0)) 3476 f->f_type = F_CONSOLE; 3477 break; 3478 3479 case '*': 3480 f->f_type = F_WALL; 3481 break; 3482 3483 default: 3484 for (i = 0; i < MAXUNAMES && *p; i++) { 3485 for (q = p; *q && *q != ','; ) 3486 q++; 3487 (void) strlcpy(f->f_un.f_uname[i], p, UNAMESZ); 3488 if ((q - p) > UNAMESZ) 3489 f->f_un.f_uname[i][UNAMESZ] = '\0'; 3490 else 3491 f->f_un.f_uname[i][q - p] = '\0'; 3492 while (*q == ',' || *q == ' ') 3493 q++; 3494 p = q; 3495 } 3496 f->f_type = F_USERS; 3497 break; 3498 } 3499 f->f_orig_type = f->f_type; 3500 } 3501 3502 3503 /* 3504 * Decode a symbolic name to a numeric value 3505 */ 3506 static int 3507 decode(char *name, struct code *codetab) 3508 { 3509 struct code *c; 3510 char *p; 3511 char buf[40]; 3512 3513 if (isdigit(*name)) 3514 return (atoi(name)); 3515 3516 (void) strncpy(buf, name, sizeof (buf) - 1); 3517 for (p = buf; *p; p++) 3518 if (isupper(*p)) 3519 *p = tolower(*p); 3520 for (c = codetab; c->c_name; c++) 3521 if (!(strcmp(buf, c->c_name))) 3522 return (c->c_val); 3523 3524 return (-1); 3525 } 3526 3527 static int 3528 ismyaddr(struct netbuf *nbp) 3529 { 3530 int i; 3531 3532 if (nbp == NULL) 3533 return (0); 3534 3535 for (i = 1; i < Ninputs; i++) { 3536 if (same_addr(nbp, Myaddrs[i])) 3537 return (1); 3538 } 3539 return (0); 3540 } 3541 3542 static void 3543 getnets(void) 3544 { 3545 struct nd_hostserv hs; 3546 struct netconfig *ncp; 3547 struct nd_addrlist *nap; 3548 struct netbuf *nbp; 3549 int i, inputs; 3550 void *handle; 3551 char *uap; 3552 pthread_t mythreadno; 3553 3554 if (Debug) { 3555 mythreadno = pthread_self(); 3556 } 3557 3558 if (turnoff) { 3559 DPRINT1(1, "getnets(%u): network is being turned off\n", 3560 mythreadno); 3561 return; 3562 } 3563 3564 hs.h_host = HOST_SELF; 3565 hs.h_serv = "syslog"; 3566 3567 if ((handle = setnetconfig()) == NULL) { 3568 return; 3569 } 3570 3571 while ((ncp = getnetconfig(handle)) != NULL) { 3572 if (ncp->nc_semantics != NC_TPI_CLTS) { 3573 continue; 3574 } 3575 3576 if (netdir_getbyname(ncp, &hs, &nap) != 0) { 3577 continue; 3578 } 3579 3580 if (nap == NULL || nap->n_cnt <= 0) { 3581 DPRINT1(1, "getnets(%u): found no address\n", 3582 mythreadno); 3583 netdir_free((void *)nap, ND_ADDRLIST); 3584 continue; 3585 } 3586 3587 if (Debug) { 3588 DPRINT2(1, "getnets(%u): found %d addresses", 3589 mythreadno, nap->n_cnt); 3590 DPRINT0(1, ", they are: "); 3591 nbp = nap->n_addrs; 3592 3593 for (i = 0; i < nap->n_cnt; i++) { 3594 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) { 3595 DPRINT1(1, "%s ", uap); 3596 free(uap); 3597 } 3598 nbp++; 3599 } 3600 3601 DPRINT0(1, "\n"); 3602 } 3603 3604 inputs = Ninputs + nap->n_cnt; 3605 3606 Nfd = realloc(Nfd, inputs * sizeof (struct pollfd)); 3607 Ncf = realloc(Ncf, inputs * sizeof (struct netconfig)); 3608 Myaddrs = realloc(Myaddrs, inputs * sizeof (struct netbuf *)); 3609 Udp = realloc(Udp, inputs * sizeof (struct t_unitdata *)); 3610 Errp = realloc(Errp, inputs * sizeof (struct t_uderr *)); 3611 3612 /* 3613 * all malloc failures here are fatal 3614 */ 3615 if (Nfd == NULL || Ncf == NULL || Myaddrs == NULL || 3616 Udp == NULL || Errp == NULL) { 3617 MALLOC_FAIL_EXIT; 3618 } 3619 3620 nbp = nap->n_addrs; 3621 3622 for (i = 0; i < nap->n_cnt; i++, nbp++) { 3623 char ebuf[128]; 3624 3625 if (addnet(ncp, nbp) == 0) { 3626 /* no error */ 3627 continue; 3628 } 3629 3630 (void) strcpy(ebuf, "Unable to configure syslog port"); 3631 3632 if ((uap = taddr2uaddr(ncp, nbp)) != NULL) { 3633 size_t l = strlen(ebuf); 3634 (void) snprintf(ebuf + l, sizeof (ebuf) - l, 3635 " for %s", uap); 3636 } 3637 3638 DPRINT2(1, "getnets(%u): %s", 3639 mythreadno, ebuf); 3640 3641 if (uap) { 3642 free(uap); 3643 } 3644 3645 logerror(ebuf); 3646 /* 3647 * Here maybe syslogd can quit. However, syslogd 3648 * has been ignoring this error and keep running. 3649 * So we won't break it. 3650 */ 3651 } 3652 3653 netdir_free((void *)nap, ND_ADDRLIST); 3654 } 3655 3656 (void) endnetconfig(handle); 3657 } 3658 3659 /* 3660 * Open the network device, and allocate necessary resources. 3661 * Myaddrs will also be filled, so that we can call ismyaddr() before 3662 * being bound to the network. 3663 */ 3664 static int 3665 addnet(struct netconfig *ncp, struct netbuf *nbp) 3666 { 3667 int fd; 3668 struct netbuf *bp; 3669 3670 fd = t_open(ncp->nc_device, O_RDWR, NULL); 3671 3672 if (fd < 0) { 3673 return (1); 3674 } 3675 3676 (void) memcpy(&Ncf[Ninputs], ncp, sizeof (struct netconfig)); 3677 3678 /*LINTED*/ 3679 Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR); 3680 3681 if (Udp[Ninputs] == NULL) { 3682 t_close(fd); 3683 return (1); 3684 } 3685 3686 /*LINTED*/ 3687 Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR); 3688 3689 if (Errp[Ninputs] == NULL) { 3690 t_close(fd); 3691 t_free((char *)Udp[Ninputs], T_UNITDATA); 3692 return (1); 3693 } 3694 3695 if ((bp = malloc(sizeof (struct netbuf))) == NULL || 3696 (bp->buf = malloc(nbp->len)) == NULL) { 3697 MALLOC_FAIL("allocating address buffer"); 3698 t_close(fd); 3699 t_free((char *)Udp[Ninputs], T_UNITDATA); 3700 t_free((char *)Errp[Ninputs], T_UDERROR); 3701 3702 if (bp) { 3703 free(bp); 3704 } 3705 3706 return (1); 3707 } 3708 3709 bp->len = nbp->len; 3710 (void) memcpy(bp->buf, nbp->buf, nbp->len); 3711 Myaddrs[Ninputs] = bp; 3712 3713 Nfd[Ninputs].fd = fd; 3714 Nfd[Ninputs].events = POLLIN; 3715 Ninputs++; 3716 return (0); 3717 } 3718 3719 /* 3720 * Allocate UDP buffer to minimize packet loss. 3721 */ 3722 static void 3723 set_udp_buffer(int fd) 3724 { 3725 struct t_optmgmt req, resp; 3726 struct opthdr *opt; 3727 size_t optsize, bsize = 256 * 1024; 3728 pthread_t mythreadno; 3729 3730 if (Debug) { 3731 mythreadno = pthread_self(); 3732 } 3733 3734 optsize = sizeof (struct opthdr) + sizeof (int); 3735 if ((opt = malloc(optsize)) == NULL) { 3736 MALLOC_FAIL("will have no udp buffer"); 3737 return; 3738 } 3739 opt->level = SOL_SOCKET; 3740 opt->name = SO_RCVBUF; 3741 opt->len = sizeof (int); 3742 *(int *)(opt + 1) = bsize; 3743 3744 req.flags = T_NEGOTIATE; 3745 req.opt.len = optsize; 3746 req.opt.buf = (char *)opt; 3747 3748 resp.flags = 0; 3749 resp.opt.maxlen = optsize; 3750 resp.opt.buf = (char *)opt; 3751 3752 while (t_optmgmt(fd, &req, &resp) == -1 || resp.flags != T_SUCCESS) { 3753 if (t_errno != TSYSERR || errno != ENOBUFS) { 3754 bsize = 0; 3755 break; 3756 } 3757 bsize >>= 1; 3758 if (bsize < 8192) { 3759 break; 3760 } 3761 *(int *)(opt + 1) = bsize; 3762 } 3763 if (bsize == 0) { 3764 logerror("failed to allocate UDP buffer"); 3765 } 3766 DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n", 3767 mythreadno, bsize, fd); 3768 free(opt); 3769 } 3770 3771 /* 3772 * Attach the network, and allocate UDP buffer for the interface. 3773 */ 3774 static void 3775 bindnet(void) 3776 { 3777 struct t_bind bind, *bound; 3778 int cnt, i; 3779 char *uap; 3780 pthread_t mythreadno; 3781 3782 if (Debug) { 3783 mythreadno = pthread_self(); 3784 } 3785 3786 cnt = 0; 3787 3788 while (cnt < Ninputs) { 3789 char ebuf[128]; 3790 3791 /*LINTED*/ 3792 bound = (struct t_bind *)t_alloc(Nfd[cnt].fd, T_BIND, T_ADDR); 3793 bind.addr = *Myaddrs[cnt]; 3794 bind.qlen = 0; 3795 3796 if (t_bind(Nfd[cnt].fd, &bind, bound) == 0) { 3797 if (same_addr(&bind.addr, &bound->addr)) { 3798 t_free((char *)bound, T_BIND); 3799 set_udp_buffer(Nfd[cnt].fd); 3800 cnt++; 3801 continue; 3802 } 3803 } 3804 3805 /* failed to bind port */ 3806 t_free((char *)bound, T_BIND); 3807 3808 (void) strcpy(ebuf, "Unable to bind syslog port"); 3809 3810 uap = taddr2uaddr(&Ncf[cnt], Myaddrs[cnt]); 3811 if (uap) { 3812 i = strlen(ebuf); 3813 (void) snprintf(ebuf + i, sizeof (ebuf) - i, 3814 " for %s", uap); 3815 } 3816 3817 DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n", 3818 mythreadno, uap ? uap : "<unknown>"); 3819 3820 if (uap) { 3821 free(uap); 3822 } 3823 3824 errno = 0; 3825 logerror(ebuf); 3826 3827 t_close(Nfd[cnt].fd); 3828 free(Myaddrs[cnt]->buf); 3829 free(Myaddrs[cnt]); 3830 t_free((char *)Udp[cnt], T_UNITDATA); 3831 t_free((char *)Errp[cnt], T_UDERROR); 3832 3833 for (i = cnt; i < (Ninputs-1); i++) { 3834 Nfd[i] = Nfd[i + 1]; 3835 Ncf[i] = Ncf[i + 1]; 3836 Myaddrs[i] = Myaddrs[i + 1]; 3837 Udp[i] = Udp[i + 1]; 3838 Errp[i] = Errp[i + 1]; 3839 } 3840 3841 Ninputs--; 3842 } 3843 } 3844 3845 static int 3846 logforward(struct filed *f, char *ebuf) 3847 { 3848 struct nd_hostserv hs; 3849 struct netbuf *nbp; 3850 struct netconfig *ncp; 3851 struct nd_addrlist *nap; 3852 void *handle; 3853 char *hp; 3854 3855 hp = f->f_un.f_forw.f_hname; 3856 hs.h_host = hp; 3857 hs.h_serv = "syslog"; 3858 3859 if ((handle = setnetconfig()) == NULL) { 3860 (void) strcpy(ebuf, 3861 "unable to rewind the netconfig database"); 3862 errno = 0; 3863 return (-1); 3864 } 3865 nap = (struct nd_addrlist *)NULL; 3866 while ((ncp = getnetconfig(handle)) != NULL) { 3867 if (ncp->nc_semantics == NC_TPI_CLTS) { 3868 if (netdir_getbyname(ncp, &hs, &nap) == 0) { 3869 if (!nap) 3870 continue; 3871 nbp = nap->n_addrs; 3872 break; 3873 } 3874 } 3875 } 3876 if (ncp == NULL) { 3877 endnetconfig(handle); 3878 (void) sprintf(ebuf, "WARNING: %s could not be resolved", hp); 3879 errno = 0; 3880 return (-1); 3881 } 3882 if (nap == (struct nd_addrlist *)NULL) { 3883 endnetconfig(handle); 3884 (void) sprintf(ebuf, "unknown host %s", hp); 3885 errno = 0; 3886 return (-1); 3887 } 3888 /* CSTYLED */ 3889 if (ismyaddr(nbp)) { /*lint !e644 */ 3890 netdir_free((void *)nap, ND_ADDRLIST); 3891 endnetconfig(handle); 3892 (void) sprintf(ebuf, "host %s is this host - logging loop", 3893 hp); 3894 errno = 0; 3895 return (-1); 3896 } 3897 f->f_un.f_forw.f_addr.buf = malloc(nbp->len); 3898 if (f->f_un.f_forw.f_addr.buf == NULL) { 3899 netdir_free((void *)nap, ND_ADDRLIST); 3900 endnetconfig(handle); 3901 (void) strcpy(ebuf, "malloc failed"); 3902 return (-1); 3903 } 3904 bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len); 3905 f->f_un.f_forw.f_addr.len = nbp->len; 3906 f->f_file = t_open(ncp->nc_device, O_RDWR, NULL); 3907 if (f->f_file < 0) { 3908 netdir_free((void *)nap, ND_ADDRLIST); 3909 endnetconfig(handle); 3910 free(f->f_un.f_forw.f_addr.buf); 3911 (void) strcpy(ebuf, "t_open"); 3912 return (-1); 3913 } 3914 netdir_free((void *)nap, ND_ADDRLIST); 3915 endnetconfig(handle); 3916 if (t_bind(f->f_file, NULL, NULL) < 0) { 3917 (void) strcpy(ebuf, "t_bind"); 3918 free(f->f_un.f_forw.f_addr.buf); 3919 t_close(f->f_file); 3920 return (-1); 3921 } 3922 return (0); 3923 } 3924 3925 static int 3926 amiloghost(void) 3927 { 3928 struct nd_hostserv hs; 3929 struct netconfig *ncp; 3930 struct nd_addrlist *nap; 3931 struct netbuf *nbp; 3932 int i, fd; 3933 void *handle; 3934 char *uap; 3935 struct t_bind bind, *bound; 3936 pthread_t mythreadno; 3937 3938 if (Debug) { 3939 mythreadno = pthread_self(); 3940 } 3941 3942 /* 3943 * we need to know if we are running on the loghost. This is 3944 * checked by binding to the address associated with "loghost" 3945 * and "syslogd" service over the connectionless transport 3946 */ 3947 hs.h_host = "loghost"; 3948 hs.h_serv = "syslog"; 3949 3950 if ((handle = setnetconfig()) == NULL) { 3951 return (0); 3952 } 3953 3954 while ((ncp = getnetconfig(handle)) != NULL) { 3955 if (ncp->nc_semantics != NC_TPI_CLTS) { 3956 continue; 3957 } 3958 3959 if (netdir_getbyname(ncp, &hs, &nap) != 0) { 3960 continue; 3961 } 3962 3963 if (nap == NULL) { 3964 continue; 3965 } 3966 3967 nbp = nap->n_addrs; 3968 3969 for (i = 0; i < nap->n_cnt; i++) { 3970 if ((uap = taddr2uaddr(ncp, nbp)) != (char *)NULL) { 3971 DPRINT2(1, "amiloghost(%u): testing %s\n", 3972 mythreadno, uap); 3973 } 3974 3975 free(uap); 3976 3977 fd = t_open(ncp->nc_device, O_RDWR, NULL); 3978 3979 if (fd < 0) { 3980 netdir_free((void *)nap, ND_ADDRLIST); 3981 endnetconfig(handle); 3982 return (0); 3983 } 3984 3985 /*LINTED*/ 3986 bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 3987 bind.addr = *nbp; 3988 bind.qlen = 0; 3989 3990 if (t_bind(fd, &bind, bound) == 0) { 3991 t_close(fd); 3992 t_free((char *)bound, T_BIND); 3993 netdir_free((void *)nap, ND_ADDRLIST); 3994 endnetconfig(handle); 3995 return (1); 3996 } else { 3997 t_close(fd); 3998 t_free((char *)bound, T_BIND); 3999 } 4000 4001 nbp++; 4002 } 4003 4004 netdir_free((void *)nap, ND_ADDRLIST); 4005 } 4006 4007 endnetconfig(handle); 4008 return (0); 4009 } 4010 4011 int 4012 same_addr(struct netbuf *na, struct netbuf *nb) 4013 { 4014 char *a, *b; 4015 size_t n; 4016 4017 assert(a != NULL && b != NULL); 4018 4019 if (na->len != nb->len) { 4020 return (0); 4021 } 4022 4023 a = na->buf; 4024 b = nb->buf; 4025 n = nb->len; 4026 4027 while (n-- > 0) { 4028 if (*a++ != *b++) { 4029 return (0); 4030 } 4031 } 4032 4033 return (1); 4034 } 4035 4036 /* 4037 * allocates a new message structure, initializes it 4038 * and returns a pointer to it 4039 */ 4040 static log_message_t * 4041 new_msg(void) 4042 { 4043 log_message_t *lm; 4044 pthread_t mythreadno; 4045 4046 if (Debug) { 4047 mythreadno = pthread_self(); 4048 } 4049 4050 if ((lm = malloc(sizeof (log_message_t))) == NULL) 4051 return ((log_message_t *)NULL); 4052 4053 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lm)) 4054 4055 if (pthread_mutex_init(&lm->msg_mutex, NULL) != 0) 4056 return ((log_message_t *)NULL); 4057 lm->refcnt = 0; 4058 lm->pri = 0; 4059 lm->flags = 0; 4060 lm->hlp = NULL; 4061 lm->msg[0] = '\0'; 4062 lm->ptr = NULL; 4063 4064 DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno, lm); 4065 return (lm); 4066 } 4067 4068 /* 4069 * frees a message structure - should only be called if 4070 * the refcount is 0 4071 */ 4072 static void 4073 free_msg(log_message_t *lm) 4074 { 4075 pthread_t mythreadno; 4076 4077 if (Debug) { 4078 mythreadno = pthread_self(); 4079 } 4080 4081 assert(lm != NULL && lm->refcnt == 0); 4082 if (lm->hlp != NULL) 4083 freehl(lm->hlp); 4084 DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno, lm); 4085 free(lm); 4086 } 4087 4088 /* 4089 * Make sure that the message makes sense in the current locale, and 4090 * does not contain stray control characters. 4091 */ 4092 static void 4093 filter_string(char *mbstr, char *filtered, size_t max) 4094 { 4095 size_t cs = 0; 4096 size_t mb_cur_max; 4097 unsigned char *p = (unsigned char *)mbstr; 4098 pthread_t mythreadno = 0; 4099 4100 if (Debug) { 4101 mythreadno = pthread_self(); 4102 } 4103 4104 assert(mbstr != NULL && filtered != NULL); 4105 4106 /* 4107 * Since the access to MB_CUR_MAX is expensive (because 4108 * MB_CUR_MAX lives in a global area), it should be 4109 * restrained for the better performance. 4110 */ 4111 mb_cur_max = (size_t)MB_CUR_MAX; 4112 if (mb_cur_max > 1) { 4113 /* multibyte locale */ 4114 int mlen; 4115 wchar_t wc; 4116 4117 while (*p != '\0') { 4118 if ((mlen = mbtowc(&wc, (char *)p, 4119 mb_cur_max)) == -1) { 4120 /* 4121 * Invalid byte sequence found. 4122 * 4123 * try to print one byte 4124 * in ASCII format. 4125 */ 4126 DPRINT2(9, "filter_string(%u): Invalid " 4127 "MB sequence: %d\n", mythreadno, 4128 wc); 4129 4130 if (!putctrlc(*p++, &filtered, &cs, max)) { 4131 /* not enough buffer */ 4132 goto end; 4133 } else { 4134 continue; 4135 } 4136 } else { 4137 /* 4138 * Since *p is not a null byte here, 4139 * mbtowc should have never returned 0. 4140 * 4141 * A valid wide character found. 4142 */ 4143 4144 if (wc != L'\t' && iswcntrl(wc)) { 4145 /* 4146 * non-tab, non-newline, and 4147 * control character found. 4148 * 4149 * try to print this wide character 4150 * in ASCII-format. 4151 */ 4152 char *q = filtered; 4153 4154 DPRINT2(9, "filter_string(%u): MB" 4155 " control character: %d\n", 4156 mythreadno, wc); 4157 4158 while (mlen--) { 4159 if (!putctrlc(*p++, &filtered, 4160 &cs, max)) { 4161 /* 4162 * not enough buffer in 4163 * filtered 4164 * 4165 * cancel already 4166 * stored bytes in 4167 * filtered for this 4168 * wide character. 4169 */ 4170 filtered = q; 4171 goto end; 4172 } 4173 } 4174 continue; 4175 } else { 4176 /* 4177 * tab, newline, or non-control 4178 * character found. 4179 */ 4180 if (cs + mlen < max) { 4181 /* enough buffer */ 4182 cs += mlen; 4183 while (mlen--) { 4184 *filtered++ = *p++; 4185 } 4186 continue; 4187 } else { 4188 /* not enough buffer */ 4189 goto end; 4190 } 4191 } 4192 } 4193 } 4194 } else { 4195 /* singlebyte locale */ 4196 4197 while (*p != '\0') { 4198 if (*p != '\t' && iscntrl(*p)) { 4199 /* 4200 * non-tab, non-newline, 4201 * and control character found. 4202 * 4203 * try to print this singlebyte character 4204 * in ASCII format. 4205 */ 4206 DPRINT2(9, "filter_string(%u): control " 4207 "character: %d\n", mythreadno, *p); 4208 4209 if (!putctrlc(*p++, &filtered, &cs, max)) { 4210 /* not enough buffer */ 4211 goto end; 4212 } else { 4213 continue; 4214 } 4215 } else if (*p != '\t' && !isprint(*p)) { 4216 /* 4217 * non-tab and non printable character found 4218 * this check is required for the C locale 4219 */ 4220 DPRINT2(9, "filter_string(%u): non-printable " 4221 "character: %d\n", mythreadno, *p); 4222 if (!putctrlc(*p++, &filtered, &cs, max)) { 4223 /* not enough buffer */ 4224 goto end; 4225 } else { 4226 continue; 4227 } 4228 } else { 4229 /* 4230 * tab, newline, non-control character, or 4231 * printable found. 4232 */ 4233 if (cs + 1 < max) { 4234 *filtered++ = *p++; 4235 cs++; 4236 continue; 4237 } else { 4238 /* not enough buffer */ 4239 goto end; 4240 } 4241 } 4242 } 4243 } 4244 4245 end: 4246 *filtered = '\0'; 4247 4248 if (cs >= 2 && 4249 filtered[-2] == '\\' && filtered[-1] == 'n') { 4250 filtered[-2] = '\0'; 4251 } 4252 } 4253 4254 static char * 4255 alloc_stacks(int numstacks) 4256 { 4257 size_t pagesize, mapsize; 4258 char *stack_top; 4259 char *addr; 4260 int i; 4261 4262 pagesize = (size_t)sysconf(_SC_PAGESIZE); 4263 /* 4264 * stacksize and redzonesize are global so threads 4265 * can be created elsewhere and refer to the sizes 4266 */ 4267 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) + 4268 DEFAULT_STACKSIZE, pagesize); 4269 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize); 4270 4271 /* 4272 * allocate an additional "redzonesize" chunk in addition 4273 * to what we require, so we can create a redzone at the 4274 * bottom of the last stack as well. 4275 */ 4276 mapsize = redzonesize + numstacks * (stacksize + redzonesize); 4277 stack_top = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, 4278 MAP_PRIVATE|MAP_ANON, -1, 0); 4279 if (stack_top == MAP_FAILED) 4280 return (NULL); 4281 4282 addr = stack_top; 4283 /* 4284 * this loop is intentionally <= instead of <, so we can 4285 * protect the redzone at the bottom of the last stack 4286 */ 4287 for (i = 0; i <= numstacks; i++) { 4288 (void) mprotect(addr, redzonesize, PROT_NONE); 4289 addr += stacksize + redzonesize; 4290 } 4291 return ((char *)(stack_top + redzonesize)); 4292 } 4293 4294 static void 4295 dealloc_stacks(int numstacks) 4296 { 4297 size_t pagesize, mapsize; 4298 4299 pagesize = (size_t)sysconf(_SC_PAGESIZE); 4300 4301 stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) + 4302 DEFAULT_STACKSIZE, pagesize); 4303 4304 redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize); 4305 4306 mapsize = redzonesize + numstacks * (stacksize + redzonesize); 4307 (void) munmap(cstack_ptr - mapsize, mapsize); 4308 } 4309 4310 static void 4311 filed_destroy(struct filed *f) 4312 { 4313 (void) dataq_destroy(&f->f_queue); 4314 pthread_mutex_destroy(&f->filed_mutex); 4315 } 4316 4317 static void 4318 close_door(void) 4319 { 4320 pthread_t mythreadno; 4321 4322 if (Debug) { 4323 mythreadno = pthread_self(); 4324 } 4325 4326 (void) fdetach(DoorFileName); 4327 4328 DPRINT2(5, "close_door(%u): detached server() from %s\n", 4329 mythreadno, DoorFileName); 4330 } 4331 4332 static void 4333 delete_doorfiles(void) 4334 { 4335 pthread_t mythreadno; 4336 struct stat sb; 4337 int err; 4338 char line[MAXLINE+1]; 4339 4340 if (Debug) { 4341 mythreadno = pthread_self(); 4342 } 4343 4344 4345 if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { 4346 if (unlink(DoorFileName) < 0) { 4347 err = errno; 4348 (void) sprintf(line, "unlink() of %s failed - fatal", 4349 DoorFileName); 4350 errno = err; 4351 logerror(line); 4352 DPRINT3(1, "delete_doorfiles(%u): error: %s, " 4353 "errno=%d\n", mythreadno, line, err); 4354 exit(1); 4355 } 4356 4357 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", 4358 mythreadno, DoorFileName); 4359 } 4360 4361 if (strcmp(DoorFileName, DOORFILE) == 0) { 4362 if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { 4363 if (unlink(OLD_DOORFILE) < 0) { 4364 err = errno; 4365 (void) sprintf(line, "unlink() of %s " 4366 "failed", OLD_DOORFILE); 4367 DPRINT2(5, "delete_doorfiles(%u): %s\n", 4368 mythreadno, line); 4369 4370 if (err != EROFS) { 4371 errno = err; 4372 (void) strcat(line, " - fatal"); 4373 logerror(line); 4374 DPRINT3(1, "delete_doorfiles(%u): " 4375 "error: %s, errno=%d\n", 4376 mythreadno, line, err); 4377 exit(1); 4378 } 4379 4380 DPRINT1(5, "delete_doorfiles(%u): unlink() " 4381 "failure OK on RO file system\n", 4382 mythreadno); 4383 } 4384 4385 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", 4386 mythreadno, OLD_DOORFILE); 4387 } 4388 } 4389 4390 if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { 4391 if (unlink(PidFileName) < 0) { 4392 err = errno; 4393 (void) sprintf(line, "unlink() of %s failed" 4394 " - fatal", PidFileName); 4395 errno = err; 4396 logerror(line); 4397 DPRINT3(1, "delete_doorfiles(%u): error: %s, " 4398 "errno=%d\n", mythreadno, line, err); 4399 exit(1); 4400 } 4401 4402 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno, 4403 PidFileName); 4404 } 4405 4406 if (strcmp(PidFileName, PIDFILE) == 0) { 4407 if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { 4408 if (unlink(OLD_PIDFILE) < 0) { 4409 err = errno; 4410 (void) sprintf(line, "unlink() of %s failed", 4411 OLD_PIDFILE); 4412 DPRINT2(5, "delete_doorfiles(%u): %s, \n", 4413 mythreadno, line); 4414 4415 if (err != EROFS) { 4416 errno = err; 4417 (void) strcat(line, " - fatal"); 4418 logerror(line); 4419 DPRINT3(1, "delete_doorfiles(%u): " 4420 "error: %s, errno=%d\n", 4421 mythreadno, line, err); 4422 exit(1); 4423 } 4424 4425 DPRINT1(5, "delete_doorfiles(%u): unlink " 4426 "failure OK on RO file system\n", 4427 mythreadno); 4428 } 4429 4430 DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", 4431 mythreadno, OLD_PIDFILE); 4432 } 4433 } 4434 4435 if (DoorFd != -1) { 4436 (void) door_revoke(DoorFd); 4437 } 4438 4439 DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n", 4440 mythreadno, DoorFd); 4441 } 4442 4443 4444 /*ARGSUSED*/ 4445 static void 4446 signull(int sig, siginfo_t *sip, void *utp) 4447 { 4448 DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n", 4449 pthread_self()); 4450 /* 4451 * Do nothing, as this is a place-holder used in conjunction with 4452 * sigaction()/sigwait() to ensure that the proper disposition is 4453 * given to the signals we handle in main(). 4454 */ 4455 } 4456 4457 /* 4458 * putctrlc returns zero, if failed due to not enough buffer. 4459 * Otherwise, putctrlc returns non-zero. 4460 * 4461 * c: a byte to print in ASCII format 4462 * **buf: a pointer to the pointer to the output buffer. 4463 * *cl: current length of characters in the output buffer 4464 * max: maximum length of the buffer 4465 */ 4466 4467 static int 4468 putctrlc(int c, char **buf, size_t *cl, size_t max) 4469 { 4470 char *p = *buf; 4471 4472 if (c == '\n') { 4473 if (*cl + 2 < max) { 4474 *p++ = '\\'; 4475 *p++ = 'n'; 4476 *cl += 2; 4477 *buf = p; 4478 return (2); 4479 } else { 4480 return (0); 4481 } 4482 } else if (c < 0200) { 4483 /* ascii control character */ 4484 if (*cl + 2 < max) { 4485 *p++ = '^'; 4486 *p++ = c ^ 0100; 4487 *cl += 2; 4488 *buf = p; 4489 return (2); 4490 } else { 4491 return (0); 4492 } 4493 } else { 4494 if (*cl + 4 < max) { 4495 *p++ = '\\'; 4496 *p++ = ((c >> 6) & 07) + '0'; 4497 *p++ = ((c >> 3) & 07) + '0'; 4498 *p++ = (c & 07) + '0'; 4499 *cl += 4; 4500 *buf = p; 4501 return (4); 4502 } else { 4503 return (0); 4504 } 4505 } 4506 } 4507 4508 /* 4509 * findnl_bkwd: 4510 * Scans each character in buf until it finds the last newline in buf, 4511 * or the scanned character becomes the last COMPLETE character in buf. 4512 * Returns the number of scanned bytes. 4513 * 4514 * buf - pointer to a buffer containing the message string 4515 * len - the length of the buffer 4516 */ 4517 size_t 4518 findnl_bkwd(const char *buf, const size_t len) 4519 { 4520 const char *p; 4521 size_t mb_cur_max; 4522 pthread_t mythreadno; 4523 4524 if (Debug) { 4525 mythreadno = pthread_self(); 4526 } 4527 4528 if (len == 0) { 4529 return (0); 4530 } 4531 4532 mb_cur_max = MB_CUR_MAX; 4533 4534 if (mb_cur_max == 1) { 4535 /* single-byte locale */ 4536 for (p = buf + len - 1; p != buf; p--) { 4537 if (*p == '\n') { 4538 return ((size_t)(p - buf)); 4539 } 4540 } 4541 return ((size_t)len); 4542 } else { 4543 /* multi-byte locale */ 4544 int mlen; 4545 const char *nl; 4546 size_t rem; 4547 4548 p = buf; 4549 nl = NULL; 4550 for (rem = len; rem >= mb_cur_max; ) { 4551 mlen = mblen(p, mb_cur_max); 4552 if (mlen == -1) { 4553 /* 4554 * Invalid character found. 4555 */ 4556 DPRINT1(9, "findnl_bkwd(%u): Invalid MB " 4557 "sequence\n", mythreadno); 4558 /* 4559 * handle as a single byte character. 4560 */ 4561 p++; 4562 rem--; 4563 } else { 4564 /* 4565 * It's guaranteed that *p points to 4566 * the 1st byte of a multibyte character. 4567 */ 4568 if (*p == '\n') { 4569 nl = p; 4570 } 4571 p += mlen; 4572 rem -= mlen; 4573 } 4574 } 4575 if (nl) { 4576 return ((size_t)(nl - buf)); 4577 } 4578 /* 4579 * no newline nor null byte found. 4580 * Also it's guaranteed that *p points to 4581 * the 1st byte of a (multibyte) character 4582 * at this point. 4583 */ 4584 return (len - rem); 4585 } 4586 } 4587 4588 /* 4589 * copynl_frwd: 4590 * Scans each character in buf and copies the scanned character to obuf 4591 * until it finds a null byte or a newline, or 4592 * the number of the remaining bytes in obuf gets to exceed obuflen 4593 * if copying the scanned character to obuf. 4594 * Returns the number of scanned bytes. 4595 * 4596 * obuf - buffer to be copied the scanned character 4597 * obuflen - the size of obuf 4598 * buf - pointer to a buffer containing the message string 4599 * len - the length of the buffer 4600 */ 4601 size_t 4602 copynl_frwd(char *obuf, const size_t obuflen, 4603 const char *buf, const size_t len) 4604 { 4605 const char *p; 4606 char *q = obuf; 4607 size_t olen = 0; 4608 size_t mb_cur_max; 4609 pthread_t mythreadno; 4610 4611 if (Debug) { 4612 mythreadno = pthread_self(); 4613 } 4614 4615 if (len == 0) { 4616 return (0); 4617 } 4618 4619 mb_cur_max = MB_CUR_MAX; 4620 4621 if (mb_cur_max == 1) { 4622 /* single-byte locale */ 4623 for (p = buf; *p; ) { 4624 if (obuflen > olen + 1) { 4625 if (*p != '\n') { 4626 *q++ = *p++; 4627 olen++; 4628 } else { 4629 *q = '\0'; 4630 return ((size_t)(p - buf)); 4631 } 4632 } else { 4633 *q = '\0'; 4634 return ((size_t)(p - buf)); 4635 } 4636 } 4637 *q = '\0'; 4638 return ((size_t)(p - buf)); 4639 } else { 4640 /* multi-byte locale */ 4641 int mlen; 4642 4643 for (p = buf; *p; ) { 4644 mlen = mblen(p, mb_cur_max); 4645 if (mlen == -1) { 4646 /* 4647 * Invalid character found. 4648 */ 4649 DPRINT1(9, "copynl_frwd(%u): Invalid MB " 4650 "sequence\n", mythreadno); 4651 /* 4652 * handle as a single byte character. 4653 */ 4654 if (obuflen > olen + 1) { 4655 *q++ = *p++; 4656 olen++; 4657 } else { 4658 *q = '\0'; 4659 return ((size_t)(p - buf)); 4660 } 4661 } else { 4662 /* 4663 * It's guaranteed that *p points to 4664 * the 1st byte of a multibyte character. 4665 */ 4666 if (*p == '\n') { 4667 *q = '\0'; 4668 return ((size_t)(p - buf)); 4669 } 4670 if (obuflen > olen + mlen) { 4671 int n; 4672 for (n = 0; n < mlen; n++) { 4673 *q++ = *p++; 4674 } 4675 olen += mlen; 4676 } else { 4677 *q = '\0'; 4678 return ((size_t)(p - buf)); 4679 } 4680 } 4681 } 4682 /* 4683 * no newline nor null byte found. 4684 * Also it's guaranteed that *p points to 4685 * the 1st byte of a (multibyte) character 4686 * at this point. 4687 */ 4688 *q = '\0'; 4689 return ((size_t)(p - buf)); 4690 } 4691 } 4692 4693 /* 4694 * copy_frwd: 4695 * Scans each character in buf and copies the scanned character to obuf 4696 * until the number of the remaining bytes in obuf gets to exceed obuflen 4697 * if copying the scanned character to obuf. 4698 * Returns the number of scanned (copied) bytes. 4699 * 4700 * obuf - buffer to be copied the scanned character 4701 * obuflen - the size of obuf 4702 * buf - pointer to a buffer containing the message string 4703 * len - the length of the buffer 4704 */ 4705 size_t 4706 copy_frwd(char *obuf, const size_t obuflen, 4707 const char *buf, const size_t len) 4708 { 4709 const char *p; 4710 char *q = obuf; 4711 size_t olen = 0; 4712 size_t mb_cur_max; 4713 pthread_t mythreadno; 4714 4715 if (Debug) { 4716 mythreadno = pthread_self(); 4717 } 4718 4719 if (len == 0) { 4720 return (0); 4721 } 4722 4723 mb_cur_max = MB_CUR_MAX; 4724 4725 if (mb_cur_max == 1) { 4726 /* single-byte locale */ 4727 if (obuflen > len) { 4728 (void) memcpy(obuf, buf, len); 4729 obuf[len] = '\0'; 4730 return ((size_t)len); 4731 } else { 4732 (void) memcpy(obuf, buf, obuflen - 1); 4733 obuf[obuflen - 1] = '\0'; 4734 return (obuflen - 1); 4735 } 4736 } else { 4737 /* multi-byte locale */ 4738 int mlen; 4739 4740 for (p = buf; *p; ) { 4741 mlen = mblen(p, mb_cur_max); 4742 if (mlen == -1) { 4743 /* 4744 * Invalid character found. 4745 */ 4746 DPRINT1(9, "copy_frwd(%u): Invalid MB " 4747 "sequence\n", mythreadno); 4748 /* 4749 * handle as a single byte character. 4750 */ 4751 if (obuflen > olen + 1) { 4752 *q++ = *p++; 4753 olen++; 4754 } else { 4755 *q = '\0'; 4756 return ((size_t)(p - buf)); 4757 } 4758 } else { 4759 if (obuflen > olen + mlen) { 4760 int n; 4761 for (n = 0; n < mlen; n++) { 4762 *q++ = *p++; 4763 } 4764 olen += mlen; 4765 } else { 4766 *q = '\0'; 4767 return ((size_t)(p - buf)); 4768 } 4769 } 4770 } 4771 *q = '\0'; 4772 return ((size_t)(p - buf)); 4773 } 4774 } 4775 4776 /* 4777 * defaults: 4778 * Read defaults from file. 4779 */ 4780 static void 4781 defaults(void) 4782 { 4783 int flags; 4784 char *ptr; 4785 4786 if (defopen(DflFile) == 0) { 4787 /* 4788 * ignore case 4789 */ 4790 flags = defcntl(DC_GETFLAGS, 0); 4791 TURNOFF(flags, DC_CASE); 4792 defcntl(DC_SETFLAGS, flags); 4793 4794 if ((ptr = defread("LOG_FROM_REMOTE=")) != NULL) { 4795 turnoff = strcasecmp(ptr, "NO") == 0; 4796 } 4797 4798 (void) defopen((char *)NULL); 4799 } 4800 } 4801 4802 /* 4803 * close all the input devices. 4804 */ 4805 static void 4806 shutdown_input(void) 4807 { 4808 int cnt; 4809 4810 shutting_down = 1; 4811 4812 for (cnt = 0; cnt < Ninputs; cnt++) { 4813 (void) t_close(Nfd[cnt].fd); 4814 } 4815 4816 (void) close(Pfd.fd); 4817 } 4818 4819 /* 4820 * This is for the one thread that dedicates to resolve the 4821 * hostname. This will get the messages from net_poll() through 4822 * hnlq, and resolve the hostname, and push the messages back 4823 * into the inputq. 4824 */ 4825 /*ARGSUSED*/ 4826 static void * 4827 hostname_lookup(void *ap) 4828 { 4829 char *uap; 4830 log_message_t *mp; 4831 host_info_t *hip; 4832 char failsafe_addr[SYS_NMLN + 1]; 4833 pthread_t mythreadno; 4834 4835 if (Debug) { 4836 mythreadno = pthread_self(); 4837 } 4838 4839 DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n", 4840 mythreadno); 4841 4842 for (;;) { 4843 (void) dataq_dequeue(&hnlq, (void **)&mp, 0); 4844 4845 DPRINT3(5, "hostname_lookup(%u): dequeued msg %p" 4846 " from queue %p\n", mythreadno, mp, &hnlq); 4847 4848 hip = (host_info_t *)mp->ptr; 4849 if ((uap = taddr2uaddr(hip->ncp, &hip->addr)) != NULL) { 4850 (void) strlcpy(failsafe_addr, uap, SYS_NMLN); 4851 free(uap); 4852 } else { 4853 (void) strlcpy(failsafe_addr, "<unknown>", SYS_NMLN); 4854 } 4855 4856 mp->hlp = cvthname(&hip->addr, hip->ncp, failsafe_addr); 4857 4858 if (mp->hlp == NULL) { 4859 mp->hlp = &NullHostName; 4860 } 4861 4862 free(hip->addr.buf); 4863 free(hip); 4864 mp->ptr = NULL; 4865 4866 if (dataq_enqueue(&inputq, (void *)mp) == -1) { 4867 MALLOC_FAIL("dropping message from remote"); 4868 free_msg(mp); 4869 continue; 4870 } 4871 4872 DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue %p\n", 4873 mythreadno, mp, &inputq); 4874 } 4875 4876 /*NOTREACHED*/ 4877 return (NULL); 4878 } 4879 4880 /* 4881 * Does all HUP(re-configuration) process. 4882 */ 4883 static void 4884 reconfigure() 4885 { 4886 int cnt, loop, drops; 4887 int really_stuck; 4888 int console_stuck = 0; 4889 struct filed *f; 4890 char buf[LINE_MAX]; 4891 struct utsname up; 4892 char cbuf[30]; 4893 time_t tim; 4894 pthread_t mythreadno; 4895 4896 if (Debug) { 4897 mythreadno = pthread_self(); 4898 } 4899 4900 /* If we get here then we must need to regen */ 4901 flushmsg(0); 4902 4903 if (logmymsg(LOG_SYSLOG|LOG_INFO, "syslogd: configuration restart", 4904 ADDDATE, 0) == -1) { 4905 MALLOC_FAIL("dropping message"); 4906 } 4907 4908 /* 4909 * make sure the logmsg thread is not in the waiting state. 4910 * Otherwise, changing hup_state will prevent the logmsg thread 4911 * getting out from the waiting loop. 4912 */ 4913 4914 if (Debug) { 4915 tim = time(NULL); 4916 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()" 4917 " moving to the safe place\n", 4918 mythreadno, ctime_r(&tim, cbuf)+4); 4919 } 4920 4921 for (loop = 0; loop < LOOP_MAX; loop++) { 4922 /* we don't need the mutex to read */ 4923 if (hup_state == HUP_ACCEPTABLE) 4924 break; 4925 (void) sleep(1); 4926 } 4927 if (hup_state != HUP_ACCEPTABLE) { 4928 goto thread_stuck; 4929 } 4930 4931 if (Debug) { 4932 tim = time(NULL); 4933 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n", 4934 mythreadno, ctime_r(&tim, cbuf)+4); 4935 } 4936 4937 /* 4938 * Prevent logging until we are truly done processing the HUP 4939 */ 4940 (void) pthread_mutex_lock(&hup_lock); 4941 hup_state = HUP_INPROGRESS; 4942 (void) pthread_mutex_unlock(&hup_lock); 4943 4944 /* 4945 * We will be going into a critical state. Any error message 4946 * from syslogd needs to be dumped to the console by default 4947 * immediately. Also, those error messages are quened in a temporary 4948 * queue to be able to post into the regular stream later. 4949 */ 4950 disable_errorlog(); 4951 4952 if (Debug) { 4953 tim = time(NULL); 4954 DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n", 4955 mythreadno, ctime_r(&tim, cbuf)+4); 4956 } 4957 4958 /* stop configured threads */ 4959 if (shutdown_msg() == -1) { 4960 /* 4961 * No memory, message will be dumped to the console. 4962 */ 4963 MALLOC_FAIL("unable to restart syslogd"); 4964 goto out; 4965 } 4966 4967 /* make sure logmsg() is in suspended state */ 4968 for (loop = 0; loop < LOOP_INTERVAL; loop++) { 4969 if (hup_state & HUP_LOGMSG_SUSPENDED) 4970 break; 4971 (void) sleep(1); 4972 } 4973 4974 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) { 4975 if (Debug) { 4976 tim = time(NULL); 4977 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not " 4978 "stop. enforcing\n", 4979 mythreadno, ctime_r(&tim, cbuf)+4); 4980 } 4981 4982 /* probably we have too long input queue, or really stuck */ 4983 (void) pthread_mutex_lock(&hup_lock); 4984 hup_state |= HUP_SUSP_LOGMSG_REQD; 4985 (void) pthread_mutex_unlock(&hup_lock); 4986 4987 for (loop = 0; loop < LOOP_MAX; loop++) { 4988 if (hup_state & HUP_LOGMSG_SUSPENDED) 4989 break; 4990 (void) sleep(1); 4991 } 4992 if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) { 4993 if (Debug) { 4994 tim = time(NULL); 4995 DPRINT2(3, "reconfigure(%u): %.15s: logmsg()" 4996 " does not stop. give up\n", 4997 mythreadno, ctime_r(&tim, cbuf)+4); 4998 } 4999 logerror("could not suspend logmsg - fatal"); 5000 goto thread_stuck; 5001 } 5002 } 5003 5004 if (Debug) { 5005 tim = time(NULL); 5006 DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n", 5007 mythreadno, ctime_r(&tim, cbuf)+4); 5008 } 5009 5010 /* 5011 * Will wait for LOOP_MAX secs with watching queue lengths for the 5012 * each logger threads. If they have backlogs, and no change in the 5013 * length of queue found in 30 seconds, those will be counted as 5014 * "really stuck". 5015 * If all running logger threads become "really stuck" state, there 5016 * should be no worth waiting for them to quit. 5017 * In that case, we will go ahead and close out file descriptors to 5018 * have them pull out from hanging system call, and give them a last 5019 * chance(LOOP_INTERVAL sec) to quit. 5020 */ 5021 5022 if (Debug) { 5023 tim = time(NULL); 5024 DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be" 5025 " shutdown\n", mythreadno, ctime_r(&tim, cbuf)+4); 5026 } 5027 5028 cnt = 0; 5029 really_stuck = 0; 5030 while (cnt < (LOOP_MAX/LOOP_INTERVAL) && 5031 conf_threads > really_stuck) { 5032 5033 /* save initial queue count */ 5034 for (f = Files; f < &Files[nlogs]; f++) { 5035 f->f_prev_queue_count = (f->f_type == F_UNUSED) ? 5036 -1 : f->f_queue_count; 5037 } 5038 5039 for (loop = 0; loop < LOOP_INTERVAL; loop++) { 5040 if (conf_threads == 0) 5041 break; 5042 (void) sleep(1); 5043 } 5044 5045 if (conf_threads == 0) 5046 break; 5047 5048 if (Debug) { 5049 tim = time(NULL); 5050 DPRINT3(3, "reconfigure(%u): %.15s: " 5051 "%d threads are still alive.\n", 5052 mythreadno, ctime_r(&tim, cbuf)+4, 5053 conf_threads); 5054 } 5055 5056 really_stuck = 0; 5057 for (f = Files; f < &Files[nlogs]; f++) { 5058 if (f->f_type == F_UNUSED) { 5059 f->f_prev_queue_count = -1; 5060 continue; 5061 } 5062 if (f->f_prev_queue_count == f->f_queue_count) { 5063 really_stuck++; 5064 f->f_prev_queue_count = 1; 5065 DPRINT2(3, "reconfigure(%u): " 5066 "tid=%d is really stuck.\n", 5067 mythreadno, f->f_thread); 5068 } else { 5069 f->f_prev_queue_count = 0; 5070 DPRINT2(3, "reconfigure(%u): " 5071 "tid=%d is still active.\n", 5072 mythreadno, f->f_thread); 5073 } 5074 } 5075 /* 5076 * Here we have one of following values in the 5077 * f_prev_queue_count: 5078 * 0: logger thread is still actively working. 5079 * 1: logger thread is really stuck. 5080 * -1: logger thread has already died. 5081 */ 5082 5083 cnt++; 5084 } 5085 5086 if (Debug) { 5087 tim = time(NULL); 5088 DPRINT2(3, "reconfigure(%u): %.15s:" 5089 " complete awaiting logit()\n", 5090 mythreadno, ctime_r(&tim, cbuf)+4); 5091 DPRINT3(3, "reconfigure(%u): %d threads alive." 5092 " %d threads stuck\n", 5093 mythreadno, conf_threads, really_stuck); 5094 } 5095 5096 /* 5097 * Still running? If so, mark it as UNUSED, and close 5098 * the fd so that logger threads can bail out from the loop. 5099 */ 5100 drops = 0; 5101 if (conf_threads) { 5102 for (f = Files; f < &Files[nlogs]; f++) { 5103 if (f->f_type == F_CONSOLE && 5104 f->f_prev_queue_count == 1) { 5105 /* console is really stuck */ 5106 console_stuck = 1; 5107 } 5108 if (f->f_type == F_USERS || f->f_type == F_WALL || 5109 f->f_type == F_UNUSED) 5110 continue; 5111 cnt = f->f_queue_count; 5112 drops += (cnt > 0) ? cnt - 1: 0; 5113 f->f_type = F_UNUSED; 5114 5115 if (f->f_orig_type == F_FORW) 5116 t_close(f->f_file); 5117 else 5118 close(f->f_file); 5119 } 5120 5121 if (Debug) { 5122 tim = time(NULL); 5123 DPRINT1(3, "reconfigure(%u): terminating logit()\n", 5124 mythreadno); 5125 } 5126 5127 /* last chance to exit */ 5128 for (loop = 0; loop < LOOP_MAX; loop++) { 5129 if (conf_threads == 0) 5130 break; 5131 (void) sleep(1); 5132 } 5133 5134 if (Debug) { 5135 tim = time(NULL); 5136 DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n", 5137 mythreadno, ctime_r(&tim, cbuf)+4, 5138 conf_threads); 5139 } 5140 } 5141 5142 if (conf_threads == 0 && drops) { 5143 errno = 0; 5144 logerror("Could not completely output pending messages" 5145 " while preparing re-configuration"); 5146 logerror("discarded %d messages and restart configuration.", 5147 drops); 5148 if (Debug) { 5149 tim = time(NULL); 5150 DPRINT3(3, "reconfigure(%u): %.15s: " 5151 "discarded %d messages\n", 5152 mythreadno, ctime_r(&tim, cbuf)+4, drops); 5153 } 5154 } 5155 5156 /* 5157 * If all threads still haven't exited 5158 * something is stuck or hosed. We just 5159 * have no option but to exit. 5160 */ 5161 if (conf_threads) { 5162 thread_stuck: 5163 if (Debug) { 5164 tim = time(NULL); 5165 DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n", 5166 mythreadno, ctime_r(&tim, cbuf)+4); 5167 } 5168 5169 shutdown_input(); 5170 delete_doorfiles(); 5171 uname(&up); 5172 5173 (void) sprintf(buf, 5174 "syslogd(%s): some logger thread(s) " 5175 "are stuck%s; syslogd is shutting down.", 5176 up.nodename, 5177 console_stuck ? " (including the console)" : ""); 5178 5179 if (console_stuck) { 5180 FILE *m = popen(MAILCMD, "w"); 5181 5182 if (m != NULL) { 5183 fprintf(m, "%s\n", buf); 5184 pclose(m); 5185 } 5186 } 5187 5188 disable_errorlog(); 5189 logerror(buf); 5190 exit(1); 5191 } 5192 5193 /* Free up some resources */ 5194 if (Files != (struct filed *)&fallback) { 5195 for (f = Files; f < &Files[nlogs]; f++) { 5196 (void) pthread_join(f->f_thread, NULL); 5197 filed_destroy(f); 5198 } 5199 free(Files); 5200 } 5201 5202 dealloc_stacks(nlogs); 5203 5204 if (Debug) { 5205 tim = time(NULL); 5206 DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n", 5207 mythreadno, ctime_r(&tim, cbuf)+4); 5208 } 5209 5210 hnc_init(1); /* purge hostname cache */ 5211 conf_init(); /* start reconfigure */ 5212 5213 out:; 5214 /* Now should be ready to dispatch error messages from syslogd. */ 5215 enable_errorlog(); 5216 5217 /* Wake up the log thread */ 5218 5219 if (Debug) { 5220 tim = time(NULL); 5221 DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n", 5222 mythreadno, ctime_r(&tim, cbuf)+4); 5223 } 5224 5225 (void) pthread_mutex_lock(&hup_lock); 5226 hup_state = HUP_COMPLETED; 5227 (void) pthread_cond_signal(&hup_done); 5228 (void) pthread_mutex_unlock(&hup_lock); 5229 } 5230 5231 /* 5232 * The following function implements simple hostname cache mechanism. 5233 * Host name cache consists of single linked list structure which contains 5234 * host_list_t and netbuf pair. All cache entries(hnc_size) are allocated 5235 * initially and linked to "hnc_freeq". If cache register request comes, 5236 * then one element will be pulled from freeq, and will be linked to 5237 * "hnc_active" with given netbuf, host_list_t and expiration time. All valid 5238 * cahces are linked from hnc_active. If the cache element has run 5239 * out, most unused element will be re-used for the new request. 5240 * 5241 * hnc_init(): 5242 * allocate and initialize the cache. If reinit is set, 5243 * invalidate all cache entries. 5244 * hnc_look(): 5245 * lookup the cache entries by following single linked list 5246 * from hnc_active. If cached entry was found, it will be 5247 * put in the head of the list, and return. While going through 5248 * the entries, an entry which has already expired will be invalidated. 5249 * hnc_register(): 5250 * take one element from freeq, and put the new entry at the top 5251 * of hnc_active. 5252 * hnc_unreg(): 5253 * invalidate the cache. i.e unlink from hnc_active, and linked the 5254 * element to freeq. 5255 */ 5256 5257 static void 5258 hnc_init(int reinit) 5259 { 5260 struct hostname_cache **hpp; 5261 pthread_t mythreadno; 5262 5263 if (Debug) { 5264 mythreadno = pthread_self(); 5265 } 5266 5267 if (reinit) { 5268 pthread_mutex_lock(&hnc_mutex); 5269 5270 for (hpp = &hnc_active; *hpp != NULL; ) { 5271 hnc_unreg(hpp); 5272 } 5273 5274 pthread_mutex_unlock(&hnc_mutex); 5275 DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n", 5276 mythreadno); 5277 } else { 5278 int i; 5279 5280 hnc_cache = malloc(hnc_size * sizeof (struct hostname_cache)); 5281 5282 if (hnc_cache == NULL) { 5283 MALLOC_FAIL("hostname cache"); 5284 logerror("hostname cache disabled"); 5285 return; 5286 } 5287 5288 for (i = 0; i < hnc_size; i++) { 5289 hnc_cache[i].h = NULL; 5290 hnc_cache[i].next = hnc_cache + i + 1; 5291 } 5292 5293 hnc_cache[hnc_size - 1].next = NULL; 5294 hnc_freeq = hnc_cache; 5295 hnc_active = NULL; 5296 5297 DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry" 5298 " ttl:%d\n", mythreadno, hnc_size, hnc_ttl); 5299 } 5300 } 5301 5302 static host_list_t * 5303 hnc_lookup(struct netbuf *nbp, struct netconfig *ncp) 5304 { 5305 struct hostname_cache **hpp, *hp; 5306 time_t now; 5307 pthread_t mythreadno; 5308 5309 if (Debug) { 5310 mythreadno = pthread_self(); 5311 } 5312 5313 if (hnc_cache == NULL) { 5314 return (NULL); 5315 } 5316 5317 pthread_mutex_lock(&hnc_mutex); 5318 now = time(0); 5319 5320 for (hpp = &hnc_active; (hp = *hpp) != NULL; ) { 5321 DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n", 5322 mythreadno, hp->h, hp, hp->h->hl_hosts[0]); 5323 5324 if (hp->expire < now) { 5325 DPRINT2(9, "hnc_lookup(%u): purge %p\n", 5326 mythreadno, hp); 5327 /* Note: hnc_unreg changes *hpp */ 5328 hnc_unreg(hpp); 5329 continue; 5330 } 5331 5332 if (ncp == hp->ncp && same_addr(&hp->addr, nbp)) { 5333 /* 5334 * found! 5335 * Put the entry at the top. 5336 */ 5337 5338 if (hp != hnc_active) { 5339 /* unlink from active list */ 5340 *hpp = (*hpp)->next; 5341 /* push it onto the top */ 5342 hp->next = hnc_active; 5343 hnc_active = hp; 5344 } 5345 5346 pthread_mutex_lock(&hp->h->hl_mutex); 5347 hp->h->hl_refcnt++; 5348 pthread_mutex_unlock(&hp->h->hl_mutex); 5349 5350 DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n", 5351 mythreadno, hp->h, hp, hp->h->hl_hosts[0]); 5352 5353 pthread_mutex_unlock(&hnc_mutex); 5354 return (hp->h); 5355 } 5356 5357 hpp = &hp->next; 5358 } 5359 5360 pthread_mutex_unlock(&hnc_mutex); 5361 return (NULL); 5362 } 5363 5364 static void 5365 hnc_register(struct netbuf *nbp, struct netconfig *ncp, host_list_t *h) 5366 { 5367 struct hostname_cache **hpp, **tailp, *hp; 5368 void *addrbuf; 5369 time_t now; 5370 pthread_t mythreadno; 5371 5372 if (Debug) { 5373 mythreadno = pthread_self(); 5374 } 5375 5376 if (hnc_cache == NULL) { 5377 return; 5378 } 5379 5380 if ((addrbuf = malloc(nbp->len)) == NULL) { 5381 MALLOC_FAIL("pushing hostname cache"); 5382 return; 5383 } 5384 5385 pthread_mutex_lock(&hnc_mutex); 5386 5387 if (hnc_freeq == NULL) { 5388 DPRINT1(9, "hnc_register(%u): freeq empty\n", mythreadno); 5389 now = time(NULL); 5390 /* 5391 * first go through active list, and discard the 5392 * caches which has been invalid. 5393 */ 5394 for (hpp = &hnc_active; (hp = *hpp) != NULL; ) { 5395 tailp = hpp; 5396 5397 if (hp->expire < now) { 5398 DPRINT2(9, "hnc_register(%u): discard %p\n", 5399 mythreadno, hp); 5400 hnc_unreg(hpp); 5401 } else { 5402 hpp = &hp->next; 5403 } 5404 } 5405 5406 if (hnc_freeq == NULL) { 5407 DPRINT2(9, "hnc_register(%u): stealing %p\n", 5408 mythreadno, *tailp); 5409 /* 5410 * If still no inactive cache, then steal the least 5411 * active element. 5412 */ 5413 hnc_unreg(tailp); 5414 } 5415 } 5416 5417 hp = hnc_freeq; 5418 hnc_freeq = hnc_freeq->next; 5419 5420 /* push it on the top */ 5421 hp->next = hnc_active; 5422 hnc_active = hp; 5423 5424 (void) memcpy(addrbuf, nbp->buf, nbp->len); 5425 hp->addr.len = nbp->len; 5426 hp->addr.buf = addrbuf; 5427 hp->ncp = ncp; 5428 hp->h = h; 5429 hp->expire = time(NULL) + hnc_ttl; 5430 5431 /* 5432 * As far as cache is valid, corresponding host_list must 5433 * also be valid. Increments the refcnt to avoid freeing 5434 * host_list. 5435 */ 5436 h->hl_refcnt++; 5437 DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n", 5438 mythreadno, h, hp, hp->h->hl_hosts[0]); 5439 pthread_mutex_unlock(&hnc_mutex); 5440 } 5441 5442 static void 5443 hnc_unreg(struct hostname_cache **hpp) 5444 { 5445 struct hostname_cache *hp = *hpp; 5446 pthread_t mythreadno; 5447 5448 if (Debug) { 5449 mythreadno = pthread_self(); 5450 } 5451 5452 DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n", 5453 mythreadno, hp->h, hp, hp->h->hl_hosts[0]); 5454 free(hp->addr.buf); 5455 freehl(hp->h); 5456 5457 /* unlink from active list */ 5458 *hpp = (*hpp)->next; 5459 5460 /* put in freeq */ 5461 hp->next = hnc_freeq; 5462 hnc_freeq = hp; 5463 } 5464 5465 /* 5466 * Once this is called, error messages through logerror() will go to 5467 * the console immediately. Also, messages are queued into the tmpq 5468 * to be able to later put them into inputq. 5469 */ 5470 static void 5471 disable_errorlog() 5472 { 5473 dataq_init(&tmpq); 5474 5475 pthread_mutex_lock(&logerror_lock); 5476 interrorlog = 0; 5477 pthread_mutex_unlock(&logerror_lock); 5478 } 5479 5480 /* 5481 * Turn internal error messages to regular input stream. 5482 * All pending messages are pulled and pushed into the regular 5483 * input queue. 5484 */ 5485 static void 5486 enable_errorlog() 5487 { 5488 log_message_t *mp; 5489 5490 pthread_mutex_lock(&logerror_lock); 5491 interrorlog = 1; 5492 pthread_mutex_unlock(&logerror_lock); 5493 5494 /* 5495 * push all the pending messages into inputq. 5496 */ 5497 while (dataq_dequeue(&tmpq, (void **)&mp, 1) == 0) { 5498 (void) dataq_enqueue(&inputq, mp); 5499 } 5500 dataq_destroy(&tmpq); 5501 } 5502