1 /* 2 * Copyright (c) 1983, 1988, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 04/04/94"; 16 #endif /* not lint */ 17 18 /* 19 * syslogd -- log system messages 20 * 21 * This program implements a system log. It takes a series of lines. 22 * Each line may have a priority, signified as "<n>" as 23 * the first characters of the line. If this is 24 * not present, a default priority is used. 25 * 26 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 27 * cause it to reread its configuration file. 28 * 29 * Defined Constants: 30 * 31 * MAXLINE -- the maximimum line length that can be handled. 32 * DEFUPRI -- the default priority for user messages 33 * DEFSPRI -- the default priority for kernel messages 34 * 35 * Author: Eric Allman 36 * extensive changes by Ralph Campbell 37 * more extensive changes by Eric Allman (again) 38 */ 39 40 #define MAXLINE 1024 /* maximum line length */ 41 #define MAXSVLINE 120 /* maximum saved line length */ 42 #define DEFUPRI (LOG_USER|LOG_NOTICE) 43 #define DEFSPRI (LOG_KERN|LOG_CRIT) 44 #define TIMERINTVL 30 /* interval for checking flush, mark */ 45 46 #include <sys/param.h> 47 #include <sys/ioctl.h> 48 #include <sys/stat.h> 49 #include <sys/wait.h> 50 #include <sys/socket.h> 51 #include <sys/msgbuf.h> 52 #include <sys/uio.h> 53 #include <sys/un.h> 54 #include <sys/time.h> 55 #include <sys/resource.h> 56 57 #include <netinet/in.h> 58 #include <netdb.h> 59 #include <arpa/inet.h> 60 61 #include <ctype.h> 62 #include <errno.h> 63 #include <fcntl.h> 64 #include <setjmp.h> 65 #include <signal.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <unistd.h> 70 #include <utmp.h> 71 #include "pathnames.h" 72 73 #define SYSLOG_NAMES 74 #include <sys/syslog.h> 75 76 char *LogName = _PATH_LOG; 77 char *ConfFile = _PATH_LOGCONF; 78 char *PidFile = _PATH_LOGPID; 79 char ctty[] = _PATH_CONSOLE; 80 81 #define FDMASK(fd) (1 << (fd)) 82 83 #define dprintf if (Debug) printf 84 85 #define MAXUNAMES 20 /* maximum number of user names */ 86 87 /* 88 * Flags to logmsg(). 89 */ 90 91 #define IGN_CONS 0x001 /* don't print on console */ 92 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 93 #define ADDDATE 0x004 /* add a date to the message */ 94 #define MARK 0x008 /* this message is a mark */ 95 96 /* 97 * This structure represents the files that will have log 98 * copies printed. 99 */ 100 101 struct filed { 102 struct filed *f_next; /* next in linked list */ 103 short f_type; /* entry type, see below */ 104 short f_file; /* file descriptor */ 105 time_t f_time; /* time this was last written */ 106 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 107 union { 108 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 109 struct { 110 char f_hname[MAXHOSTNAMELEN+1]; 111 struct sockaddr_in f_addr; 112 } f_forw; /* forwarding address */ 113 char f_fname[MAXPATHLEN]; 114 } f_un; 115 char f_prevline[MAXSVLINE]; /* last message logged */ 116 char f_lasttime[16]; /* time of last occurrence */ 117 char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ 118 int f_prevpri; /* pri of f_prevline */ 119 int f_prevlen; /* length of f_prevline */ 120 int f_prevcount; /* repetition cnt of prevline */ 121 int f_repeatcount; /* number of "repeated" msgs */ 122 }; 123 124 /* 125 * Intervals at which we flush out "message repeated" messages, 126 * in seconds after previous message is logged. After each flush, 127 * we move to the next interval until we reach the largest. 128 */ 129 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 130 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 131 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 132 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 133 (f)->f_repeatcount = MAXREPEAT; \ 134 } 135 136 /* values for f_type */ 137 #define F_UNUSED 0 /* unused entry */ 138 #define F_FILE 1 /* regular file */ 139 #define F_TTY 2 /* terminal */ 140 #define F_CONSOLE 3 /* console terminal */ 141 #define F_FORW 4 /* remote machine */ 142 #define F_USERS 5 /* list of users */ 143 #define F_WALL 6 /* everyone logged on */ 144 145 char *TypeNames[7] = { 146 "UNUSED", "FILE", "TTY", "CONSOLE", 147 "FORW", "USERS", "WALL" 148 }; 149 150 struct filed *Files; 151 struct filed consfile; 152 153 int Debug; /* debug flag */ 154 char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ 155 char *LocalDomain; /* our local domain name */ 156 int InetInuse = 0; /* non-zero if INET sockets are being used */ 157 int finet; /* Internet datagram socket */ 158 int LogPort; /* port number for INET connections */ 159 int Initialized = 0; /* set when we have initialized ourselves */ 160 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 161 int MarkSeq = 0; /* mark sequence number */ 162 163 void cfline __P((char *, struct filed *)); 164 char *cvthname __P((struct sockaddr_in *)); 165 int decode __P((const char *, CODE *)); 166 void die __P((int)); 167 void domark __P((int)); 168 void fprintlog __P((struct filed *, int, char *)); 169 void init __P((int)); 170 void logerror __P((char *)); 171 void logmsg __P((int, char *, char *, int)); 172 void printline __P((char *, char *)); 173 void printsys __P((char *)); 174 void reapchild __P((int)); 175 char *ttymsg __P((struct iovec *, int, char *, int)); 176 void usage __P((void)); 177 void wallmsg __P((struct filed *, struct iovec *)); 178 179 int 180 main(argc, argv) 181 int argc; 182 char *argv[]; 183 { 184 int ch, funix, i, inetm, fklog, klogm, len; 185 struct sockaddr_un sunx, fromunix; 186 struct sockaddr_in sin, frominet; 187 FILE *fp; 188 char *p, line[MSG_BSIZE + 1]; 189 190 while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) 191 switch(ch) { 192 case 'd': /* debug */ 193 Debug++; 194 break; 195 case 'f': /* configuration file */ 196 ConfFile = optarg; 197 break; 198 case 'm': /* mark interval */ 199 MarkInterval = atoi(optarg) * 60; 200 break; 201 case 'p': /* path */ 202 LogName = optarg; 203 break; 204 case '?': 205 default: 206 usage(); 207 } 208 if ((argc -= optind) != 0) 209 usage(); 210 211 if (!Debug) 212 (void)daemon(0, 0); 213 else 214 setlinebuf(stdout); 215 216 consfile.f_type = F_CONSOLE; 217 (void)strcpy(consfile.f_un.f_fname, ctty); 218 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 219 if ((p = strchr(LocalHostName, '.')) != NULL) { 220 *p++ = '\0'; 221 LocalDomain = p; 222 } else 223 LocalDomain = ""; 224 (void)signal(SIGTERM, die); 225 (void)signal(SIGINT, Debug ? die : SIG_IGN); 226 (void)signal(SIGQUIT, Debug ? die : SIG_IGN); 227 (void)signal(SIGCHLD, reapchild); 228 (void)signal(SIGALRM, domark); 229 (void)alarm(TIMERINTVL); 230 (void)unlink(LogName); 231 232 #ifndef SUN_LEN 233 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 234 #endif 235 memset(&sunx, 0, sizeof(sunx)); 236 sunx.sun_family = AF_UNIX; 237 (void)strncpy(sunx.sun_path, LogName, sizeof(sunx.sun_path)); 238 funix = socket(AF_UNIX, SOCK_DGRAM, 0); 239 if (funix < 0 || 240 bind(funix, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 241 chmod(LogName, 0666) < 0) { 242 (void) sprintf(line, "cannot create %s", LogName); 243 logerror(line); 244 dprintf("cannot create %s (%d)\n", LogName, errno); 245 die(0); 246 } 247 finet = socket(AF_INET, SOCK_DGRAM, 0); 248 inetm = 0; 249 if (finet >= 0) { 250 struct servent *sp; 251 252 sp = getservbyname("syslog", "udp"); 253 if (sp == NULL) { 254 errno = 0; 255 logerror("syslog/udp: unknown service"); 256 die(0); 257 } 258 memset(&sin, 0, sizeof(sin)); 259 sin.sin_family = AF_INET; 260 sin.sin_port = LogPort = sp->s_port; 261 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 262 logerror("bind"); 263 if (!Debug) 264 die(0); 265 } else { 266 inetm = FDMASK(finet); 267 InetInuse = 1; 268 } 269 } 270 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) 271 klogm = FDMASK(fklog); 272 else { 273 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 274 klogm = 0; 275 } 276 277 /* tuck my process id away */ 278 fp = fopen(PidFile, "w"); 279 if (fp != NULL) { 280 fprintf(fp, "%d\n", getpid()); 281 (void) fclose(fp); 282 } 283 284 dprintf("off & running....\n"); 285 286 init(0); 287 (void)signal(SIGHUP, init); 288 289 for (;;) { 290 int nfds, readfds = FDMASK(funix) | inetm | klogm; 291 292 dprintf("readfds = %#x\n", readfds); 293 nfds = select(20, (fd_set *)&readfds, (fd_set *)NULL, 294 (fd_set *)NULL, (struct timeval *)NULL); 295 if (nfds == 0) 296 continue; 297 if (nfds < 0) { 298 if (errno != EINTR) 299 logerror("select"); 300 continue; 301 } 302 dprintf("got a message (%d, %#x)\n", nfds, readfds); 303 if (readfds & klogm) { 304 i = read(fklog, line, sizeof(line) - 1); 305 if (i > 0) { 306 line[i] = '\0'; 307 printsys(line); 308 } else if (i < 0 && errno != EINTR) { 309 logerror("klog"); 310 fklog = -1; 311 klogm = 0; 312 } 313 } 314 if (readfds & FDMASK(funix)) { 315 len = sizeof(fromunix); 316 i = recvfrom(funix, line, MAXLINE, 0, 317 (struct sockaddr *)&fromunix, &len); 318 if (i > 0) { 319 line[i] = '\0'; 320 printline(LocalHostName, line); 321 } else if (i < 0 && errno != EINTR) 322 logerror("recvfrom unix"); 323 } 324 if (readfds & inetm) { 325 len = sizeof(frominet); 326 i = recvfrom(finet, line, MAXLINE, 0, 327 (struct sockaddr *)&frominet, &len); 328 if (i > 0) { 329 line[i] = '\0'; 330 printline(cvthname(&frominet), line); 331 } else if (i < 0 && errno != EINTR) 332 logerror("recvfrom inet"); 333 } 334 } 335 } 336 337 void 338 usage() 339 { 340 341 (void)fprintf(stderr, 342 "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n"); 343 exit(1); 344 } 345 346 /* 347 * Take a raw input line, decode the message, and print the message 348 * on the appropriate log files. 349 */ 350 void 351 printline(hname, msg) 352 char *hname; 353 char *msg; 354 { 355 int c, pri; 356 char *p, *q, line[MAXLINE + 1]; 357 358 /* test for special codes */ 359 pri = DEFUPRI; 360 p = msg; 361 if (*p == '<') { 362 pri = 0; 363 while (isdigit(*++p)) 364 pri = 10 * pri + (*p - '0'); 365 if (*p == '>') 366 ++p; 367 } 368 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 369 pri = DEFUPRI; 370 371 /* don't allow users to log kernel messages */ 372 if (LOG_FAC(pri) == LOG_KERN) 373 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 374 375 q = line; 376 377 while ((c = *p++ & 0177) != '\0' && 378 q < &line[sizeof(line) - 1]) 379 if (iscntrl(c)) 380 if (c == '\n') 381 *q++ = ' '; 382 else if (c == '\t') 383 *q++ = '\t'; 384 else { 385 *q++ = '^'; 386 *q++ = c ^ 0100; 387 } 388 else 389 *q++ = c; 390 *q = '\0'; 391 392 logmsg(pri, line, hname, 0); 393 } 394 395 /* 396 * Take a raw input line from /dev/klog, split and format similar to syslog(). 397 */ 398 void 399 printsys(msg) 400 char *msg; 401 { 402 int c, pri, flags; 403 char *lp, *p, *q, line[MAXLINE + 1]; 404 405 (void)strcpy(line, "vmunix: "); 406 lp = line + strlen(line); 407 for (p = msg; *p != '\0'; ) { 408 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 409 pri = DEFSPRI; 410 if (*p == '<') { 411 pri = 0; 412 while (isdigit(*++p)) 413 pri = 10 * pri + (*p - '0'); 414 if (*p == '>') 415 ++p; 416 } else { 417 /* kernel printf's come out on console */ 418 flags |= IGN_CONS; 419 } 420 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 421 pri = DEFSPRI; 422 q = lp; 423 while (*p != '\0' && (c = *p++) != '\n' && 424 q < &line[MAXLINE]) 425 *q++ = c; 426 *q = '\0'; 427 logmsg(pri, line, LocalHostName, flags); 428 } 429 } 430 431 time_t now; 432 433 /* 434 * Log a message to the appropriate log files, users, etc. based on 435 * the priority. 436 */ 437 void 438 logmsg(pri, msg, from, flags) 439 int pri; 440 char *msg, *from; 441 int flags; 442 { 443 struct filed *f; 444 int fac, msglen, omask, prilev; 445 char *timestamp; 446 447 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", 448 pri, flags, from, msg); 449 450 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 451 452 /* 453 * Check to see if msg looks non-standard. 454 */ 455 msglen = strlen(msg); 456 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 457 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 458 flags |= ADDDATE; 459 460 (void)time(&now); 461 if (flags & ADDDATE) 462 timestamp = ctime(&now) + 4; 463 else { 464 timestamp = msg; 465 msg += 16; 466 msglen -= 16; 467 } 468 469 /* extract facility and priority level */ 470 if (flags & MARK) 471 fac = LOG_NFACILITIES; 472 else 473 fac = LOG_FAC(pri); 474 prilev = LOG_PRI(pri); 475 476 /* log the message to the particular outputs */ 477 if (!Initialized) { 478 f = &consfile; 479 f->f_file = open(ctty, O_WRONLY, 0); 480 481 if (f->f_file >= 0) { 482 fprintlog(f, flags, msg); 483 (void)close(f->f_file); 484 } 485 (void)sigsetmask(omask); 486 return; 487 } 488 for (f = Files; f; f = f->f_next) { 489 /* skip messages that are incorrect priority */ 490 if (f->f_pmask[fac] < prilev || 491 f->f_pmask[fac] == INTERNAL_NOPRI) 492 continue; 493 494 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 495 continue; 496 497 /* don't output marks to recently written files */ 498 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 499 continue; 500 501 /* 502 * suppress duplicate lines to this file 503 */ 504 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 505 !strcmp(msg, f->f_prevline) && 506 !strcmp(from, f->f_prevhost)) { 507 (void)strncpy(f->f_lasttime, timestamp, 15); 508 f->f_prevcount++; 509 dprintf("msg repeated %d times, %ld sec of %d\n", 510 f->f_prevcount, now - f->f_time, 511 repeatinterval[f->f_repeatcount]); 512 /* 513 * If domark would have logged this by now, 514 * flush it now (so we don't hold isolated messages), 515 * but back off so we'll flush less often 516 * in the future. 517 */ 518 if (now > REPEATTIME(f)) { 519 fprintlog(f, flags, (char *)NULL); 520 BACKOFF(f); 521 } 522 } else { 523 /* new line, save it */ 524 if (f->f_prevcount) 525 fprintlog(f, 0, (char *)NULL); 526 f->f_repeatcount = 0; 527 (void)strncpy(f->f_lasttime, timestamp, 15); 528 (void)strncpy(f->f_prevhost, from, 529 sizeof(f->f_prevhost)); 530 if (msglen < MAXSVLINE) { 531 f->f_prevlen = msglen; 532 f->f_prevpri = pri; 533 (void)strcpy(f->f_prevline, msg); 534 fprintlog(f, flags, (char *)NULL); 535 } else { 536 f->f_prevline[0] = 0; 537 f->f_prevlen = 0; 538 fprintlog(f, flags, msg); 539 } 540 } 541 } 542 (void)sigsetmask(omask); 543 } 544 545 void 546 fprintlog(f, flags, msg) 547 struct filed *f; 548 int flags; 549 char *msg; 550 { 551 struct iovec iov[6]; 552 struct iovec *v; 553 int l; 554 char line[MAXLINE + 1], repbuf[80], greetings[200]; 555 556 v = iov; 557 if (f->f_type == F_WALL) { 558 v->iov_base = greetings; 559 v->iov_len = sprintf(greetings, 560 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 561 f->f_prevhost, ctime(&now)); 562 v++; 563 v->iov_base = ""; 564 v->iov_len = 0; 565 v++; 566 } else { 567 v->iov_base = f->f_lasttime; 568 v->iov_len = 15; 569 v++; 570 v->iov_base = " "; 571 v->iov_len = 1; 572 v++; 573 } 574 v->iov_base = f->f_prevhost; 575 v->iov_len = strlen(v->iov_base); 576 v++; 577 v->iov_base = " "; 578 v->iov_len = 1; 579 v++; 580 581 if (msg) { 582 v->iov_base = msg; 583 v->iov_len = strlen(msg); 584 } else if (f->f_prevcount > 1) { 585 v->iov_base = repbuf; 586 v->iov_len = sprintf(repbuf, "last message repeated %d times", 587 f->f_prevcount); 588 } else { 589 v->iov_base = f->f_prevline; 590 v->iov_len = f->f_prevlen; 591 } 592 v++; 593 594 dprintf("Logging to %s", TypeNames[f->f_type]); 595 f->f_time = now; 596 597 switch (f->f_type) { 598 case F_UNUSED: 599 dprintf("\n"); 600 break; 601 602 case F_FORW: 603 dprintf(" %s\n", f->f_un.f_forw.f_hname); 604 l = sprintf(line, "<%d>%.15s %s", f->f_prevpri, 605 iov[0].iov_base, iov[4].iov_base); 606 if (l > MAXLINE) 607 l = MAXLINE; 608 if (sendto(finet, line, l, 0, 609 (struct sockaddr *)&f->f_un.f_forw.f_addr, 610 sizeof(f->f_un.f_forw.f_addr)) != l) { 611 int e = errno; 612 (void)close(f->f_file); 613 f->f_type = F_UNUSED; 614 errno = e; 615 logerror("sendto"); 616 } 617 break; 618 619 case F_CONSOLE: 620 if (flags & IGN_CONS) { 621 dprintf(" (ignored)\n"); 622 break; 623 } 624 /* FALLTHROUGH */ 625 626 case F_TTY: 627 case F_FILE: 628 dprintf(" %s\n", f->f_un.f_fname); 629 if (f->f_type != F_FILE) { 630 v->iov_base = "\r\n"; 631 v->iov_len = 2; 632 } else { 633 v->iov_base = "\n"; 634 v->iov_len = 1; 635 } 636 again: 637 if (writev(f->f_file, iov, 6) < 0) { 638 int e = errno; 639 (void)close(f->f_file); 640 /* 641 * Check for errors on TTY's due to loss of tty 642 */ 643 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 644 f->f_file = open(f->f_un.f_fname, 645 O_WRONLY|O_APPEND, 0); 646 if (f->f_file < 0) { 647 f->f_type = F_UNUSED; 648 logerror(f->f_un.f_fname); 649 } else 650 goto again; 651 } else { 652 f->f_type = F_UNUSED; 653 errno = e; 654 logerror(f->f_un.f_fname); 655 } 656 } else if (flags & SYNC_FILE) 657 (void)fsync(f->f_file); 658 break; 659 660 case F_USERS: 661 case F_WALL: 662 dprintf("\n"); 663 v->iov_base = "\r\n"; 664 v->iov_len = 2; 665 wallmsg(f, iov); 666 break; 667 } 668 f->f_prevcount = 0; 669 } 670 671 /* 672 * WALLMSG -- Write a message to the world at large 673 * 674 * Write the specified message to either the entire 675 * world, or a list of approved users. 676 */ 677 void 678 wallmsg(f, iov) 679 struct filed *f; 680 struct iovec *iov; 681 { 682 static int reenter; /* avoid calling ourselves */ 683 FILE *uf; 684 struct utmp ut; 685 int i; 686 char *p; 687 char line[sizeof(ut.ut_line) + 1]; 688 689 if (reenter++) 690 return; 691 if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { 692 logerror(_PATH_UTMP); 693 reenter = 0; 694 return; 695 } 696 /* NOSTRICT */ 697 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 698 if (ut.ut_name[0] == '\0') 699 continue; 700 strncpy(line, ut.ut_line, sizeof(ut.ut_line)); 701 line[sizeof(ut.ut_line)] = '\0'; 702 if (f->f_type == F_WALL) { 703 if ((p = ttymsg(iov, 6, line, 60*5)) != NULL) { 704 errno = 0; /* already in msg */ 705 logerror(p); 706 } 707 continue; 708 } 709 /* should we send the message to this user? */ 710 for (i = 0; i < MAXUNAMES; i++) { 711 if (!f->f_un.f_uname[i][0]) 712 break; 713 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 714 UT_NAMESIZE)) { 715 if ((p = ttymsg(iov, 6, line, 60*5)) != NULL) { 716 errno = 0; /* already in msg */ 717 logerror(p); 718 } 719 break; 720 } 721 } 722 } 723 (void)fclose(uf); 724 reenter = 0; 725 } 726 727 void 728 reapchild(signo) 729 int signo; 730 { 731 union wait status; 732 733 while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0) 734 ; 735 } 736 737 /* 738 * Return a printable representation of a host address. 739 */ 740 char * 741 cvthname(f) 742 struct sockaddr_in *f; 743 { 744 struct hostent *hp; 745 char *p; 746 747 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); 748 749 if (f->sin_family != AF_INET) { 750 dprintf("Malformed from address\n"); 751 return ("???"); 752 } 753 hp = gethostbyaddr((char *)&f->sin_addr, 754 sizeof(struct in_addr), f->sin_family); 755 if (hp == 0) { 756 dprintf("Host name for your address (%s) unknown\n", 757 inet_ntoa(f->sin_addr)); 758 return (inet_ntoa(f->sin_addr)); 759 } 760 if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) 761 *p = '\0'; 762 return (hp->h_name); 763 } 764 765 void 766 domark(signo) 767 int signo; 768 { 769 struct filed *f; 770 771 now = time((time_t *)NULL); 772 MarkSeq += TIMERINTVL; 773 if (MarkSeq >= MarkInterval) { 774 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 775 MarkSeq = 0; 776 } 777 778 for (f = Files; f; f = f->f_next) { 779 if (f->f_prevcount && now >= REPEATTIME(f)) { 780 dprintf("flush %s: repeated %d times, %d sec.\n", 781 TypeNames[f->f_type], f->f_prevcount, 782 repeatinterval[f->f_repeatcount]); 783 fprintlog(f, 0, (char *)NULL); 784 BACKOFF(f); 785 } 786 } 787 (void)alarm(TIMERINTVL); 788 } 789 790 /* 791 * Print syslogd errors some place. 792 */ 793 void 794 logerror(type) 795 char *type; 796 { 797 char buf[100]; 798 799 if (errno) 800 (void)snprintf(buf, 801 sizeof(buf), "syslogd: %s: %s", type, strerror(errno)); 802 else 803 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 804 errno = 0; 805 dprintf("%s\n", buf); 806 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 807 } 808 809 void 810 die(signo) 811 int signo; 812 { 813 struct filed *f; 814 char buf[100]; 815 816 for (f = Files; f != NULL; f = f->f_next) { 817 /* flush any pending output */ 818 if (f->f_prevcount) 819 fprintlog(f, 0, (char *)NULL); 820 } 821 if (signo) { 822 dprintf("syslogd: exiting on signal %d\n", signo); 823 (void)sprintf(buf, "exiting on signal %d", signo); 824 errno = 0; 825 logerror(buf); 826 } 827 (void)unlink(LogName); 828 exit(0); 829 } 830 831 /* 832 * INIT -- Initialize syslogd from configuration table 833 */ 834 void 835 init(signo) 836 int signo; 837 { 838 int i; 839 FILE *cf; 840 struct filed *f, *next, **nextp; 841 char *p; 842 char cline[LINE_MAX]; 843 844 dprintf("init\n"); 845 846 /* 847 * Close all open log files. 848 */ 849 Initialized = 0; 850 for (f = Files; f != NULL; f = next) { 851 /* flush any pending output */ 852 if (f->f_prevcount) 853 fprintlog(f, 0, (char *)NULL); 854 855 switch (f->f_type) { 856 case F_FILE: 857 case F_TTY: 858 case F_CONSOLE: 859 case F_FORW: 860 (void)close(f->f_file); 861 break; 862 } 863 next = f->f_next; 864 free((char *)f); 865 } 866 Files = NULL; 867 nextp = &Files; 868 869 /* open the configuration file */ 870 if ((cf = fopen(ConfFile, "r")) == NULL) { 871 dprintf("cannot open %s\n", ConfFile); 872 *nextp = (struct filed *)calloc(1, sizeof(*f)); 873 cfline("*.ERR\t/dev/console", *nextp); 874 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 875 cfline("*.PANIC\t*", (*nextp)->f_next); 876 Initialized = 1; 877 return; 878 } 879 880 /* 881 * Foreach line in the conf table, open that file. 882 */ 883 f = NULL; 884 while (fgets(cline, sizeof(cline), cf) != NULL) { 885 /* 886 * check for end-of-section, comments, strip off trailing 887 * spaces and newline character. 888 */ 889 for (p = cline; isspace(*p); ++p) 890 continue; 891 if (*p == NULL || *p == '#') 892 continue; 893 for (p = strchr(cline, '\0'); isspace(*--p);) 894 continue; 895 *++p = '\0'; 896 f = (struct filed *)calloc(1, sizeof(*f)); 897 *nextp = f; 898 nextp = &f->f_next; 899 cfline(cline, f); 900 } 901 902 /* close the configuration file */ 903 (void)fclose(cf); 904 905 Initialized = 1; 906 907 if (Debug) { 908 for (f = Files; f; f = f->f_next) { 909 for (i = 0; i <= LOG_NFACILITIES; i++) 910 if (f->f_pmask[i] == INTERNAL_NOPRI) 911 printf("X "); 912 else 913 printf("%d ", f->f_pmask[i]); 914 printf("%s: ", TypeNames[f->f_type]); 915 switch (f->f_type) { 916 case F_FILE: 917 case F_TTY: 918 case F_CONSOLE: 919 printf("%s", f->f_un.f_fname); 920 break; 921 922 case F_FORW: 923 printf("%s", f->f_un.f_forw.f_hname); 924 break; 925 926 case F_USERS: 927 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 928 printf("%s, ", f->f_un.f_uname[i]); 929 break; 930 } 931 printf("\n"); 932 } 933 } 934 935 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 936 dprintf("syslogd: restarted\n"); 937 } 938 939 /* 940 * Crack a configuration file line 941 */ 942 void 943 cfline(line, f) 944 char *line; 945 struct filed *f; 946 { 947 struct hostent *hp; 948 int i, pri; 949 char *bp, *p, *q; 950 char buf[MAXLINE], ebuf[100]; 951 952 dprintf("cfline(%s)\n", line); 953 954 errno = 0; /* keep strerror() stuff out of logerror messages */ 955 956 /* clear out file entry */ 957 memset(f, 0, sizeof(*f)); 958 for (i = 0; i <= LOG_NFACILITIES; i++) 959 f->f_pmask[i] = INTERNAL_NOPRI; 960 961 /* scan through the list of selectors */ 962 for (p = line; *p && *p != '\t';) { 963 964 /* find the end of this facility name list */ 965 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 966 continue; 967 968 /* collect priority name */ 969 for (bp = buf; *q && !strchr("\t,;", *q); ) 970 *bp++ = *q++; 971 *bp = '\0'; 972 973 /* skip cruft */ 974 while (strchr(", ;", *q)) 975 q++; 976 977 /* decode priority name */ 978 if (*buf == '*') 979 pri = LOG_PRIMASK + 1; 980 else { 981 pri = decode(buf, prioritynames); 982 if (pri < 0) { 983 (void)sprintf(ebuf, 984 "unknown priority name \"%s\"", buf); 985 logerror(ebuf); 986 return; 987 } 988 } 989 990 /* scan facilities */ 991 while (*p && !strchr("\t.;", *p)) { 992 for (bp = buf; *p && !strchr("\t,;.", *p); ) 993 *bp++ = *p++; 994 *bp = '\0'; 995 if (*buf == '*') 996 for (i = 0; i < LOG_NFACILITIES; i++) 997 f->f_pmask[i] = pri; 998 else { 999 i = decode(buf, facilitynames); 1000 if (i < 0) { 1001 (void)sprintf(ebuf, 1002 "unknown facility name \"%s\"", 1003 buf); 1004 logerror(ebuf); 1005 return; 1006 } 1007 f->f_pmask[i >> 3] = pri; 1008 } 1009 while (*p == ',' || *p == ' ') 1010 p++; 1011 } 1012 1013 p = q; 1014 } 1015 1016 /* skip to action part */ 1017 while (*p == '\t') 1018 p++; 1019 1020 switch (*p) 1021 { 1022 case '@': 1023 if (!InetInuse) 1024 break; 1025 (void)strcpy(f->f_un.f_forw.f_hname, ++p); 1026 hp = gethostbyname(p); 1027 if (hp == NULL) { 1028 extern int h_errno; 1029 1030 logerror(hstrerror(h_errno)); 1031 break; 1032 } 1033 memset(&f->f_un.f_forw.f_addr, 0, 1034 sizeof(f->f_un.f_forw.f_addr)); 1035 f->f_un.f_forw.f_addr.sin_family = AF_INET; 1036 f->f_un.f_forw.f_addr.sin_port = LogPort; 1037 memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); 1038 f->f_type = F_FORW; 1039 break; 1040 1041 case '/': 1042 (void)strcpy(f->f_un.f_fname, p); 1043 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1044 f->f_file = F_UNUSED; 1045 logerror(p); 1046 break; 1047 } 1048 if (isatty(f->f_file)) 1049 f->f_type = F_TTY; 1050 else 1051 f->f_type = F_FILE; 1052 if (strcmp(p, ctty) == 0) 1053 f->f_type = F_CONSOLE; 1054 break; 1055 1056 case '*': 1057 f->f_type = F_WALL; 1058 break; 1059 1060 default: 1061 for (i = 0; i < MAXUNAMES && *p; i++) { 1062 for (q = p; *q && *q != ','; ) 1063 q++; 1064 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1065 if ((q - p) > UT_NAMESIZE) 1066 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1067 else 1068 f->f_un.f_uname[i][q - p] = '\0'; 1069 while (*q == ',' || *q == ' ') 1070 q++; 1071 p = q; 1072 } 1073 f->f_type = F_USERS; 1074 break; 1075 } 1076 } 1077 1078 1079 /* 1080 * Decode a symbolic name to a numeric value 1081 */ 1082 int 1083 decode(name, codetab) 1084 const char *name; 1085 CODE *codetab; 1086 { 1087 CODE *c; 1088 char *p, buf[40]; 1089 1090 if (isdigit(*name)) 1091 return (atoi(name)); 1092 1093 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1094 if (isupper(*name)) 1095 *p = tolower(*name); 1096 else 1097 *p = *name; 1098 } 1099 *p = '\0'; 1100 for (c = codetab; c->c_name; c++) 1101 if (!strcmp(buf, c->c_name)) 1102 return (c->c_val); 1103 1104 return (-1); 1105 } 1106