1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 8.102 (Berkeley) 08/21/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include "pathnames.h" 15 # include <sys/ioctl.h> 16 # include <sys/param.h> 17 # include <netdb.h> 18 # include <pwd.h> 19 20 /* 21 ** CONF.C -- Sendmail Configuration Tables. 22 ** 23 ** Defines the configuration of this installation. 24 ** 25 ** Configuration Variables: 26 ** HdrInfo -- a table describing well-known header fields. 27 ** Each entry has the field name and some flags, 28 ** which are described in sendmail.h. 29 ** 30 ** Notes: 31 ** I have tried to put almost all the reasonable 32 ** configuration information into the configuration 33 ** file read at runtime. My intent is that anything 34 ** here is a function of the version of UNIX you 35 ** are running, or is really static -- for example 36 ** the headers are a superset of widely used 37 ** protocols. If you find yourself playing with 38 ** this file too much, you may be making a mistake! 39 */ 40 41 42 43 44 /* 45 ** Header info table 46 ** Final (null) entry contains the flags used for any other field. 47 ** 48 ** Not all of these are actually handled specially by sendmail 49 ** at this time. They are included as placeholders, to let 50 ** you know that "someday" I intend to have sendmail do 51 ** something with them. 52 */ 53 54 struct hdrinfo HdrInfo[] = 55 { 56 /* originator fields, most to least significant */ 57 "resent-sender", H_FROM|H_RESENT, 58 "resent-from", H_FROM|H_RESENT, 59 "resent-reply-to", H_FROM|H_RESENT, 60 "sender", H_FROM, 61 "from", H_FROM, 62 "reply-to", H_FROM, 63 "full-name", H_ACHECK, 64 "return-receipt-to", H_FROM|H_RECEIPTTO, 65 "errors-to", H_FROM|H_ERRORSTO, 66 67 /* destination fields */ 68 "to", H_RCPT, 69 "resent-to", H_RCPT|H_RESENT, 70 "cc", H_RCPT, 71 "resent-cc", H_RCPT|H_RESENT, 72 "bcc", H_RCPT|H_ACHECK, 73 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 74 "apparently-to", H_RCPT, 75 76 /* message identification and control */ 77 "message-id", 0, 78 "resent-message-id", H_RESENT, 79 "message", H_EOH, 80 "text", H_EOH, 81 82 /* date fields */ 83 "date", 0, 84 "resent-date", H_RESENT, 85 86 /* trace fields */ 87 "received", H_TRACE|H_FORCE, 88 "x400-received", H_TRACE|H_FORCE, 89 "via", H_TRACE|H_FORCE, 90 "mail-from", H_TRACE|H_FORCE, 91 92 /* miscellaneous fields */ 93 "comments", H_FORCE, 94 "return-path", H_FORCE|H_ACHECK, 95 "content-transfer-encoding", H_CTE, 96 97 NULL, 0, 98 }; 99 100 101 102 /* 103 ** Location of system files/databases/etc. 104 */ 105 106 char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 107 108 109 110 /* 111 ** Privacy values 112 */ 113 114 struct prival PrivacyValues[] = 115 { 116 "public", PRIV_PUBLIC, 117 "needmailhelo", PRIV_NEEDMAILHELO, 118 "needexpnhelo", PRIV_NEEDEXPNHELO, 119 "needvrfyhelo", PRIV_NEEDVRFYHELO, 120 "noexpn", PRIV_NOEXPN, 121 "novrfy", PRIV_NOVRFY, 122 "restrictmailq", PRIV_RESTRICTMAILQ, 123 "restrictqrun", PRIV_RESTRICTQRUN, 124 "authwarnings", PRIV_AUTHWARNINGS, 125 "noreceipts", PRIV_NORECEIPTS, 126 "goaway", PRIV_GOAWAY, 127 NULL, 0, 128 }; 129 130 131 132 /* 133 ** Miscellaneous stuff. 134 */ 135 136 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 137 /* 138 ** SETDEFAULTS -- set default values 139 ** 140 ** Because of the way freezing is done, these must be initialized 141 ** using direct code. 142 ** 143 ** Parameters: 144 ** e -- the default envelope. 145 ** 146 ** Returns: 147 ** none. 148 ** 149 ** Side Effects: 150 ** Initializes a bunch of global variables to their 151 ** default values. 152 */ 153 154 #define DAYS * 24 * 60 * 60 155 156 setdefaults(e) 157 register ENVELOPE *e; 158 { 159 int i; 160 161 SpaceSub = ' '; /* option B */ 162 QueueLA = 8; /* option x */ 163 RefuseLA = 12; /* option X */ 164 WkRecipFact = 30000L; /* option y */ 165 WkClassFact = 1800L; /* option z */ 166 WkTimeFact = 90000L; /* option Z */ 167 QueueFactor = WkRecipFact * 20; /* option q */ 168 FileMode = (RealUid != geteuid()) ? 0644 : 0600; 169 /* option F */ 170 DefUid = 1; /* option u */ 171 DefGid = 1; /* option g */ 172 CheckpointInterval = 10; /* option C */ 173 MaxHopCount = 25; /* option h */ 174 e->e_sendmode = SM_FORK; /* option d */ 175 e->e_errormode = EM_PRINT; /* option e */ 176 SevenBitInput = FALSE; /* option 7 */ 177 MaxMciCache = 1; /* option k */ 178 MciCacheTimeout = 300; /* option K */ 179 LogLevel = 9; /* option L */ 180 settimeouts(NULL); /* option r */ 181 PrivacyFlags = 0; /* option p */ 182 MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */ 183 for (i = 0; i < MAXTOCLASS; i++) 184 { 185 TimeOuts.to_q_return[i] = 5 DAYS; /* option T */ 186 TimeOuts.to_q_warning[i] = 0; /* option T */ 187 } 188 setdefuser(); 189 setupmaps(); 190 setupmailers(); 191 } 192 193 194 /* 195 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 196 */ 197 198 setdefuser() 199 { 200 struct passwd *defpwent; 201 static char defuserbuf[40]; 202 203 DefUser = defuserbuf; 204 if ((defpwent = getpwuid(DefUid)) != NULL) 205 strcpy(defuserbuf, defpwent->pw_name); 206 else 207 strcpy(defuserbuf, "nobody"); 208 } 209 /* 210 ** HOST_MAP_INIT -- initialize host class structures 211 */ 212 213 bool 214 host_map_init(map, args) 215 MAP *map; 216 char *args; 217 { 218 register char *p = args; 219 220 for (;;) 221 { 222 while (isascii(*p) && isspace(*p)) 223 p++; 224 if (*p != '-') 225 break; 226 switch (*++p) 227 { 228 case 'a': 229 map->map_app = ++p; 230 break; 231 } 232 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 233 p++; 234 if (*p != '\0') 235 *p++ = '\0'; 236 } 237 if (map->map_app != NULL) 238 map->map_app = newstr(map->map_app); 239 return TRUE; 240 } 241 /* 242 ** SETUPMAILERS -- initialize default mailers 243 */ 244 245 setupmailers() 246 { 247 char buf[100]; 248 249 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 250 makemailer(buf); 251 252 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 253 makemailer(buf); 254 255 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 256 makemailer(buf); 257 } 258 /* 259 ** SETUPMAPS -- set up map classes 260 */ 261 262 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 263 { \ 264 extern bool parse __P((MAP *, char *)); \ 265 extern bool open __P((MAP *, int)); \ 266 extern void close __P((MAP *)); \ 267 extern char *lookup __P((MAP *, char *, char **, int *)); \ 268 extern void store __P((MAP *, char *, char *)); \ 269 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 270 s->s_mapclass.map_cname = name; \ 271 s->s_mapclass.map_ext = ext; \ 272 s->s_mapclass.map_cflags = flags; \ 273 s->s_mapclass.map_parse = parse; \ 274 s->s_mapclass.map_open = open; \ 275 s->s_mapclass.map_close = close; \ 276 s->s_mapclass.map_lookup = lookup; \ 277 s->s_mapclass.map_store = store; \ 278 } 279 280 setupmaps() 281 { 282 register STAB *s; 283 284 #ifdef NEWDB 285 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 286 map_parseargs, hash_map_open, db_map_close, 287 db_map_lookup, db_map_store); 288 289 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 290 map_parseargs, bt_map_open, db_map_close, 291 db_map_lookup, db_map_store); 292 #endif 293 294 #ifdef NDBM 295 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 296 map_parseargs, ndbm_map_open, ndbm_map_close, 297 ndbm_map_lookup, ndbm_map_store); 298 #endif 299 300 #ifdef NIS 301 MAPDEF("nis", NULL, MCF_ALIASOK, 302 map_parseargs, nis_map_open, null_map_close, 303 nis_map_lookup, null_map_store); 304 #endif 305 306 #ifdef NISPLUS 307 MAPDEF("nisplus", NULL, MCF_ALIASOK, 308 map_parseargs, nisplus_map_open, null_map_close, 309 nisplus_map_lookup, null_map_store); 310 #endif 311 312 #if NAMED_BIND 313 # if 0 314 MAPDEF("dns", NULL, 0, 315 dns_map_init, null_map_open, null_map_close, 316 dns_map_lookup, null_map_store); 317 # endif 318 319 /* old name for back compat */ 320 MAPDEF("host", NULL, 0, 321 host_map_init, null_map_open, null_map_close, 322 host_map_lookup, null_map_store); 323 #endif 324 325 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 326 map_parseargs, stab_map_open, null_map_close, 327 stab_map_lookup, stab_map_store); 328 329 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 330 map_parseargs, impl_map_open, impl_map_close, 331 impl_map_lookup, impl_map_store); 332 333 /* access to system passwd file */ 334 MAPDEF("user", NULL, 0, 335 map_parseargs, user_map_open, null_map_close, 336 user_map_lookup, null_map_store); 337 338 /* dequote map */ 339 MAPDEF("dequote", NULL, 0, 340 dequote_init, null_map_open, null_map_close, 341 dequote_map, null_map_store); 342 343 #if 0 344 # ifdef USERDB 345 /* user database */ 346 MAPDEF("udb", ".db", 0, 347 udb_map_parse, null_map_open, null_map_close, 348 udb_map_lookup, null_map_store); 349 # endif 350 #endif 351 352 /* sequenced maps */ 353 MAPDEF("sequence", NULL, MCF_ALIASOK, 354 seq_map_parse, null_map_open, null_map_close, 355 seq_map_lookup, seq_map_store); 356 } 357 358 #undef MAPDEF 359 /* 360 ** INITHOSTMAPS -- initial host-dependent maps 361 ** 362 ** This should act as an interface to any local service switch 363 ** provided by the host operating system. 364 ** 365 ** Parameters: 366 ** none 367 ** 368 ** Returns: 369 ** none 370 ** 371 ** Side Effects: 372 ** Should define maps "host" and "passwd" as necessary 373 ** for this OS. If they are not defined, they will get 374 ** a default value later. It should check to make sure 375 ** they are not defined first, since it's possible that 376 ** the config file has provided an override. 377 */ 378 379 void 380 inithostmaps() 381 { 382 #ifdef SOLARIS 383 #endif 384 } 385 /* 386 ** USERNAME -- return the user id of the logged in user. 387 ** 388 ** Parameters: 389 ** none. 390 ** 391 ** Returns: 392 ** The login name of the logged in user. 393 ** 394 ** Side Effects: 395 ** none. 396 ** 397 ** Notes: 398 ** The return value is statically allocated. 399 */ 400 401 char * 402 username() 403 { 404 static char *myname = NULL; 405 extern char *getlogin(); 406 register struct passwd *pw; 407 408 /* cache the result */ 409 if (myname == NULL) 410 { 411 myname = getlogin(); 412 if (myname == NULL || myname[0] == '\0') 413 { 414 pw = getpwuid(RealUid); 415 if (pw != NULL) 416 myname = newstr(pw->pw_name); 417 } 418 else 419 { 420 uid_t uid = RealUid; 421 422 myname = newstr(myname); 423 if ((pw = getpwnam(myname)) == NULL || 424 (uid != 0 && uid != pw->pw_uid)) 425 { 426 pw = getpwuid(uid); 427 if (pw != NULL) 428 myname = newstr(pw->pw_name); 429 } 430 } 431 if (myname == NULL || myname[0] == '\0') 432 { 433 syserr("554 Who are you?"); 434 myname = "postmaster"; 435 } 436 } 437 438 return (myname); 439 } 440 /* 441 ** TTYPATH -- Get the path of the user's tty 442 ** 443 ** Returns the pathname of the user's tty. Returns NULL if 444 ** the user is not logged in or if s/he has write permission 445 ** denied. 446 ** 447 ** Parameters: 448 ** none 449 ** 450 ** Returns: 451 ** pathname of the user's tty. 452 ** NULL if not logged in or write permission denied. 453 ** 454 ** Side Effects: 455 ** none. 456 ** 457 ** WARNING: 458 ** Return value is in a local buffer. 459 ** 460 ** Called By: 461 ** savemail 462 */ 463 464 char * 465 ttypath() 466 { 467 struct stat stbuf; 468 register char *pathn; 469 extern char *ttyname(); 470 extern char *getlogin(); 471 472 /* compute the pathname of the controlling tty */ 473 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 474 (pathn = ttyname(0)) == NULL) 475 { 476 errno = 0; 477 return (NULL); 478 } 479 480 /* see if we have write permission */ 481 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 482 { 483 errno = 0; 484 return (NULL); 485 } 486 487 /* see if the user is logged in */ 488 if (getlogin() == NULL) 489 return (NULL); 490 491 /* looks good */ 492 return (pathn); 493 } 494 /* 495 ** CHECKCOMPAT -- check for From and To person compatible. 496 ** 497 ** This routine can be supplied on a per-installation basis 498 ** to determine whether a person is allowed to send a message. 499 ** This allows restriction of certain types of internet 500 ** forwarding or registration of users. 501 ** 502 ** If the hosts are found to be incompatible, an error 503 ** message should be given using "usrerr" and 0 should 504 ** be returned. 505 ** 506 ** EF_NORETURN can be set in e->e_flags to suppress the return-to-sender 507 ** function; this should be done on huge messages. 508 ** 509 ** Parameters: 510 ** to -- the person being sent to. 511 ** 512 ** Returns: 513 ** an exit status 514 ** 515 ** Side Effects: 516 ** none (unless you include the usrerr stuff) 517 */ 518 519 checkcompat(to, e) 520 register ADDRESS *to; 521 register ENVELOPE *e; 522 { 523 # ifdef lint 524 if (to == NULL) 525 to++; 526 # endif /* lint */ 527 528 if (tTd(49, 1)) 529 printf("checkcompat(to=%s, from=%s)\n", 530 to->q_paddr, e->e_from.q_paddr); 531 532 # ifdef EXAMPLE_CODE 533 /* this code is intended as an example only */ 534 register STAB *s; 535 536 s = stab("arpa", ST_MAILER, ST_FIND); 537 if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 && 538 to->q_mailer == s->s_mailer) 539 { 540 usrerr("553 No ARPA mail through this machine: see your system administration"); 541 /* e->e_flags |= EF_NORETURN; to supress return copy */ 542 return (EX_UNAVAILABLE); 543 } 544 # endif /* EXAMPLE_CODE */ 545 return (EX_OK); 546 } 547 /* 548 ** SETSIGNAL -- set a signal handler 549 ** 550 ** This is essentially old BSD "signal(3)". 551 */ 552 553 sigfunc_t 554 setsignal(sig, handler) 555 int sig; 556 sigfunc_t handler; 557 { 558 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE) 559 return signal(sig, handler); 560 #else 561 struct sigaction n, o; 562 563 bzero(&n, sizeof n); 564 n.sa_handler = handler; 565 # ifdef SA_RESTART 566 n.sa_flags = SA_RESTART; 567 # endif 568 if (sigaction(sig, &n, &o) < 0) 569 return SIG_ERR; 570 return o.sa_handler; 571 #endif 572 } 573 /* 574 ** HOLDSIGS -- arrange to hold all signals 575 ** 576 ** Parameters: 577 ** none. 578 ** 579 ** Returns: 580 ** none. 581 ** 582 ** Side Effects: 583 ** Arranges that signals are held. 584 */ 585 586 holdsigs() 587 { 588 } 589 /* 590 ** RLSESIGS -- arrange to release all signals 591 ** 592 ** This undoes the effect of holdsigs. 593 ** 594 ** Parameters: 595 ** none. 596 ** 597 ** Returns: 598 ** none. 599 ** 600 ** Side Effects: 601 ** Arranges that signals are released. 602 */ 603 604 rlsesigs() 605 { 606 } 607 /* 608 ** INIT_MD -- do machine dependent initializations 609 ** 610 ** Systems that have global modes that should be set should do 611 ** them here rather than in main. 612 */ 613 614 #ifdef _AUX_SOURCE 615 # include <compat.h> 616 #endif 617 618 init_md(argc, argv) 619 int argc; 620 char **argv; 621 { 622 #ifdef _AUX_SOURCE 623 setcompat(getcompat() | COMPAT_BSDPROT); 624 #endif 625 } 626 /* 627 ** GETLA -- get the current load average 628 ** 629 ** This code stolen from la.c. 630 ** 631 ** Parameters: 632 ** none. 633 ** 634 ** Returns: 635 ** The current load average as an integer. 636 ** 637 ** Side Effects: 638 ** none. 639 */ 640 641 /* try to guess what style of load average we have */ 642 #define LA_ZERO 1 /* always return load average as zero */ 643 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 644 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 645 #define LA_SUBR 4 /* call getloadavg */ 646 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 647 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 648 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */ 649 650 /* do guesses based on general OS type */ 651 #ifndef LA_TYPE 652 # define LA_TYPE LA_ZERO 653 #endif 654 655 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 656 657 #include <nlist.h> 658 659 #ifndef LA_AVENRUN 660 # ifdef SYSTEM5 661 # define LA_AVENRUN "avenrun" 662 # else 663 # define LA_AVENRUN "_avenrun" 664 # endif 665 #endif 666 667 /* _PATH_UNIX should be defined in <paths.h> */ 668 #ifndef _PATH_UNIX 669 # if defined(SYSTEM5) 670 # define _PATH_UNIX "/unix" 671 # else 672 # define _PATH_UNIX "/vmunix" 673 # endif 674 #endif 675 676 struct nlist Nl[] = 677 { 678 { LA_AVENRUN }, 679 #define X_AVENRUN 0 680 { 0 }, 681 }; 682 683 #ifndef FSHIFT 684 # if defined(unixpc) 685 # define FSHIFT 5 686 # endif 687 688 # if defined(__alpha) || defined(IRIX) 689 # define FSHIFT 10 690 # endif 691 #endif 692 693 #ifndef FSHIFT 694 # define FSHIFT 8 695 #endif 696 697 #ifndef FSCALE 698 # define FSCALE (1 << FSHIFT) 699 #endif 700 701 getla() 702 { 703 static int kmem = -1; 704 #if LA_TYPE == LA_INT 705 long avenrun[3]; 706 #else 707 # if LA_TYPE == LA_SHORT 708 short avenrun[3]; 709 # else 710 double avenrun[3]; 711 # endif 712 #endif 713 extern off_t lseek(); 714 extern int errno; 715 716 if (kmem < 0) 717 { 718 kmem = open("/dev/kmem", 0, 0); 719 if (kmem < 0) 720 { 721 if (tTd(3, 1)) 722 printf("getla: open(/dev/kmem): %s\n", 723 errstring(errno)); 724 return (-1); 725 } 726 (void) fcntl(kmem, F_SETFD, 1); 727 if (nlist(_PATH_UNIX, Nl) < 0) 728 { 729 if (tTd(3, 1)) 730 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 731 errstring(errno)); 732 return (-1); 733 } 734 if (Nl[X_AVENRUN].n_value == 0) 735 { 736 if (tTd(3, 1)) 737 printf("getla: nlist(%s, %s) ==> 0\n", 738 _PATH_UNIX, LA_AVENRUN); 739 return (-1); 740 } 741 #ifdef NAMELISTMASK 742 Nl[X_AVENRUN].n_value &= NAMELISTMASK; 743 #endif 744 } 745 if (tTd(3, 20)) 746 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 747 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 748 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 749 { 750 /* thank you Ian */ 751 if (tTd(3, 1)) 752 printf("getla: lseek or read: %s\n", errstring(errno)); 753 return (-1); 754 } 755 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 756 if (tTd(3, 5)) 757 { 758 printf("getla: avenrun = %d", avenrun[0]); 759 if (tTd(3, 15)) 760 printf(", %d, %d", avenrun[1], avenrun[2]); 761 printf("\n"); 762 } 763 if (tTd(3, 1)) 764 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 765 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 766 #else 767 if (tTd(3, 5)) 768 { 769 printf("getla: avenrun = %g", avenrun[0]); 770 if (tTd(3, 15)) 771 printf(", %g, %g", avenrun[1], avenrun[2]); 772 printf("\n"); 773 } 774 if (tTd(3, 1)) 775 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 776 return ((int) (avenrun[0] + 0.5)); 777 #endif 778 } 779 780 #else 781 #if LA_TYPE == LA_SUBR 782 783 #ifdef DGUX 784 785 #include <sys/dg_sys_info.h> 786 787 int getla() 788 { 789 struct dg_sys_info_load_info load_info; 790 791 dg_sys_info((long *)&load_info, 792 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 793 794 return((int) (load_info.one_minute + 0.5)); 795 } 796 797 #else 798 799 getla() 800 { 801 double avenrun[3]; 802 803 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 804 { 805 if (tTd(3, 1)) 806 perror("getla: getloadavg failed:"); 807 return (-1); 808 } 809 if (tTd(3, 1)) 810 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 811 return ((int) (avenrun[0] + 0.5)); 812 } 813 814 #endif /* DGUX */ 815 #else 816 #if LA_TYPE == LA_MACH 817 818 /* 819 ** This has been tested on NEXTSTEP release 2.1/3.X. 820 */ 821 822 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 823 # include <mach/mach.h> 824 #else 825 # include <mach.h> 826 #endif 827 828 getla() 829 { 830 processor_set_t default_set; 831 kern_return_t error; 832 unsigned int info_count; 833 struct processor_set_basic_info info; 834 host_t host; 835 836 error = processor_set_default(host_self(), &default_set); 837 if (error != KERN_SUCCESS) 838 return -1; 839 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 840 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 841 &host, (processor_set_info_t)&info, 842 &info_count) != KERN_SUCCESS) 843 { 844 return -1; 845 } 846 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 847 } 848 849 850 #else 851 #if LA_TYPE == LA_PROCSTR 852 853 /* 854 ** Read /proc/loadavg for the load average. This is assumed to be 855 ** in a format like "0.15 0.12 0.06". 856 ** 857 ** Initially intended for Linux. This has been in the kernel 858 ** since at least 0.99.15. 859 */ 860 861 # ifndef _PATH_LOADAVG 862 # define _PATH_LOADAVG "/proc/loadavg" 863 # endif 864 865 int 866 getla() 867 { 868 double avenrun; 869 register int result; 870 FILE *fp; 871 872 fp = fopen(_PATH_LOADAVG, "r"); 873 if (fp == NULL) 874 { 875 if (tTd(3, 1)) 876 printf("getla: fopen(%s): %s\n", 877 _PATH_LOADAVG, errstring(errno)); 878 return -1; 879 } 880 result = fscanf(fp, "%lf", &avenrun); 881 fclose(fp); 882 if (result != 1) 883 { 884 if (tTd(3, 1)) 885 printf("getla: fscanf() = %d: %s\n", 886 result, errstring(errno)); 887 return -1; 888 } 889 890 if (tTd(3, 1)) 891 printf("getla(): %.2f\n", avenrun); 892 893 return ((int) (avenrun + 0.5)); 894 } 895 896 #else 897 898 getla() 899 { 900 if (tTd(3, 1)) 901 printf("getla: ZERO\n"); 902 return (0); 903 } 904 905 #endif 906 #endif 907 #endif 908 #endif 909 910 911 /* 912 * Copyright 1989 Massachusetts Institute of Technology 913 * 914 * Permission to use, copy, modify, distribute, and sell this software and its 915 * documentation for any purpose is hereby granted without fee, provided that 916 * the above copyright notice appear in all copies and that both that 917 * copyright notice and this permission notice appear in supporting 918 * documentation, and that the name of M.I.T. not be used in advertising or 919 * publicity pertaining to distribution of the software without specific, 920 * written prior permission. M.I.T. makes no representations about the 921 * suitability of this software for any purpose. It is provided "as is" 922 * without express or implied warranty. 923 * 924 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 925 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 926 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 927 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 928 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 929 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 930 * 931 * Authors: Many and varied... 932 */ 933 934 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 935 #ifndef lint 936 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 937 #endif /* !lint */ 938 939 #ifdef apollo 940 # undef volatile 941 # include <apollo/base.h> 942 943 /* ARGSUSED */ 944 int getloadavg( call_data ) 945 caddr_t call_data; /* pointer to (double) return value */ 946 { 947 double *avenrun = (double *) call_data; 948 int i; 949 status_$t st; 950 long loadav[3]; 951 proc1_$get_loadav(loadav, &st); 952 *avenrun = loadav[0] / (double) (1 << 16); 953 return(0); 954 } 955 # endif /* apollo */ 956 /* 957 ** SHOULDQUEUE -- should this message be queued or sent? 958 ** 959 ** Compares the message cost to the load average to decide. 960 ** 961 ** Parameters: 962 ** pri -- the priority of the message in question. 963 ** ctime -- the message creation time. 964 ** 965 ** Returns: 966 ** TRUE -- if this message should be queued up for the 967 ** time being. 968 ** FALSE -- if the load is low enough to send this message. 969 ** 970 ** Side Effects: 971 ** none. 972 */ 973 974 bool 975 shouldqueue(pri, ctime) 976 long pri; 977 time_t ctime; 978 { 979 if (CurrentLA < QueueLA) 980 return (FALSE); 981 if (CurrentLA >= RefuseLA) 982 return (TRUE); 983 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 984 } 985 /* 986 ** REFUSECONNECTIONS -- decide if connections should be refused 987 ** 988 ** Parameters: 989 ** none. 990 ** 991 ** Returns: 992 ** TRUE if incoming SMTP connections should be refused 993 ** (for now). 994 ** FALSE if we should accept new work. 995 ** 996 ** Side Effects: 997 ** none. 998 */ 999 1000 bool 1001 refuseconnections() 1002 { 1003 #ifdef XLA 1004 if (!xla_smtp_ok()) 1005 return TRUE; 1006 #endif 1007 1008 /* this is probably too simplistic */ 1009 return (CurrentLA >= RefuseLA); 1010 } 1011 /* 1012 ** SETPROCTITLE -- set process title for ps 1013 ** 1014 ** Parameters: 1015 ** fmt -- a printf style format string. 1016 ** a, b, c -- possible parameters to fmt. 1017 ** 1018 ** Returns: 1019 ** none. 1020 ** 1021 ** Side Effects: 1022 ** Clobbers argv of our main procedure so ps(1) will 1023 ** display the title. 1024 */ 1025 1026 #ifdef SETPROCTITLE 1027 1028 # ifdef HASSETPROCTITLE 1029 *** ERROR *** Cannot have both SETPROCTITLE and HASSETPROCTITLE defined 1030 # endif 1031 1032 # ifdef __hpux 1033 # include <sys/pstat.h> 1034 # endif 1035 # ifdef BSD4_4 1036 # include <machine/vmparam.h> 1037 # include <sys/exec.h> 1038 # ifdef __bsdi__ 1039 # undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */ 1040 # define PROCTITLEPAD '\0' 1041 # endif 1042 # ifdef PS_STRINGS 1043 # define SETPROC_STATIC static 1044 # endif 1045 # endif 1046 # ifdef _AIX3 1047 # define PROCTITLEPAD '\0' 1048 # endif 1049 1050 # ifndef SETPROC_STATIC 1051 # define SETPROC_STATIC 1052 # endif 1053 1054 #endif 1055 1056 #ifndef PROCTITLEPAD 1057 # define PROCTITLEPAD ' ' 1058 #endif 1059 1060 #ifndef HASSETPROCTITLE 1061 1062 /*VARARGS1*/ 1063 #ifdef __STDC__ 1064 setproctitle(char *fmt, ...) 1065 #else 1066 setproctitle(fmt, va_alist) 1067 char *fmt; 1068 va_dcl 1069 #endif 1070 { 1071 # ifdef SETPROCTITLE 1072 register char *p; 1073 register int i; 1074 SETPROC_STATIC char buf[MAXLINE]; 1075 VA_LOCAL_DECL 1076 # ifdef __hpux 1077 union pstun pst; 1078 # endif 1079 extern char **Argv; 1080 extern char *LastArgv; 1081 1082 p = buf; 1083 1084 /* print sendmail: heading for grep */ 1085 (void) strcpy(p, "sendmail: "); 1086 p += strlen(p); 1087 1088 /* print the argument string */ 1089 VA_START(fmt); 1090 (void) vsprintf(p, fmt, ap); 1091 VA_END; 1092 1093 i = strlen(buf); 1094 1095 # ifdef __hpux 1096 pst.pst_command = buf; 1097 pstat(PSTAT_SETCMD, pst, i, 0, 0); 1098 # else 1099 # ifdef PS_STRINGS 1100 PS_STRINGS->ps_nargvstr = 1; 1101 PS_STRINGS->ps_argvstr = buf; 1102 # else 1103 if (i > LastArgv - Argv[0] - 2) 1104 { 1105 i = LastArgv - Argv[0] - 2; 1106 buf[i] = '\0'; 1107 } 1108 (void) strcpy(Argv[0], buf); 1109 p = &Argv[0][i]; 1110 while (p < LastArgv) 1111 *p++ = PROCTITLEPAD; 1112 Argv[1] = NULL; 1113 # endif 1114 # endif 1115 # endif /* SETPROCTITLE */ 1116 } 1117 1118 #endif 1119 /* 1120 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 1121 ** 1122 ** Parameters: 1123 ** none. 1124 ** 1125 ** Returns: 1126 ** none. 1127 ** 1128 ** Side Effects: 1129 ** Picks up extant zombies. 1130 */ 1131 1132 void 1133 reapchild() 1134 { 1135 int olderrno = errno; 1136 # ifdef HASWAITPID 1137 auto int status; 1138 int count; 1139 int pid; 1140 1141 count = 0; 1142 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 1143 { 1144 if (count++ > 1000) 1145 { 1146 #ifdef LOG 1147 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 1148 pid, status); 1149 #endif 1150 break; 1151 } 1152 } 1153 # else 1154 # ifdef WNOHANG 1155 union wait status; 1156 1157 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 1158 continue; 1159 # else /* WNOHANG */ 1160 auto int status; 1161 1162 while (wait(&status) > 0) 1163 continue; 1164 # endif /* WNOHANG */ 1165 # endif 1166 # ifdef SYS5SIGNALS 1167 (void) setsignal(SIGCHLD, reapchild); 1168 # endif 1169 errno = olderrno; 1170 } 1171 /* 1172 ** UNSETENV -- remove a variable from the environment 1173 ** 1174 ** Not needed on newer systems. 1175 ** 1176 ** Parameters: 1177 ** name -- the string name of the environment variable to be 1178 ** deleted from the current environment. 1179 ** 1180 ** Returns: 1181 ** none. 1182 ** 1183 ** Globals: 1184 ** environ -- a pointer to the current environment. 1185 ** 1186 ** Side Effects: 1187 ** Modifies environ. 1188 */ 1189 1190 #ifndef HASUNSETENV 1191 1192 void 1193 unsetenv(name) 1194 char *name; 1195 { 1196 extern char **environ; 1197 register char **pp; 1198 int len = strlen(name); 1199 1200 for (pp = environ; *pp != NULL; pp++) 1201 { 1202 if (strncmp(name, *pp, len) == 0 && 1203 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 1204 break; 1205 } 1206 1207 for (; *pp != NULL; pp++) 1208 *pp = pp[1]; 1209 } 1210 1211 #endif 1212 /* 1213 ** GETDTABLESIZE -- return number of file descriptors 1214 ** 1215 ** Only on non-BSD systems 1216 ** 1217 ** Parameters: 1218 ** none 1219 ** 1220 ** Returns: 1221 ** size of file descriptor table 1222 ** 1223 ** Side Effects: 1224 ** none 1225 */ 1226 1227 #ifdef SOLARIS 1228 # include <sys/resource.h> 1229 #endif 1230 1231 int 1232 getdtsize() 1233 { 1234 #ifdef RLIMIT_NOFILE 1235 struct rlimit rl; 1236 1237 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1238 return rl.rlim_cur; 1239 #endif 1240 1241 # ifdef HASGETDTABLESIZE 1242 return getdtablesize(); 1243 # else 1244 # ifdef _SC_OPEN_MAX 1245 return sysconf(_SC_OPEN_MAX); 1246 # else 1247 return NOFILE; 1248 # endif 1249 # endif 1250 } 1251 /* 1252 ** UNAME -- get the UUCP name of this system. 1253 */ 1254 1255 #ifndef HASUNAME 1256 1257 int 1258 uname(name) 1259 struct utsname *name; 1260 { 1261 FILE *file; 1262 char *n; 1263 1264 name->nodename[0] = '\0'; 1265 1266 /* try /etc/whoami -- one line with the node name */ 1267 if ((file = fopen("/etc/whoami", "r")) != NULL) 1268 { 1269 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1270 (void) fclose(file); 1271 n = strchr(name->nodename, '\n'); 1272 if (n != NULL) 1273 *n = '\0'; 1274 if (name->nodename[0] != '\0') 1275 return (0); 1276 } 1277 1278 /* try /usr/include/whoami.h -- has a #define somewhere */ 1279 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1280 { 1281 char buf[MAXLINE]; 1282 1283 while (fgets(buf, MAXLINE, file) != NULL) 1284 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1285 NODE_LENGTH, name->nodename) > 0) 1286 break; 1287 (void) fclose(file); 1288 if (name->nodename[0] != '\0') 1289 return (0); 1290 } 1291 1292 #ifdef TRUST_POPEN 1293 /* 1294 ** Popen is known to have security holes. 1295 */ 1296 1297 /* try uuname -l to return local name */ 1298 if ((file = popen("uuname -l", "r")) != NULL) 1299 { 1300 (void) fgets(name, NODE_LENGTH + 1, file); 1301 (void) pclose(file); 1302 n = strchr(name, '\n'); 1303 if (n != NULL) 1304 *n = '\0'; 1305 if (name->nodename[0] != '\0') 1306 return (0); 1307 } 1308 #endif 1309 1310 return (-1); 1311 } 1312 #endif /* HASUNAME */ 1313 /* 1314 ** INITGROUPS -- initialize groups 1315 ** 1316 ** Stub implementation for System V style systems 1317 */ 1318 1319 #ifndef HASINITGROUPS 1320 1321 initgroups(name, basegid) 1322 char *name; 1323 int basegid; 1324 { 1325 return 0; 1326 } 1327 1328 #endif 1329 /* 1330 ** SETSID -- set session id (for non-POSIX systems) 1331 */ 1332 1333 #ifndef HASSETSID 1334 1335 pid_t 1336 setsid __P ((void)) 1337 { 1338 #ifdef TIOCNOTTY 1339 int fd; 1340 1341 fd = open("/dev/tty", O_RDWR, 0); 1342 if (fd >= 0) 1343 { 1344 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1345 (void) close(fd); 1346 } 1347 #endif /* TIOCNOTTY */ 1348 # ifdef SYS5SETPGRP 1349 return setpgrp(); 1350 # else 1351 return setpgid(0, getpid()); 1352 # endif 1353 } 1354 1355 #endif 1356 /* 1357 ** FSYNC -- dummy fsync 1358 */ 1359 1360 #ifdef NEEDFSYNC 1361 1362 fsync(fd) 1363 int fd; 1364 { 1365 # ifdef O_SYNC 1366 return fcntl(fd, F_SETFL, O_SYNC); 1367 # else 1368 /* nothing we can do */ 1369 return 0; 1370 # endif 1371 } 1372 1373 #endif 1374 /* 1375 ** DGUX_INET_ADDR -- inet_addr for DG/UX 1376 ** 1377 ** Data General DG/UX version of inet_addr returns a struct in_addr 1378 ** instead of a long. This patches things. Only needed on versions 1379 ** prior to 5.4.3. 1380 */ 1381 1382 #ifdef DGUX_5_4_2 1383 1384 #undef inet_addr 1385 1386 long 1387 dgux_inet_addr(host) 1388 char *host; 1389 { 1390 struct in_addr haddr; 1391 1392 haddr = inet_addr(host); 1393 return haddr.s_addr; 1394 } 1395 1396 #endif 1397 /* 1398 ** GETOPT -- for old systems or systems with bogus implementations 1399 */ 1400 1401 #ifdef NEEDGETOPT 1402 1403 /* 1404 * Copyright (c) 1985 Regents of the University of California. 1405 * All rights reserved. The Berkeley software License Agreement 1406 * specifies the terms and conditions for redistribution. 1407 */ 1408 1409 1410 /* 1411 ** this version hacked to add `atend' flag to allow state machine 1412 ** to reset if invoked by the program to scan args for a 2nd time 1413 */ 1414 1415 #if defined(LIBC_SCCS) && !defined(lint) 1416 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1417 #endif /* LIBC_SCCS and not lint */ 1418 1419 #include <stdio.h> 1420 1421 /* 1422 * get option letter from argument vector 1423 */ 1424 #ifdef _CONVEX_SOURCE 1425 extern int optind, opterr; 1426 #else 1427 int opterr = 1; /* if error message should be printed */ 1428 int optind = 1; /* index into parent argv vector */ 1429 #endif 1430 int optopt; /* character checked for validity */ 1431 char *optarg; /* argument associated with option */ 1432 1433 #define BADCH (int)'?' 1434 #define EMSG "" 1435 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1436 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1437 1438 getopt(nargc,nargv,ostr) 1439 int nargc; 1440 char *const *nargv; 1441 const char *ostr; 1442 { 1443 static char *place = EMSG; /* option letter processing */ 1444 static char atend = 0; 1445 register char *oli; /* option letter list index */ 1446 1447 if (atend) { 1448 atend = 0; 1449 place = EMSG; 1450 } 1451 if(!*place) { /* update scanning pointer */ 1452 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1453 atend++; 1454 return(EOF); 1455 } 1456 if (*place == '-') { /* found "--" */ 1457 ++optind; 1458 atend++; 1459 return(EOF); 1460 } 1461 } /* option letter okay? */ 1462 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1463 if (!*place) ++optind; 1464 tell(": illegal option -- "); 1465 } 1466 if (*++oli != ':') { /* don't need argument */ 1467 optarg = NULL; 1468 if (!*place) ++optind; 1469 } 1470 else { /* need an argument */ 1471 if (*place) optarg = place; /* no white space */ 1472 else if (nargc <= ++optind) { /* no arg */ 1473 place = EMSG; 1474 tell(": option requires an argument -- "); 1475 } 1476 else optarg = nargv[optind]; /* white space */ 1477 place = EMSG; 1478 ++optind; 1479 } 1480 return(optopt); /* dump back option letter */ 1481 } 1482 1483 #endif 1484 /* 1485 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1486 */ 1487 1488 #ifdef NEEDVPRINTF 1489 1490 #define MAXARG 16 1491 1492 vfprintf(fp, fmt, ap) 1493 FILE * fp; 1494 char * fmt; 1495 char ** ap; 1496 { 1497 char * bp[MAXARG]; 1498 int i = 0; 1499 1500 while (*ap && i < MAXARG) 1501 bp[i++] = *ap++; 1502 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1503 bp[4], bp[5], bp[6], bp[7], 1504 bp[8], bp[9], bp[10], bp[11], 1505 bp[12], bp[13], bp[14], bp[15]); 1506 } 1507 1508 vsprintf(s, fmt, ap) 1509 char * s; 1510 char * fmt; 1511 char ** ap; 1512 { 1513 char * bp[MAXARG]; 1514 int i = 0; 1515 1516 while (*ap && i < MAXARG) 1517 bp[i++] = *ap++; 1518 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1519 bp[4], bp[5], bp[6], bp[7], 1520 bp[8], bp[9], bp[10], bp[11], 1521 bp[12], bp[13], bp[14], bp[15]); 1522 } 1523 1524 #endif 1525 /* 1526 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 1527 ** 1528 ** Parameters: 1529 ** shell -- the user's shell from /etc/passwd 1530 ** 1531 ** Returns: 1532 ** TRUE -- if it is ok to use this for unrestricted access. 1533 ** FALSE -- if the shell is restricted. 1534 */ 1535 1536 #if !HASGETUSERSHELL 1537 1538 # ifndef _PATH_SHELLS 1539 # define _PATH_SHELLS "/etc/shells" 1540 # endif 1541 1542 char *DefaultUserShells[] = 1543 { 1544 "/bin/sh", 1545 "/usr/bin/sh", 1546 "/bin/csh", 1547 "/usr/bin/csh", 1548 #ifdef __hpux 1549 "/bin/rsh", 1550 "/bin/ksh", 1551 "/bin/rksh", 1552 "/bin/pam", 1553 "/usr/bin/keysh", 1554 "/bin/posix/sh", 1555 #endif 1556 NULL 1557 }; 1558 1559 #endif 1560 1561 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 1562 1563 bool 1564 usershellok(shell) 1565 char *shell; 1566 { 1567 #if HASGETUSERSHELL 1568 register char *p; 1569 extern char *getusershell(); 1570 1571 setusershell(); 1572 while ((p = getusershell()) != NULL) 1573 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 1574 break; 1575 endusershell(); 1576 return p != NULL; 1577 #else 1578 register FILE *shellf; 1579 char buf[MAXLINE]; 1580 1581 shellf = fopen(_PATH_SHELLS, "r"); 1582 if (shellf == NULL) 1583 { 1584 /* no /etc/shells; see if it is one of the std shells */ 1585 char **d; 1586 1587 for (d = DefaultUserShells; *d != NULL; d++) 1588 { 1589 if (strcmp(shell, *d) == 0) 1590 return TRUE; 1591 } 1592 return FALSE; 1593 } 1594 1595 while (fgets(buf, sizeof buf, shellf) != NULL) 1596 { 1597 register char *p, *q; 1598 1599 p = buf; 1600 while (*p != '\0' && *p != '#' && *p != '/') 1601 p++; 1602 if (*p == '#' || *p == '\0') 1603 continue; 1604 q = p; 1605 while (*p != '\0' && *p != '#' && !isspace(*p)) 1606 p++; 1607 *p = '\0'; 1608 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 1609 { 1610 fclose(shellf); 1611 return TRUE; 1612 } 1613 } 1614 fclose(shellf); 1615 return FALSE; 1616 #endif 1617 } 1618 /* 1619 ** FREESPACE -- see how much free space is on the queue filesystem 1620 ** 1621 ** Only implemented if you have statfs. 1622 ** 1623 ** Parameters: 1624 ** dir -- the directory in question. 1625 ** bsize -- a variable into which the filesystem 1626 ** block size is stored. 1627 ** 1628 ** Returns: 1629 ** The number of bytes free on the queue filesystem. 1630 ** -1 if the statfs call fails. 1631 ** 1632 ** Side effects: 1633 ** Puts the filesystem block size into bsize. 1634 */ 1635 1636 /* statfs types */ 1637 #define SFS_NONE 0 /* no statfs implementation */ 1638 #define SFS_USTAT 1 /* use ustat */ 1639 #define SFS_4ARGS 2 /* use four-argument statfs call */ 1640 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 1641 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 1642 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 1643 #define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */ 1644 1645 #ifndef SFS_TYPE 1646 # define SFS_TYPE SFS_NONE 1647 #endif 1648 1649 #if SFS_TYPE == SFS_USTAT 1650 # include <ustat.h> 1651 #endif 1652 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 1653 # include <sys/statfs.h> 1654 #endif 1655 #if SFS_TYPE == SFS_VFS 1656 # include <sys/vfs.h> 1657 #endif 1658 #if SFS_TYPE == SFS_MOUNT 1659 # include <sys/mount.h> 1660 #endif 1661 #if SFS_TYPE == SFS_STATVFS 1662 # include <sys/statvfs.h> 1663 #endif 1664 1665 long 1666 freespace(dir, bsize) 1667 char *dir; 1668 long *bsize; 1669 { 1670 #if SFS_TYPE != SFS_NONE 1671 # if SFS_TYPE == SFS_USTAT 1672 struct ustat fs; 1673 struct stat statbuf; 1674 # define FSBLOCKSIZE DEV_BSIZE 1675 # define f_bavail f_tfree 1676 # else 1677 # if defined(ultrix) 1678 struct fs_data fs; 1679 # define f_bavail fd_bfreen 1680 # define FSBLOCKSIZE 1024L 1681 # else 1682 # if SFS_TYPE == SFS_STATVFS 1683 struct statvfs fs; 1684 # define FSBLOCKSIZE fs.f_bsize 1685 # else 1686 struct statfs fs; 1687 # define FSBLOCKSIZE fs.f_bsize 1688 # if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) 1689 # define f_bavail f_bfree 1690 # endif 1691 # endif 1692 # endif 1693 # endif 1694 extern int errno; 1695 1696 # if SFS_TYPE == SFS_USTAT 1697 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1698 # else 1699 # if SFS_TYPE == SFS_4ARGS 1700 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1701 # else 1702 # if SFS_TYPE == SFS_STATVFS 1703 if (statvfs(dir, &fs) == 0) 1704 # else 1705 # if defined(ultrix) 1706 if (statfs(dir, &fs) > 0) 1707 # else 1708 if (statfs(dir, &fs) == 0) 1709 # endif 1710 # endif 1711 # endif 1712 # endif 1713 { 1714 if (bsize != NULL) 1715 *bsize = FSBLOCKSIZE; 1716 return (fs.f_bavail); 1717 } 1718 #endif 1719 return (-1); 1720 } 1721 /* 1722 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1723 ** 1724 ** Only implemented if you have statfs. 1725 ** 1726 ** Parameters: 1727 ** msize -- the size to check against. If zero, we don't yet 1728 ** know how big the message will be, so just check for 1729 ** a "reasonable" amount. 1730 ** 1731 ** Returns: 1732 ** TRUE if there is enough space. 1733 ** FALSE otherwise. 1734 */ 1735 1736 bool 1737 enoughspace(msize) 1738 long msize; 1739 { 1740 long bfree, bsize; 1741 1742 if (MinBlocksFree <= 0 && msize <= 0) 1743 { 1744 if (tTd(4, 80)) 1745 printf("enoughspace: no threshold\n"); 1746 return TRUE; 1747 } 1748 1749 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 1750 { 1751 if (tTd(4, 80)) 1752 printf("enoughspace: bavail=%ld, need=%ld\n", 1753 bfree, msize); 1754 1755 /* convert msize to block count */ 1756 msize = msize / bsize + 1; 1757 if (MinBlocksFree >= 0) 1758 msize += MinBlocksFree; 1759 1760 if (bfree < msize) 1761 { 1762 #ifdef LOG 1763 if (LogLevel > 0) 1764 syslog(LOG_ALERT, 1765 "%s: low on space (have %ld, %s needs %ld in %s)", 1766 CurEnv->e_id, bfree, 1767 CurHostName, msize, QueueDir); 1768 #endif 1769 return FALSE; 1770 } 1771 } 1772 else if (tTd(4, 80)) 1773 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1774 MinBlocksFree, msize, errstring(errno)); 1775 return TRUE; 1776 } 1777 /* 1778 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1779 ** 1780 ** This looks at an errno value and tells if this is likely to 1781 ** go away if retried later. 1782 ** 1783 ** Parameters: 1784 ** err -- the errno code to classify. 1785 ** 1786 ** Returns: 1787 ** TRUE if this is probably transient. 1788 ** FALSE otherwise. 1789 */ 1790 1791 bool 1792 transienterror(err) 1793 int err; 1794 { 1795 switch (err) 1796 { 1797 case EIO: /* I/O error */ 1798 case ENXIO: /* Device not configured */ 1799 case EAGAIN: /* Resource temporarily unavailable */ 1800 case ENOMEM: /* Cannot allocate memory */ 1801 case ENODEV: /* Operation not supported by device */ 1802 case ENFILE: /* Too many open files in system */ 1803 case EMFILE: /* Too many open files */ 1804 case ENOSPC: /* No space left on device */ 1805 #ifdef ETIMEDOUT 1806 case ETIMEDOUT: /* Connection timed out */ 1807 #endif 1808 #ifdef ESTALE 1809 case ESTALE: /* Stale NFS file handle */ 1810 #endif 1811 #ifdef ENETDOWN 1812 case ENETDOWN: /* Network is down */ 1813 #endif 1814 #ifdef ENETUNREACH 1815 case ENETUNREACH: /* Network is unreachable */ 1816 #endif 1817 #ifdef ENETRESET 1818 case ENETRESET: /* Network dropped connection on reset */ 1819 #endif 1820 #ifdef ECONNABORTED 1821 case ECONNABORTED: /* Software caused connection abort */ 1822 #endif 1823 #ifdef ECONNRESET 1824 case ECONNRESET: /* Connection reset by peer */ 1825 #endif 1826 #ifdef ENOBUFS 1827 case ENOBUFS: /* No buffer space available */ 1828 #endif 1829 #ifdef ESHUTDOWN 1830 case ESHUTDOWN: /* Can't send after socket shutdown */ 1831 #endif 1832 #ifdef ECONNREFUSED 1833 case ECONNREFUSED: /* Connection refused */ 1834 #endif 1835 #ifdef EHOSTDOWN 1836 case EHOSTDOWN: /* Host is down */ 1837 #endif 1838 #ifdef EHOSTUNREACH 1839 case EHOSTUNREACH: /* No route to host */ 1840 #endif 1841 #ifdef EDQUOT 1842 case EDQUOT: /* Disc quota exceeded */ 1843 #endif 1844 #ifdef EPROCLIM 1845 case EPROCLIM: /* Too many processes */ 1846 #endif 1847 #ifdef EUSERS 1848 case EUSERS: /* Too many users */ 1849 #endif 1850 #ifdef EDEADLK 1851 case EDEADLK: /* Resource deadlock avoided */ 1852 #endif 1853 #ifdef EISCONN 1854 case EISCONN: /* Socket already connected */ 1855 #endif 1856 #ifdef EINPROGRESS 1857 case EINPROGRESS: /* Operation now in progress */ 1858 #endif 1859 #ifdef EALREADY 1860 case EALREADY: /* Operation already in progress */ 1861 #endif 1862 #ifdef EADDRINUSE 1863 case EADDRINUSE: /* Address already in use */ 1864 #endif 1865 #ifdef EADDRNOTAVAIL 1866 case EADDRNOTAVAIL: /* Can't assign requested address */ 1867 #endif 1868 #ifdef ETXTBSY 1869 case ETXTBSY: /* (Apollo) file locked */ 1870 #endif 1871 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1872 case ENOSR: /* Out of streams resources */ 1873 #endif 1874 return TRUE; 1875 } 1876 1877 /* nope, must be permanent */ 1878 return FALSE; 1879 } 1880 /* 1881 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1882 ** 1883 ** Parameters: 1884 ** fd -- the file descriptor of the file. 1885 ** filename -- the file name (for error messages). 1886 ** ext -- the filename extension. 1887 ** type -- type of the lock. Bits can be: 1888 ** LOCK_EX -- exclusive lock. 1889 ** LOCK_NB -- non-blocking. 1890 ** 1891 ** Returns: 1892 ** TRUE if the lock was acquired. 1893 ** FALSE otherwise. 1894 */ 1895 1896 bool 1897 lockfile(fd, filename, ext, type) 1898 int fd; 1899 char *filename; 1900 char *ext; 1901 int type; 1902 { 1903 # if !HASFLOCK 1904 int action; 1905 struct flock lfd; 1906 1907 if (ext == NULL) 1908 ext = ""; 1909 1910 bzero(&lfd, sizeof lfd); 1911 if (bitset(LOCK_UN, type)) 1912 lfd.l_type = F_UNLCK; 1913 else if (bitset(LOCK_EX, type)) 1914 lfd.l_type = F_WRLCK; 1915 else 1916 lfd.l_type = F_RDLCK; 1917 1918 if (bitset(LOCK_NB, type)) 1919 action = F_SETLK; 1920 else 1921 action = F_SETLKW; 1922 1923 if (tTd(55, 60)) 1924 printf("lockfile(%s%s, action=%d, type=%d): ", 1925 filename, ext, action, lfd.l_type); 1926 1927 if (fcntl(fd, action, &lfd) >= 0) 1928 { 1929 if (tTd(55, 60)) 1930 printf("SUCCESS\n"); 1931 return TRUE; 1932 } 1933 1934 if (tTd(55, 60)) 1935 printf("(%s) ", errstring(errno)); 1936 1937 /* 1938 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1939 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1940 ** as type "tmp" (that is, served from swap space), the 1941 ** previous fcntl will fail with "Invalid argument" errors. 1942 ** Since this is fairly common during testing, we will assume 1943 ** that this indicates that the lock is successfully grabbed. 1944 */ 1945 1946 if (errno == EINVAL) 1947 { 1948 if (tTd(55, 60)) 1949 printf("SUCCESS\n"); 1950 return TRUE; 1951 } 1952 1953 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1954 { 1955 int omode = -1; 1956 # ifdef F_GETFL 1957 int oerrno = errno; 1958 1959 (void) fcntl(fd, F_GETFL, &omode); 1960 errno = oerrno; 1961 # endif 1962 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1963 filename, ext, fd, type, omode, geteuid()); 1964 } 1965 # else 1966 if (ext == NULL) 1967 ext = ""; 1968 1969 if (tTd(55, 60)) 1970 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 1971 1972 if (flock(fd, type) >= 0) 1973 { 1974 if (tTd(55, 60)) 1975 printf("SUCCESS\n"); 1976 return TRUE; 1977 } 1978 1979 if (tTd(55, 60)) 1980 printf("(%s) ", errstring(errno)); 1981 1982 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1983 { 1984 int omode = -1; 1985 # ifdef F_GETFL 1986 int oerrno = errno; 1987 1988 (void) fcntl(fd, F_GETFL, &omode); 1989 errno = oerrno; 1990 # endif 1991 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1992 filename, ext, fd, type, omode, geteuid()); 1993 } 1994 # endif 1995 if (tTd(55, 60)) 1996 printf("FAIL\n"); 1997 return FALSE; 1998 } 1999 /* 2000 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 2001 ** 2002 ** Parameters: 2003 ** fd -- the file descriptor to check. 2004 ** 2005 ** Returns: 2006 ** TRUE -- if only root can chown the file to an arbitrary 2007 ** user. 2008 ** FALSE -- if an arbitrary user can give away a file. 2009 */ 2010 2011 bool 2012 chownsafe(fd) 2013 int fd; 2014 { 2015 #ifdef __hpux 2016 char *s; 2017 int tfd; 2018 uid_t o_uid, o_euid; 2019 gid_t o_gid, o_egid; 2020 bool rval; 2021 struct stat stbuf; 2022 2023 o_uid = getuid(); 2024 o_euid = geteuid(); 2025 o_gid = getgid(); 2026 o_egid = getegid(); 2027 fstat(fd, &stbuf); 2028 setresuid(stbuf.st_uid, stbuf.st_uid, -1); 2029 setresgid(stbuf.st_gid, stbuf.st_gid, -1); 2030 s = tmpnam(NULL); 2031 tfd = open(s, O_RDONLY|O_CREAT, 0600); 2032 rval = fchown(tfd, DefUid, DefGid) != 0; 2033 close(tfd); 2034 unlink(s); 2035 setreuid(o_uid, o_euid); 2036 setresgid(o_gid, o_egid, -1); 2037 return rval; 2038 #else 2039 # ifdef _POSIX_CHOWN_RESTRICTED 2040 # if _POSIX_CHOWN_RESTRICTED == -1 2041 return FALSE; 2042 # else 2043 return TRUE; 2044 # endif 2045 # else 2046 # ifdef _PC_CHOWN_RESTRICTED 2047 int rval; 2048 2049 /* 2050 ** Some systems (e.g., SunOS) seem to have the call and the 2051 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement 2052 ** the call. This heuristic checks for that. 2053 */ 2054 2055 errno = 0; 2056 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); 2057 if (errno == 0) 2058 return rval > 0; 2059 # endif 2060 # ifdef BSD 2061 return TRUE; 2062 # else 2063 return FALSE; 2064 # endif 2065 # endif 2066 #endif 2067 } 2068 /* 2069 ** RESETLIMITS -- reset system controlled resource limits 2070 ** 2071 ** This is to avoid denial-of-service attacks 2072 ** 2073 ** Parameters: 2074 ** none 2075 ** 2076 ** Returns: 2077 ** none 2078 */ 2079 2080 #if HASSETRLIMIT 2081 # include <sys/resource.h> 2082 #endif 2083 2084 resetlimits() 2085 { 2086 #if HASSETRLIMIT 2087 struct rlimit lim; 2088 2089 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 2090 (void) setrlimit(RLIMIT_CPU, &lim); 2091 (void) setrlimit(RLIMIT_FSIZE, &lim); 2092 #else 2093 # if HASULIMIT 2094 (void) ulimit(2, 0x3fffff); 2095 # endif 2096 #endif 2097 } 2098 /* 2099 ** GETCFNAME -- return the name of the .cf file. 2100 ** 2101 ** Some systems (e.g., NeXT) determine this dynamically. 2102 */ 2103 2104 char * 2105 getcfname() 2106 { 2107 if (ConfFile != NULL) 2108 return ConfFile; 2109 #ifdef NETINFO 2110 { 2111 extern char *ni_propval(); 2112 char *cflocation; 2113 2114 cflocation = ni_propval("/locations/sendmail", "sendmail.cf"); 2115 if (cflocation != NULL) 2116 return cflocation; 2117 } 2118 #endif 2119 return _PATH_SENDMAILCF; 2120 } 2121 /* 2122 ** SETVENDOR -- process vendor code from V configuration line 2123 ** 2124 ** Parameters: 2125 ** vendor -- string representation of vendor. 2126 ** 2127 ** Returns: 2128 ** TRUE -- if ok. 2129 ** FALSE -- if vendor code could not be processed. 2130 ** 2131 ** Side Effects: 2132 ** It is reasonable to set mode flags here to tweak 2133 ** processing in other parts of the code if necessary. 2134 ** For example, if you are a vendor that uses $%y to 2135 ** indicate YP lookups, you could enable that here. 2136 */ 2137 2138 bool 2139 setvendor(vendor) 2140 char *vendor; 2141 { 2142 if (strcasecmp(vendor, "Berkeley") == 0) 2143 return TRUE; 2144 2145 /* add vendor extensions here */ 2146 2147 return FALSE; 2148 } 2149 /* 2150 ** STRTOL -- convert string to long integer 2151 ** 2152 ** For systems that don't have it in the C library. 2153 ** 2154 ** This is taken verbatim from the 4.4-Lite C library. 2155 */ 2156 2157 #ifdef NEEDSTRTOL 2158 2159 #if defined(LIBC_SCCS) && !defined(lint) 2160 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 2161 #endif /* LIBC_SCCS and not lint */ 2162 2163 #include <limits.h> 2164 2165 /* 2166 * Convert a string to a long integer. 2167 * 2168 * Ignores `locale' stuff. Assumes that the upper and lower case 2169 * alphabets and digits are each contiguous. 2170 */ 2171 2172 long 2173 strtol(nptr, endptr, base) 2174 const char *nptr; 2175 char **endptr; 2176 register int base; 2177 { 2178 register const char *s = nptr; 2179 register unsigned long acc; 2180 register int c; 2181 register unsigned long cutoff; 2182 register int neg = 0, any, cutlim; 2183 2184 /* 2185 * Skip white space and pick up leading +/- sign if any. 2186 * If base is 0, allow 0x for hex and 0 for octal, else 2187 * assume decimal; if base is already 16, allow 0x. 2188 */ 2189 do { 2190 c = *s++; 2191 } while (isspace(c)); 2192 if (c == '-') { 2193 neg = 1; 2194 c = *s++; 2195 } else if (c == '+') 2196 c = *s++; 2197 if ((base == 0 || base == 16) && 2198 c == '0' && (*s == 'x' || *s == 'X')) { 2199 c = s[1]; 2200 s += 2; 2201 base = 16; 2202 } 2203 if (base == 0) 2204 base = c == '0' ? 8 : 10; 2205 2206 /* 2207 * Compute the cutoff value between legal numbers and illegal 2208 * numbers. That is the largest legal value, divided by the 2209 * base. An input number that is greater than this value, if 2210 * followed by a legal input character, is too big. One that 2211 * is equal to this value may be valid or not; the limit 2212 * between valid and invalid numbers is then based on the last 2213 * digit. For instance, if the range for longs is 2214 * [-2147483648..2147483647] and the input base is 10, 2215 * cutoff will be set to 214748364 and cutlim to either 2216 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 2217 * a value > 214748364, or equal but the next digit is > 7 (or 8), 2218 * the number is too big, and we will return a range error. 2219 * 2220 * Set any if any `digits' consumed; make it negative to indicate 2221 * overflow. 2222 */ 2223 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 2224 cutlim = cutoff % (unsigned long)base; 2225 cutoff /= (unsigned long)base; 2226 for (acc = 0, any = 0;; c = *s++) { 2227 if (isdigit(c)) 2228 c -= '0'; 2229 else if (isalpha(c)) 2230 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 2231 else 2232 break; 2233 if (c >= base) 2234 break; 2235 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 2236 any = -1; 2237 else { 2238 any = 1; 2239 acc *= base; 2240 acc += c; 2241 } 2242 } 2243 if (any < 0) { 2244 acc = neg ? LONG_MIN : LONG_MAX; 2245 errno = ERANGE; 2246 } else if (neg) 2247 acc = -acc; 2248 if (endptr != 0) 2249 *endptr = (char *)(any ? s - 1 : nptr); 2250 return (acc); 2251 } 2252 2253 #endif 2254 /* 2255 ** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 2256 ** 2257 ** Solaris versions at least through 2.3 don't properly deliver a 2258 ** canonical h_name field. This tries to work around it. 2259 */ 2260 2261 #ifdef SOLARIS 2262 2263 extern int h_errno; 2264 2265 struct hostent * 2266 solaris_gethostbyname(name) 2267 const char *name; 2268 { 2269 # ifdef SOLARIS_2_3 2270 static struct hostent hp; 2271 static char buf[1000]; 2272 extern struct hostent *_switch_gethostbyname_r(); 2273 2274 return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 2275 # else 2276 extern struct hostent *__switch_gethostbyname(); 2277 2278 return __switch_gethostbyname(name); 2279 # endif 2280 } 2281 2282 struct hostent * 2283 solaris_gethostbyaddr(addr, len, type) 2284 const char *addr; 2285 int len; 2286 int type; 2287 { 2288 # ifdef SOLARIS_2_3 2289 static struct hostent hp; 2290 static char buf[1000]; 2291 extern struct hostent *_switch_gethostbyaddr_r(); 2292 2293 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno); 2294 # else 2295 extern struct hostent *__switch_gethostbyaddr(); 2296 2297 return __switch_gethostbyaddr(addr, len, type); 2298 # endif 2299 } 2300 2301 #endif 2302 /* 2303 ** NI_PROPVAL -- netinfo property value lookup routine 2304 ** 2305 ** Parameters: 2306 ** directory -- the Netinfo directory name. 2307 ** propname -- the Netinfo property name. 2308 ** 2309 ** Returns: 2310 ** NULL -- if: 2311 ** 1. the directory is not found 2312 ** 2. the property name is not found 2313 ** 3. the property contains multiple values 2314 ** 4. some error occured 2315 ** else -- the location of the config file. 2316 ** 2317 ** Notes: 2318 ** Caller should free the return value of ni_proval 2319 */ 2320 2321 #ifdef NETINFO 2322 2323 # include <netinfo/ni.h> 2324 2325 # define LOCAL_NETINFO_DOMAIN "." 2326 # define PARENT_NETINFO_DOMAIN ".." 2327 # define MAX_NI_LEVELS 256 2328 2329 char * 2330 ni_propval(directory, propname) 2331 char *directory; 2332 char *propname; 2333 { 2334 char *propval = NULL; 2335 int i; 2336 void *ni = NULL; 2337 void *lastni = NULL; 2338 ni_status nis; 2339 ni_id nid; 2340 ni_namelist ninl; 2341 2342 /* 2343 ** If the passed directory and property name are found 2344 ** in one of netinfo domains we need to search (starting 2345 ** from the local domain moving all the way back to the 2346 ** root domain) set propval to the property's value 2347 ** and return it. 2348 */ 2349 2350 for (i = 0; i < MAX_NI_LEVELS; ++i) 2351 { 2352 if (i == 0) 2353 { 2354 nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 2355 } 2356 else 2357 { 2358 if (lastni != NULL) 2359 ni_free(lastni); 2360 lastni = ni; 2361 nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 2362 } 2363 2364 /* 2365 ** Don't bother if we didn't get a handle on a 2366 ** proper domain. This is not necessarily an error. 2367 ** We would get a positive ni_status if, for instance 2368 ** we never found the directory or property and tried 2369 ** to open the parent of the root domain! 2370 */ 2371 2372 if (nis != 0) 2373 break; 2374 2375 /* 2376 ** Find the path to the server information. 2377 */ 2378 2379 if (ni_pathsearch(ni, &nid, directory) != 0) 2380 continue; 2381 2382 /* 2383 ** Find "host" information. 2384 */ 2385 2386 if (ni_lookupprop(ni, &nid, propname, &ninl) != 0) 2387 continue; 2388 2389 /* 2390 ** If there's only one name in 2391 ** the list, assume we've got 2392 ** what we want. 2393 */ 2394 2395 if (ninl.ni_namelist_len == 1) 2396 { 2397 propval = ni_name_dup(ninl.ni_namelist_val[0]); 2398 break; 2399 } 2400 } 2401 2402 /* 2403 ** Clean up. 2404 */ 2405 2406 if (ni != NULL) 2407 ni_free(ni); 2408 if (lastni != NULL && ni != lastni) 2409 ni_free(lastni); 2410 2411 return propval; 2412 } 2413 2414 #endif /* NETINFO */ 2415 /* 2416 ** HARD_SYSLOG -- call syslog repeatedly until it works 2417 ** 2418 ** Needed on HP-UX, which apparently doesn't guarantee that 2419 ** syslog succeeds during interrupt handlers. 2420 */ 2421 2422 #ifdef __hpux 2423 2424 # define MAXSYSLOGTRIES 100 2425 # undef syslog 2426 2427 # ifdef __STDC__ 2428 hard_syslog(int pri, char *msg, ...) 2429 # else 2430 hard_syslog(pri, msg, va_alist) 2431 int pri; 2432 char *msg; 2433 va_dcl 2434 # endif 2435 { 2436 int i; 2437 char buf[SYSLOG_BUFSIZE * 2]; 2438 VA_LOCAL_DECL; 2439 2440 VA_START(msg); 2441 vsprintf(buf, msg, ap); 2442 VA_END; 2443 2444 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) 2445 continue; 2446 } 2447 2448 #endif 2449