122698Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 642825Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822698Sdist 922698Sdist #ifndef lint 10*55418Seric static char sccsid[] = "@(#)conf.c 5.41 (Berkeley) 07/20/92"; 1133728Sbostic #endif /* not lint */ 1222698Sdist 1314881Seric # include <sys/ioctl.h> 1424943Seric # include <sys/param.h> 1536928Sbostic # include <pwd.h> 163309Seric # include "sendmail.h" 1740980Sbostic # include "pathnames.h" 18404Seric 19294Seric /* 203309Seric ** CONF.C -- Sendmail Configuration Tables. 21294Seric ** 22294Seric ** Defines the configuration of this installation. 23294Seric ** 241388Seric ** Configuration Variables: 252897Seric ** HdrInfo -- a table describing well-known header fields. 262897Seric ** Each entry has the field name and some flags, 274147Seric ** which are described in sendmail.h. 284093Seric ** 294093Seric ** Notes: 304093Seric ** I have tried to put almost all the reasonable 314093Seric ** configuration information into the configuration 324093Seric ** file read at runtime. My intent is that anything 334093Seric ** here is a function of the version of UNIX you 344093Seric ** are running, or is really static -- for example 354093Seric ** the headers are a superset of widely used 364093Seric ** protocols. If you find yourself playing with 374093Seric ** this file too much, you may be making a mistake! 38294Seric */ 39294Seric 40294Seric 41294Seric 42294Seric 434437Seric /* 442897Seric ** Header info table 453057Seric ** Final (null) entry contains the flags used for any other field. 464147Seric ** 474147Seric ** Not all of these are actually handled specially by sendmail 484147Seric ** at this time. They are included as placeholders, to let 494147Seric ** you know that "someday" I intend to have sendmail do 504147Seric ** something with them. 512897Seric */ 522897Seric 532897Seric struct hdrinfo HdrInfo[] = 542897Seric { 558060Seric /* originator fields, most to least significant */ 5611417Seric "resent-sender", H_FROM|H_RESENT, 5711417Seric "resent-from", H_FROM|H_RESENT, 5825686Seric "resent-reply-to", H_FROM|H_RESENT, 599055Seric "sender", H_FROM, 609055Seric "from", H_FROM, 6125686Seric "reply-to", H_FROM, 629055Seric "full-name", H_ACHECK, 639055Seric "return-receipt-to", H_FROM, 649055Seric "errors-to", H_FROM, 658060Seric /* destination fields */ 669055Seric "to", H_RCPT, 6711417Seric "resent-to", H_RCPT|H_RESENT, 689055Seric "cc", H_RCPT, 6911417Seric "resent-cc", H_RCPT|H_RESENT, 709055Seric "bcc", H_RCPT|H_ACHECK, 7111417Seric "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 728060Seric /* message identification and control */ 7311417Seric "message-id", 0, 7411417Seric "resent-message-id", H_RESENT, 759055Seric "message", H_EOH, 769055Seric "text", H_EOH, 7711417Seric /* date fields */ 7811417Seric "date", 0, 7911417Seric "resent-date", H_RESENT, 808060Seric /* trace fields */ 819055Seric "received", H_TRACE|H_FORCE, 829055Seric "via", H_TRACE|H_FORCE, 839055Seric "mail-from", H_TRACE|H_FORCE, 848060Seric 859055Seric NULL, 0, 862897Seric }; 874166Seric 884166Seric 894166Seric /* 904166Seric ** ARPANET error message numbers. 914166Seric */ 924166Seric 937956Seric char Arpa_Info[] = "050"; /* arbitrary info */ 947956Seric char Arpa_TSyserr[] = "451"; /* some (transient) system error */ 957956Seric char Arpa_PSyserr[] = "554"; /* some (permanent) system error */ 967956Seric char Arpa_Usrerr[] = "554"; /* some (fatal) user error */ 974282Seric 984282Seric 994282Seric 1004282Seric /* 1014282Seric ** Location of system files/databases/etc. 1024282Seric */ 1034282Seric 10440980Sbostic char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ 10540980Sbostic char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ 1069039Seric 1079064Seric 1089064Seric 1099039Seric /* 11024943Seric ** Miscellaneous stuff. 1119039Seric */ 1129039Seric 11324943Seric int DtableSize = 50; /* max open files; reset in 4.2bsd */ 11424943Seric /* 11524943Seric ** SETDEFAULTS -- set default values 11624943Seric ** 11724943Seric ** Because of the way freezing is done, these must be initialized 11824943Seric ** using direct code. 11924943Seric ** 12024943Seric ** Parameters: 12124943Seric ** none. 12224943Seric ** 12324943Seric ** Returns: 12424943Seric ** none. 12524943Seric ** 12624943Seric ** Side Effects: 12724943Seric ** Initializes a bunch of global variables to their 12824943Seric ** default values. 12924943Seric */ 13024943Seric 13124943Seric setdefaults() 13224943Seric { 13324943Seric QueueLA = 8; 13424943Seric QueueFactor = 10000; 13524943Seric RefuseLA = 12; 13624943Seric SpaceSub = ' '; 13724981Seric WkRecipFact = 1000; 13824981Seric WkClassFact = 1800; 13925812Seric WkTimeFact = 9000; 14024981Seric FileMode = 0644; 14124981Seric DefUid = 1; 14224981Seric DefGid = 1; 14347284Seric CheckpointInterval = 10; 14451305Seric MaxHopCount = MAXHOP; 14552105Seric SendMode = SM_FORK; 14652105Seric ErrorMode = EM_PRINT; 14752106Seric EightBit = FALSE; 14854967Seric MaxMciCache = 1; 14954967Seric MciCacheTimeout = 300; 15040973Sbostic setdefuser(); 15153654Seric setupmaps(); 15224943Seric } 153294Seric 15440973Sbostic 1554326Seric /* 15640973Sbostic ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 15740973Sbostic */ 15840973Sbostic 15940973Sbostic setdefuser() 16040973Sbostic { 16140973Sbostic struct passwd *defpwent; 16240973Sbostic 16340973Sbostic if (DefUser != NULL) 16440973Sbostic free(DefUser); 16540973Sbostic if ((defpwent = getpwuid(DefUid)) != NULL) 16640973Sbostic DefUser = newstr(defpwent->pw_name); 16740973Sbostic else 16840973Sbostic DefUser = newstr("nobody"); 16940973Sbostic } 17053654Seric /* 17153654Seric ** SETUPMAPS -- set up map classes 17253654Seric ** 17353654Seric ** Since these are compiled in, they cannot be in the config file. 17453654Seric ** 17553654Seric */ 17640973Sbostic 17753654Seric setupmaps() 17853654Seric { 17953654Seric register STAB *s; 18053654Seric MAPCLASS *hostmapclass; 18153654Seric extern char *maphostname(); 18240973Sbostic 18353654Seric /* set up host name lookup map */ 18453654Seric s = stab("host", ST_MAPCLASS, ST_ENTER); 18553654Seric s->s_mapclass.map_init = NULL; 18653654Seric s->s_mapclass.map_lookup = maphostname; 18753654Seric hostmapclass = &s->s_mapclass; 18853654Seric 18953654Seric s = stab("host", ST_MAP, ST_ENTER); 19053654Seric s->s_map.map_class = hostmapclass; 19153654Seric s->s_map.map_flags = MF_VALID; 19253654Seric 19353654Seric /* 19453654Seric ** Set up other map classes. 19553654Seric */ 19653654Seric 19753654Seric # ifdef DBM_MAP 19853654Seric /* dbm file access */ 19953654Seric { 20053654Seric extern void dbm_map_init(); 20153654Seric extern char *dbm_map_lookup(); 20253654Seric 20353654Seric s = stab("dbm", ST_MAPCLASS, ST_ENTER); 20453654Seric s->s_mapclass.map_init = dbm_map_init; 20553654Seric s->s_mapclass.map_lookup = dbm_map_lookup; 20653654Seric } 20753654Seric # endif 20853654Seric 20953654Seric # ifdef BTREE_MAP 21053654Seric /* new database file access -- btree files */ 21153654Seric { 21253654Seric extern void bt_map_init(); 21353654Seric extern char *bt_map_lookup(); 21453654Seric 21553654Seric s = stab("btree", ST_MAPCLASS, ST_ENTER); 21653654Seric s->s_mapclass.map_init = bt_map_init; 21753654Seric s->s_mapclass.map_lookup = bt_map_lookup; 21853654Seric } 21953654Seric # endif 22053654Seric 22153654Seric # ifdef HASH_MAP 22253654Seric /* new database file access -- hash files */ 22353654Seric { 22453654Seric extern void hash_map_init(); 22553654Seric extern char *hash_map_lookup(); 22653654Seric 22753654Seric s = stab("hash", ST_MAPCLASS, ST_ENTER); 22853654Seric s->s_mapclass.map_init = hash_map_init; 22953654Seric s->s_mapclass.map_lookup = hash_map_lookup; 23053654Seric } 23153654Seric # endif 23253654Seric 23353654Seric # ifdef USERDB_MAP 23453654Seric /* user database */ 23553654Seric { 23653654Seric extern void udb_map_init(); 23753654Seric extern char *udb_map_lookup(); 23853654Seric 23953654Seric s = stab("udb", ST_MAPCLASS, ST_ENTER); 24053654Seric s->s_mapclass.map_init = udb_map_init; 24153654Seric s->s_mapclass.map_lookup = udb_map_lookup; 24253654Seric } 24353654Seric # endif 24453654Seric } 24553654Seric /* 2464326Seric ** GETRUID -- get real user id (V7) 2474326Seric */ 2484326Seric 2494326Seric getruid() 2504326Seric { 2519274Seric if (OpMode == MD_DAEMON) 2524536Seric return (RealUid); 2534536Seric else 2544536Seric return (getuid()); 2554326Seric } 2564326Seric 2574326Seric 2584326Seric /* 2594326Seric ** GETRGID -- get real group id (V7). 2604326Seric */ 2614326Seric 2624326Seric getrgid() 2634326Seric { 2649274Seric if (OpMode == MD_DAEMON) 2654536Seric return (RealGid); 2664536Seric else 2674536Seric return (getgid()); 2684326Seric } 26953654Seric /* 2709369Seric ** USERNAME -- return the user id of the logged in user. 2719369Seric ** 2729369Seric ** Parameters: 2739369Seric ** none. 2749369Seric ** 2759369Seric ** Returns: 2769369Seric ** The login name of the logged in user. 2779369Seric ** 2789369Seric ** Side Effects: 2799369Seric ** none. 2809369Seric ** 2819369Seric ** Notes: 2829369Seric ** The return value is statically allocated. 2839369Seric */ 2849369Seric 2859369Seric char * 2869369Seric username() 2879369Seric { 28817469Seric static char *myname = NULL; 2899369Seric extern char *getlogin(); 29019904Smiriam register struct passwd *pw; 2919369Seric 29217469Seric /* cache the result */ 29317469Seric if (myname == NULL) 29417469Seric { 29517469Seric myname = getlogin(); 29617469Seric if (myname == NULL || myname[0] == '\0') 29717469Seric { 29817469Seric 29917469Seric pw = getpwuid(getruid()); 30017469Seric if (pw != NULL) 30140993Sbostic myname = newstr(pw->pw_name); 30217469Seric } 30319904Smiriam else 30419904Smiriam { 30519873Smiriam 30640993Sbostic myname = newstr(myname); 30740993Sbostic if ((pw = getpwnam(myname)) == NULL || 30840993Sbostic getuid() != pw->pw_uid) 30919904Smiriam { 31019873Smiriam pw = getpwuid(getuid()); 31124945Seric if (pw != NULL) 31240993Sbostic myname = newstr(pw->pw_name); 31319873Smiriam } 31419873Smiriam } 31517469Seric if (myname == NULL || myname[0] == '\0') 31617469Seric { 31717469Seric syserr("Who are you?"); 31817469Seric myname = "postmaster"; 31917469Seric } 32017469Seric } 32117469Seric 32217469Seric return (myname); 3239369Seric } 3249369Seric /* 3254190Seric ** TTYPATH -- Get the path of the user's tty 326294Seric ** 327294Seric ** Returns the pathname of the user's tty. Returns NULL if 328294Seric ** the user is not logged in or if s/he has write permission 329294Seric ** denied. 330294Seric ** 331294Seric ** Parameters: 332294Seric ** none 333294Seric ** 334294Seric ** Returns: 335294Seric ** pathname of the user's tty. 336294Seric ** NULL if not logged in or write permission denied. 337294Seric ** 338294Seric ** Side Effects: 339294Seric ** none. 340294Seric ** 341294Seric ** WARNING: 342294Seric ** Return value is in a local buffer. 343294Seric ** 344294Seric ** Called By: 345294Seric ** savemail 346294Seric */ 347294Seric 348294Seric # include <sys/stat.h> 349294Seric 350294Seric char * 351294Seric ttypath() 352294Seric { 353294Seric struct stat stbuf; 354294Seric register char *pathn; 355294Seric extern char *ttyname(); 3564081Seric extern char *getlogin(); 357294Seric 358294Seric /* compute the pathname of the controlling tty */ 3599369Seric if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 3609369Seric (pathn = ttyname(0)) == NULL) 361294Seric { 362294Seric errno = 0; 363294Seric return (NULL); 364294Seric } 365294Seric 366294Seric /* see if we have write permission */ 3672967Seric if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 368294Seric { 369294Seric errno = 0; 370294Seric return (NULL); 371294Seric } 372294Seric 373294Seric /* see if the user is logged in */ 374294Seric if (getlogin() == NULL) 375294Seric return (NULL); 376294Seric 377294Seric /* looks good */ 378294Seric return (pathn); 379294Seric } 3802967Seric /* 3812967Seric ** CHECKCOMPAT -- check for From and To person compatible. 3822967Seric ** 3832967Seric ** This routine can be supplied on a per-installation basis 3842967Seric ** to determine whether a person is allowed to send a message. 3852967Seric ** This allows restriction of certain types of internet 3862967Seric ** forwarding or registration of users. 3872967Seric ** 3882967Seric ** If the hosts are found to be incompatible, an error 3892967Seric ** message should be given using "usrerr" and FALSE should 3902967Seric ** be returned. 3912967Seric ** 3924288Seric ** 'NoReturn' can be set to suppress the return-to-sender 3934288Seric ** function; this should be done on huge messages. 3944288Seric ** 3952967Seric ** Parameters: 3962967Seric ** to -- the person being sent to. 3972967Seric ** 3982967Seric ** Returns: 3992967Seric ** TRUE -- ok to send. 4002967Seric ** FALSE -- not ok. 4012967Seric ** 4022967Seric ** Side Effects: 4032967Seric ** none (unless you include the usrerr stuff) 4042967Seric */ 4052967Seric 4062967Seric bool 40755012Seric checkcompat(to, e) 4082967Seric register ADDRESS *to; 40955012Seric register ENVELOPE *e; 4102967Seric { 41112133Seric # ifdef lint 41212133Seric if (to == NULL) 41312133Seric to++; 41412133Seric # endif lint 41510698Seric # ifdef EXAMPLE_CODE 41610698Seric /* this code is intended as an example only */ 4174437Seric register STAB *s; 4184437Seric 4194437Seric s = stab("arpa", ST_MAILER, ST_FIND); 42055012Seric if (s != NULL && e->e_from.q_mailer != LocalMailer && 4219369Seric to->q_mailer == s->s_mailer) 4224437Seric { 4234437Seric usrerr("No ARPA mail through this machine: see your system administration"); 42410698Seric /* NoReturn = TRUE; to supress return copy */ 4254437Seric return (FALSE); 4264437Seric } 42710698Seric # endif EXAMPLE_CODE 4282967Seric return (TRUE); 4292967Seric } 4309369Seric /* 4319369Seric ** HOLDSIGS -- arrange to hold all signals 4329369Seric ** 4339369Seric ** Parameters: 4349369Seric ** none. 4359369Seric ** 4369369Seric ** Returns: 4379369Seric ** none. 4389369Seric ** 4399369Seric ** Side Effects: 4409369Seric ** Arranges that signals are held. 4419369Seric */ 4429369Seric 4439369Seric holdsigs() 4449369Seric { 4459369Seric } 4469369Seric /* 4479369Seric ** RLSESIGS -- arrange to release all signals 4489369Seric ** 4499369Seric ** This undoes the effect of holdsigs. 4509369Seric ** 4519369Seric ** Parameters: 4529369Seric ** none. 4539369Seric ** 4549369Seric ** Returns: 4559369Seric ** none. 4569369Seric ** 4579369Seric ** Side Effects: 4589369Seric ** Arranges that signals are released. 4599369Seric */ 4609369Seric 4619369Seric rlsesigs() 4629369Seric { 4639369Seric } 46414872Seric /* 46514872Seric ** GETLA -- get the current load average 46614872Seric ** 46714881Seric ** This code stolen from la.c. 46814881Seric ** 46914872Seric ** Parameters: 47014872Seric ** none. 47114872Seric ** 47214872Seric ** Returns: 47314872Seric ** The current load average as an integer. 47414872Seric ** 47514872Seric ** Side Effects: 47614872Seric ** none. 47714872Seric */ 47814872Seric 47951920Seric /* try to guess what style of load average we have */ 48051920Seric #define LA_ZERO 1 /* always return load average as zero */ 48151920Seric #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 48251920Seric #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 48351920Seric #define LA_SUBR 4 /* call getloadavg */ 48414872Seric 48551920Seric #ifndef LA_TYPE 48651920Seric # if defined(sun) 48751920Seric # define LA_TYPE LA_INT 48851920Seric # endif 48951920Seric # if defined(mips) 49051920Seric /* Ultrix or RISC/os */ 49151920Seric # define LA_TYPE LA_INT 49251920Seric # define LA_AVENRUN "avenrun" 49351920Seric # endif 49451920Seric # if defined(hpux) 49551920Seric # define LA_TYPE LA_FLOAT 49651920Seric # endif 49751920Seric # if defined(BSD) 49851920Seric # define LA_TYPE LA_SUBR 49951920Seric # endif 50051920Seric 50151920Seric # ifndef LA_TYPE 50251920Seric # define LA_TYPE LA_ZERO 50351920Seric # endif 50451920Seric #endif 50551920Seric 50651920Seric #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 50751920Seric 50814872Seric #include <nlist.h> 50951920Seric #include <fcntl.h> 51014872Seric 51151920Seric #ifndef LA_AVENRUN 51251920Seric #define LA_AVENRUN "_avenrun" 51351920Seric #endif 51451920Seric 51551920Seric /* _PATH_UNIX should be defined in <paths.h> */ 51651920Seric #ifndef _PATH_UNIX 51751920Seric # if defined(hpux) 51851920Seric # define _PATH_UNIX "/hp-ux" 51951920Seric # endif 52051920Seric # if defined(mips) && !defined(ultrix) 52151920Seric /* powerful RISC/os */ 52251920Seric # define _PATH_UNIX "/unix" 52351920Seric # endif 52451920Seric # ifndef _PATH_UNIX 52551920Seric # define _PATH_UNIX "/vmunix" 52651920Seric # endif 52751920Seric #endif 52851920Seric 52914872Seric struct nlist Nl[] = 53014872Seric { 53151920Seric { LA_AVENRUN }, 53214872Seric #define X_AVENRUN 0 53314872Seric { 0 }, 53414872Seric }; 53514872Seric 53651920Seric #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 53751920Seric # define FSHIFT 8 53851920Seric # define FSCALE (1 << FSHIFT) 53951920Seric #endif 54040930Srick 54114872Seric getla() 54214872Seric { 54314872Seric static int kmem = -1; 54451920Seric #if LA_TYPE == LA_INT 54524943Seric long avenrun[3]; 54651920Seric #else 54751920Seric double avenrun[3]; 54851920Seric #endif 54925615Seric extern off_t lseek(); 55014872Seric 55114872Seric if (kmem < 0) 55214872Seric { 55324945Seric kmem = open("/dev/kmem", 0, 0); 55414872Seric if (kmem < 0) 55514872Seric return (-1); 55651920Seric (void) fcntl(kmem, F_SETFD, 1); 55751920Seric nlist(_PATH_UNIX, Nl); 55814872Seric if (Nl[0].n_type == 0) 55914872Seric return (-1); 56014872Seric } 56124945Seric if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 56223118Seric read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 56319967Seric { 56419967Seric /* thank you Ian */ 56519967Seric return (-1); 56619967Seric } 56751920Seric #if LA_TYPE == LA_INT 56824943Seric return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 56951920Seric #else 57051920Seric return ((int) (avenrun[0] + 0.5)); 57151920Seric #endif 57214872Seric } 57314872Seric 57451773Seric #else 57551920Seric #if LA_TYPE == LA_SUBR 57651773Seric 57751773Seric getla() 57851773Seric { 57951920Seric double avenrun[3]; 58051920Seric 58151920Seric if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 58251920Seric return (-1); 58351920Seric return ((int) (avenrun[0] + 0.5)); 58451773Seric } 58551773Seric 58651773Seric #else 58751773Seric 58851773Seric getla() 58951773Seric { 59051920Seric return (0); 59151773Seric } 59251773Seric 59351773Seric #endif 59451773Seric #endif 59524943Seric /* 59624943Seric ** SHOULDQUEUE -- should this message be queued or sent? 59724943Seric ** 59824943Seric ** Compares the message cost to the load average to decide. 59924943Seric ** 60024943Seric ** Parameters: 60124943Seric ** pri -- the priority of the message in question. 60224943Seric ** 60324943Seric ** Returns: 60424943Seric ** TRUE -- if this message should be queued up for the 60524943Seric ** time being. 60624943Seric ** FALSE -- if the load is low enough to send this message. 60724943Seric ** 60824943Seric ** Side Effects: 60924943Seric ** none. 61024943Seric */ 61124943Seric 61224943Seric bool 61324943Seric shouldqueue(pri) 61424943Seric long pri; 61524943Seric { 61651920Seric if (CurrentLA < QueueLA) 61724943Seric return (FALSE); 61851920Seric return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 61924943Seric } 62024943Seric /* 62153037Seric ** REFUSECONNECTIONS -- decide if connections should be refused 62253037Seric ** 62353037Seric ** Parameters: 62453037Seric ** none. 62553037Seric ** 62653037Seric ** Returns: 62753037Seric ** TRUE if incoming SMTP connections should be refused 62853037Seric ** (for now). 62953037Seric ** FALSE if we should accept new work. 63053037Seric ** 63153037Seric ** Side Effects: 63253037Seric ** none. 63353037Seric */ 63453037Seric 63553037Seric bool 63653037Seric refuseconnections() 63753037Seric { 63853037Seric /* this is probably too simplistic */ 63953037Seric return (CurrentLA > RefuseLA); 64053037Seric } 64153037Seric /* 64224943Seric ** SETPROCTITLE -- set process title for ps 64324943Seric ** 64424943Seric ** Parameters: 64524943Seric ** fmt -- a printf style format string. 64624943Seric ** a, b, c -- possible parameters to fmt. 64724943Seric ** 64824943Seric ** Returns: 64924943Seric ** none. 65024943Seric ** 65124943Seric ** Side Effects: 65224943Seric ** Clobbers argv of our main procedure so ps(1) will 65324943Seric ** display the title. 65424943Seric */ 65524943Seric 65624943Seric /*VARARGS1*/ 65724943Seric setproctitle(fmt, a, b, c) 65824943Seric char *fmt; 65924943Seric { 66024943Seric # ifdef SETPROCTITLE 66124943Seric register char *p; 66225049Seric register int i; 66324943Seric extern char **Argv; 66424943Seric extern char *LastArgv; 66525049Seric char buf[MAXLINE]; 66624943Seric 66754996Seric p = buf; 66824943Seric 66954996Seric /* print sendmail: heading for grep */ 67054996Seric (void) strcpy(p, "sendmail: "); 67154996Seric p += strlen(p); 67224943Seric 67354996Seric /* print the argument string */ 67454996Seric (void) sprintf(p, fmt, a, b, c); 67554996Seric 67625049Seric i = strlen(buf); 67754996Seric if (i > LastArgv - Argv[0] - 2) 67825049Seric { 67954996Seric i = LastArgv - Argv[0] - 2; 68025049Seric buf[i] = '\0'; 68125049Seric } 68254996Seric (void) strcpy(Argv[0], buf); 68354997Seric p = &Argv[0][i]; 68424943Seric while (p < LastArgv) 68524943Seric *p++ = ' '; 68624943Seric # endif SETPROCTITLE 68724943Seric } 68825698Seric /* 68925698Seric ** REAPCHILD -- pick up the body of my child, lest it become a zombie 69025698Seric ** 69125698Seric ** Parameters: 69225698Seric ** none. 69325698Seric ** 69425698Seric ** Returns: 69525698Seric ** none. 69625698Seric ** 69725698Seric ** Side Effects: 69825698Seric ** Picks up extant zombies. 69925698Seric */ 70025698Seric 70125698Seric # include <sys/wait.h> 70225698Seric 70346928Sbostic void 70425698Seric reapchild() 70525698Seric { 70625698Seric # ifdef WNOHANG 70725698Seric union wait status; 70825698Seric 70946928Sbostic while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 71025698Seric continue; 71125698Seric # else WNOHANG 71225698Seric auto int status; 71325698Seric 71446928Sbostic while (wait((int *)&status) > 0) 71525698Seric continue; 71625698Seric # endif WNOHANG 71725698Seric } 718*55418Seric /* 719*55418Seric ** UNSETENV -- remove a variable from the environment 720*55418Seric ** 721*55418Seric ** Not needed on newer systems. 722*55418Seric ** 723*55418Seric ** Parameters: 724*55418Seric ** name -- the string name of the environment variable to be 725*55418Seric ** deleted from the current environment. 726*55418Seric ** 727*55418Seric ** Returns: 728*55418Seric ** none. 729*55418Seric ** 730*55418Seric ** Globals: 731*55418Seric ** environ -- a pointer to the current environment. 732*55418Seric ** 733*55418Seric ** Side Effects: 734*55418Seric ** Modifies environ. 735*55418Seric */ 736*55418Seric 737*55418Seric #ifdef UNSETENV 738*55418Seric 739*55418Seric void 740*55418Seric unsetenv(name) 741*55418Seric char *name; 742*55418Seric { 743*55418Seric extern char **environ; 744*55418Seric register char **pp; 745*55418Seric int len = strlen(name); 746*55418Seric 747*55418Seric for (pp = environ; *pp != NULL; pp++) 748*55418Seric { 749*55418Seric if (strncmp(name, *pp, len) == 0 && 750*55418Seric ((*pp)[len] == '=' || (*pp)[len] == '\0')) 751*55418Seric break; 752*55418Seric } 753*55418Seric 754*55418Seric for (; *pp != NULL; pp++) 755*55418Seric *pp = pp[1]; 756*55418Seric } 757*55418Seric 758*55418Seric #endif /* UNSETENV */ 759