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*53654Seric static char sccsid[] = "@(#)conf.c 5.36 (Berkeley) 05/25/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; 14840973Sbostic setdefuser(); 149*53654Seric setupmaps(); 15024943Seric } 151294Seric 15240973Sbostic 1534326Seric /* 15440973Sbostic ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 15540973Sbostic */ 15640973Sbostic 15740973Sbostic setdefuser() 15840973Sbostic { 15940973Sbostic struct passwd *defpwent; 16040973Sbostic 16140973Sbostic if (DefUser != NULL) 16240973Sbostic free(DefUser); 16340973Sbostic if ((defpwent = getpwuid(DefUid)) != NULL) 16440973Sbostic DefUser = newstr(defpwent->pw_name); 16540973Sbostic else 16640973Sbostic DefUser = newstr("nobody"); 16740973Sbostic } 168*53654Seric /* 169*53654Seric ** SETUPMAPS -- set up map classes 170*53654Seric ** 171*53654Seric ** Since these are compiled in, they cannot be in the config file. 172*53654Seric ** 173*53654Seric */ 17440973Sbostic 175*53654Seric setupmaps() 176*53654Seric { 177*53654Seric register STAB *s; 178*53654Seric MAPCLASS *hostmapclass; 179*53654Seric extern char *maphostname(); 18040973Sbostic 181*53654Seric /* set up host name lookup map */ 182*53654Seric s = stab("host", ST_MAPCLASS, ST_ENTER); 183*53654Seric s->s_mapclass.map_init = NULL; 184*53654Seric s->s_mapclass.map_lookup = maphostname; 185*53654Seric hostmapclass = &s->s_mapclass; 186*53654Seric 187*53654Seric s = stab("host", ST_MAP, ST_ENTER); 188*53654Seric s->s_map.map_class = hostmapclass; 189*53654Seric s->s_map.map_flags = MF_VALID; 190*53654Seric 191*53654Seric /* 192*53654Seric ** Set up other map classes. 193*53654Seric */ 194*53654Seric 195*53654Seric # ifdef DBM_MAP 196*53654Seric /* dbm file access */ 197*53654Seric { 198*53654Seric extern void dbm_map_init(); 199*53654Seric extern char *dbm_map_lookup(); 200*53654Seric 201*53654Seric s = stab("dbm", ST_MAPCLASS, ST_ENTER); 202*53654Seric s->s_mapclass.map_init = dbm_map_init; 203*53654Seric s->s_mapclass.map_lookup = dbm_map_lookup; 204*53654Seric } 205*53654Seric # endif 206*53654Seric 207*53654Seric # ifdef BTREE_MAP 208*53654Seric /* new database file access -- btree files */ 209*53654Seric { 210*53654Seric extern void bt_map_init(); 211*53654Seric extern char *bt_map_lookup(); 212*53654Seric 213*53654Seric s = stab("btree", ST_MAPCLASS, ST_ENTER); 214*53654Seric s->s_mapclass.map_init = bt_map_init; 215*53654Seric s->s_mapclass.map_lookup = bt_map_lookup; 216*53654Seric } 217*53654Seric # endif 218*53654Seric 219*53654Seric # ifdef HASH_MAP 220*53654Seric /* new database file access -- hash files */ 221*53654Seric { 222*53654Seric extern void hash_map_init(); 223*53654Seric extern char *hash_map_lookup(); 224*53654Seric 225*53654Seric s = stab("hash", ST_MAPCLASS, ST_ENTER); 226*53654Seric s->s_mapclass.map_init = hash_map_init; 227*53654Seric s->s_mapclass.map_lookup = hash_map_lookup; 228*53654Seric } 229*53654Seric # endif 230*53654Seric 231*53654Seric # ifdef USERDB_MAP 232*53654Seric /* user database */ 233*53654Seric { 234*53654Seric extern void udb_map_init(); 235*53654Seric extern char *udb_map_lookup(); 236*53654Seric 237*53654Seric s = stab("udb", ST_MAPCLASS, ST_ENTER); 238*53654Seric s->s_mapclass.map_init = udb_map_init; 239*53654Seric s->s_mapclass.map_lookup = udb_map_lookup; 240*53654Seric } 241*53654Seric # endif 242*53654Seric } 243*53654Seric /* 2444326Seric ** GETRUID -- get real user id (V7) 2454326Seric */ 2464326Seric 2474326Seric getruid() 2484326Seric { 2499274Seric if (OpMode == MD_DAEMON) 2504536Seric return (RealUid); 2514536Seric else 2524536Seric return (getuid()); 2534326Seric } 2544326Seric 2554326Seric 2564326Seric /* 2574326Seric ** GETRGID -- get real group id (V7). 2584326Seric */ 2594326Seric 2604326Seric getrgid() 2614326Seric { 2629274Seric if (OpMode == MD_DAEMON) 2634536Seric return (RealGid); 2644536Seric else 2654536Seric return (getgid()); 2664326Seric } 267*53654Seric /* 2689369Seric ** USERNAME -- return the user id of the logged in user. 2699369Seric ** 2709369Seric ** Parameters: 2719369Seric ** none. 2729369Seric ** 2739369Seric ** Returns: 2749369Seric ** The login name of the logged in user. 2759369Seric ** 2769369Seric ** Side Effects: 2779369Seric ** none. 2789369Seric ** 2799369Seric ** Notes: 2809369Seric ** The return value is statically allocated. 2819369Seric */ 2829369Seric 2839369Seric char * 2849369Seric username() 2859369Seric { 28617469Seric static char *myname = NULL; 2879369Seric extern char *getlogin(); 28819904Smiriam register struct passwd *pw; 2899369Seric 29017469Seric /* cache the result */ 29117469Seric if (myname == NULL) 29217469Seric { 29317469Seric myname = getlogin(); 29417469Seric if (myname == NULL || myname[0] == '\0') 29517469Seric { 29617469Seric 29717469Seric pw = getpwuid(getruid()); 29817469Seric if (pw != NULL) 29940993Sbostic myname = newstr(pw->pw_name); 30017469Seric } 30119904Smiriam else 30219904Smiriam { 30319873Smiriam 30440993Sbostic myname = newstr(myname); 30540993Sbostic if ((pw = getpwnam(myname)) == NULL || 30640993Sbostic getuid() != pw->pw_uid) 30719904Smiriam { 30819873Smiriam pw = getpwuid(getuid()); 30924945Seric if (pw != NULL) 31040993Sbostic myname = newstr(pw->pw_name); 31119873Smiriam } 31219873Smiriam } 31317469Seric if (myname == NULL || myname[0] == '\0') 31417469Seric { 31517469Seric syserr("Who are you?"); 31617469Seric myname = "postmaster"; 31717469Seric } 31817469Seric } 31917469Seric 32017469Seric return (myname); 3219369Seric } 3229369Seric /* 3234190Seric ** TTYPATH -- Get the path of the user's tty 324294Seric ** 325294Seric ** Returns the pathname of the user's tty. Returns NULL if 326294Seric ** the user is not logged in or if s/he has write permission 327294Seric ** denied. 328294Seric ** 329294Seric ** Parameters: 330294Seric ** none 331294Seric ** 332294Seric ** Returns: 333294Seric ** pathname of the user's tty. 334294Seric ** NULL if not logged in or write permission denied. 335294Seric ** 336294Seric ** Side Effects: 337294Seric ** none. 338294Seric ** 339294Seric ** WARNING: 340294Seric ** Return value is in a local buffer. 341294Seric ** 342294Seric ** Called By: 343294Seric ** savemail 344294Seric */ 345294Seric 346294Seric # include <sys/stat.h> 347294Seric 348294Seric char * 349294Seric ttypath() 350294Seric { 351294Seric struct stat stbuf; 352294Seric register char *pathn; 353294Seric extern char *ttyname(); 3544081Seric extern char *getlogin(); 355294Seric 356294Seric /* compute the pathname of the controlling tty */ 3579369Seric if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 3589369Seric (pathn = ttyname(0)) == NULL) 359294Seric { 360294Seric errno = 0; 361294Seric return (NULL); 362294Seric } 363294Seric 364294Seric /* see if we have write permission */ 3652967Seric if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 366294Seric { 367294Seric errno = 0; 368294Seric return (NULL); 369294Seric } 370294Seric 371294Seric /* see if the user is logged in */ 372294Seric if (getlogin() == NULL) 373294Seric return (NULL); 374294Seric 375294Seric /* looks good */ 376294Seric return (pathn); 377294Seric } 3782967Seric /* 3792967Seric ** CHECKCOMPAT -- check for From and To person compatible. 3802967Seric ** 3812967Seric ** This routine can be supplied on a per-installation basis 3822967Seric ** to determine whether a person is allowed to send a message. 3832967Seric ** This allows restriction of certain types of internet 3842967Seric ** forwarding or registration of users. 3852967Seric ** 3862967Seric ** If the hosts are found to be incompatible, an error 3872967Seric ** message should be given using "usrerr" and FALSE should 3882967Seric ** be returned. 3892967Seric ** 3904288Seric ** 'NoReturn' can be set to suppress the return-to-sender 3914288Seric ** function; this should be done on huge messages. 3924288Seric ** 3932967Seric ** Parameters: 3942967Seric ** to -- the person being sent to. 3952967Seric ** 3962967Seric ** Returns: 3972967Seric ** TRUE -- ok to send. 3982967Seric ** FALSE -- not ok. 3992967Seric ** 4002967Seric ** Side Effects: 4012967Seric ** none (unless you include the usrerr stuff) 4022967Seric */ 4032967Seric 4042967Seric bool 4052967Seric checkcompat(to) 4062967Seric register ADDRESS *to; 4072967Seric { 40812133Seric # ifdef lint 40912133Seric if (to == NULL) 41012133Seric to++; 41112133Seric # endif lint 41210698Seric # ifdef EXAMPLE_CODE 41310698Seric /* this code is intended as an example only */ 4144437Seric register STAB *s; 4154437Seric 4164437Seric s = stab("arpa", ST_MAILER, ST_FIND); 4179369Seric if (s != NULL && CurEnv->e_from.q_mailer != LocalMailer && 4189369Seric to->q_mailer == s->s_mailer) 4194437Seric { 4204437Seric usrerr("No ARPA mail through this machine: see your system administration"); 42110698Seric /* NoReturn = TRUE; to supress return copy */ 4224437Seric return (FALSE); 4234437Seric } 42410698Seric # endif EXAMPLE_CODE 4252967Seric return (TRUE); 4262967Seric } 4279369Seric /* 4289369Seric ** HOLDSIGS -- arrange to hold all signals 4299369Seric ** 4309369Seric ** Parameters: 4319369Seric ** none. 4329369Seric ** 4339369Seric ** Returns: 4349369Seric ** none. 4359369Seric ** 4369369Seric ** Side Effects: 4379369Seric ** Arranges that signals are held. 4389369Seric */ 4399369Seric 4409369Seric holdsigs() 4419369Seric { 4429369Seric } 4439369Seric /* 4449369Seric ** RLSESIGS -- arrange to release all signals 4459369Seric ** 4469369Seric ** This undoes the effect of holdsigs. 4479369Seric ** 4489369Seric ** Parameters: 4499369Seric ** none. 4509369Seric ** 4519369Seric ** Returns: 4529369Seric ** none. 4539369Seric ** 4549369Seric ** Side Effects: 4559369Seric ** Arranges that signals are released. 4569369Seric */ 4579369Seric 4589369Seric rlsesigs() 4599369Seric { 4609369Seric } 46114872Seric /* 46214872Seric ** GETLA -- get the current load average 46314872Seric ** 46414881Seric ** This code stolen from la.c. 46514881Seric ** 46614872Seric ** Parameters: 46714872Seric ** none. 46814872Seric ** 46914872Seric ** Returns: 47014872Seric ** The current load average as an integer. 47114872Seric ** 47214872Seric ** Side Effects: 47314872Seric ** none. 47414872Seric */ 47514872Seric 47651920Seric /* try to guess what style of load average we have */ 47751920Seric #define LA_ZERO 1 /* always return load average as zero */ 47851920Seric #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 47951920Seric #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 48051920Seric #define LA_SUBR 4 /* call getloadavg */ 48114872Seric 48251920Seric #ifndef LA_TYPE 48351920Seric # if defined(sun) 48451920Seric # define LA_TYPE LA_INT 48551920Seric # endif 48651920Seric # if defined(mips) 48751920Seric /* Ultrix or RISC/os */ 48851920Seric # define LA_TYPE LA_INT 48951920Seric # define LA_AVENRUN "avenrun" 49051920Seric # endif 49151920Seric # if defined(hpux) 49251920Seric # define LA_TYPE LA_FLOAT 49351920Seric # endif 49451920Seric # if defined(BSD) 49551920Seric # define LA_TYPE LA_SUBR 49651920Seric # endif 49751920Seric 49851920Seric # ifndef LA_TYPE 49951920Seric # define LA_TYPE LA_ZERO 50051920Seric # endif 50151920Seric #endif 50251920Seric 50351920Seric #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 50451920Seric 50514872Seric #include <nlist.h> 50651920Seric #include <fcntl.h> 50714872Seric 50851920Seric #ifndef LA_AVENRUN 50951920Seric #define LA_AVENRUN "_avenrun" 51051920Seric #endif 51151920Seric 51251920Seric /* _PATH_UNIX should be defined in <paths.h> */ 51351920Seric #ifndef _PATH_UNIX 51451920Seric # if defined(hpux) 51551920Seric # define _PATH_UNIX "/hp-ux" 51651920Seric # endif 51751920Seric # if defined(mips) && !defined(ultrix) 51851920Seric /* powerful RISC/os */ 51951920Seric # define _PATH_UNIX "/unix" 52051920Seric # endif 52151920Seric # ifndef _PATH_UNIX 52251920Seric # define _PATH_UNIX "/vmunix" 52351920Seric # endif 52451920Seric #endif 52551920Seric 52614872Seric struct nlist Nl[] = 52714872Seric { 52851920Seric { LA_AVENRUN }, 52914872Seric #define X_AVENRUN 0 53014872Seric { 0 }, 53114872Seric }; 53214872Seric 53351920Seric #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 53451920Seric # define FSHIFT 8 53551920Seric # define FSCALE (1 << FSHIFT) 53651920Seric #endif 53740930Srick 53814872Seric getla() 53914872Seric { 54014872Seric static int kmem = -1; 54151920Seric #if LA_TYPE == LA_INT 54224943Seric long avenrun[3]; 54351920Seric #else 54451920Seric double avenrun[3]; 54551920Seric #endif 54625615Seric extern off_t lseek(); 54714872Seric 54814872Seric if (kmem < 0) 54914872Seric { 55024945Seric kmem = open("/dev/kmem", 0, 0); 55114872Seric if (kmem < 0) 55214872Seric return (-1); 55351920Seric (void) fcntl(kmem, F_SETFD, 1); 55451920Seric nlist(_PATH_UNIX, Nl); 55514872Seric if (Nl[0].n_type == 0) 55614872Seric return (-1); 55714872Seric } 55824945Seric if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 55923118Seric read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 56019967Seric { 56119967Seric /* thank you Ian */ 56219967Seric return (-1); 56319967Seric } 56451920Seric #if LA_TYPE == LA_INT 56524943Seric return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 56651920Seric #else 56751920Seric return ((int) (avenrun[0] + 0.5)); 56851920Seric #endif 56914872Seric } 57014872Seric 57151773Seric #else 57251920Seric #if LA_TYPE == LA_SUBR 57351773Seric 57451773Seric getla() 57551773Seric { 57651920Seric double avenrun[3]; 57751920Seric 57851920Seric if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 57951920Seric return (-1); 58051920Seric return ((int) (avenrun[0] + 0.5)); 58151773Seric } 58251773Seric 58351773Seric #else 58451773Seric 58551773Seric getla() 58651773Seric { 58751920Seric return (0); 58851773Seric } 58951773Seric 59051773Seric #endif 59151773Seric #endif 59224943Seric /* 59324943Seric ** SHOULDQUEUE -- should this message be queued or sent? 59424943Seric ** 59524943Seric ** Compares the message cost to the load average to decide. 59624943Seric ** 59724943Seric ** Parameters: 59824943Seric ** pri -- the priority of the message in question. 59924943Seric ** 60024943Seric ** Returns: 60124943Seric ** TRUE -- if this message should be queued up for the 60224943Seric ** time being. 60324943Seric ** FALSE -- if the load is low enough to send this message. 60424943Seric ** 60524943Seric ** Side Effects: 60624943Seric ** none. 60724943Seric */ 60824943Seric 60924943Seric bool 61024943Seric shouldqueue(pri) 61124943Seric long pri; 61224943Seric { 61351920Seric if (CurrentLA < QueueLA) 61424943Seric return (FALSE); 61551920Seric return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 61624943Seric } 61724943Seric /* 61853037Seric ** REFUSECONNECTIONS -- decide if connections should be refused 61953037Seric ** 62053037Seric ** Parameters: 62153037Seric ** none. 62253037Seric ** 62353037Seric ** Returns: 62453037Seric ** TRUE if incoming SMTP connections should be refused 62553037Seric ** (for now). 62653037Seric ** FALSE if we should accept new work. 62753037Seric ** 62853037Seric ** Side Effects: 62953037Seric ** none. 63053037Seric */ 63153037Seric 63253037Seric bool 63353037Seric refuseconnections() 63453037Seric { 63553037Seric /* this is probably too simplistic */ 63653037Seric return (CurrentLA > RefuseLA); 63753037Seric } 63853037Seric /* 63924943Seric ** SETPROCTITLE -- set process title for ps 64024943Seric ** 64124943Seric ** Parameters: 64224943Seric ** fmt -- a printf style format string. 64324943Seric ** a, b, c -- possible parameters to fmt. 64424943Seric ** 64524943Seric ** Returns: 64624943Seric ** none. 64724943Seric ** 64824943Seric ** Side Effects: 64924943Seric ** Clobbers argv of our main procedure so ps(1) will 65024943Seric ** display the title. 65124943Seric */ 65224943Seric 65324943Seric /*VARARGS1*/ 65424943Seric setproctitle(fmt, a, b, c) 65524943Seric char *fmt; 65624943Seric { 65724943Seric # ifdef SETPROCTITLE 65824943Seric register char *p; 65925049Seric register int i; 66024943Seric extern char **Argv; 66124943Seric extern char *LastArgv; 66225049Seric char buf[MAXLINE]; 66324943Seric 66425049Seric (void) sprintf(buf, fmt, a, b, c); 66524943Seric 66624943Seric /* make ps print "(sendmail)" */ 66725049Seric p = Argv[0]; 66824943Seric *p++ = '-'; 66924943Seric 67025049Seric i = strlen(buf); 67125049Seric if (i > LastArgv - p - 2) 67225049Seric { 67325049Seric i = LastArgv - p - 2; 67425049Seric buf[i] = '\0'; 67525049Seric } 67625049Seric (void) strcpy(p, buf); 67725049Seric p += i; 67824943Seric while (p < LastArgv) 67924943Seric *p++ = ' '; 68024943Seric # endif SETPROCTITLE 68124943Seric } 68225698Seric /* 68325698Seric ** REAPCHILD -- pick up the body of my child, lest it become a zombie 68425698Seric ** 68525698Seric ** Parameters: 68625698Seric ** none. 68725698Seric ** 68825698Seric ** Returns: 68925698Seric ** none. 69025698Seric ** 69125698Seric ** Side Effects: 69225698Seric ** Picks up extant zombies. 69325698Seric */ 69425698Seric 69525698Seric # include <sys/wait.h> 69625698Seric 69746928Sbostic void 69825698Seric reapchild() 69925698Seric { 70025698Seric # ifdef WNOHANG 70125698Seric union wait status; 70225698Seric 70346928Sbostic while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 70425698Seric continue; 70525698Seric # else WNOHANG 70625698Seric auto int status; 70725698Seric 70846928Sbostic while (wait((int *)&status) > 0) 70925698Seric continue; 71025698Seric # endif WNOHANG 71125698Seric } 712