122717Sdist /* 242833Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642833Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822717Sdist 922717Sdist #ifndef lint 10*58247Seric static char sccsid[] = "@(#)util.c 6.8 (Berkeley) 02/26/93"; 1133731Sbostic #endif /* not lint */ 1222717Sdist 133151Seric # include <stdio.h> 144538Seric # include <sys/types.h> 154538Seric # include <sys/stat.h> 16298Seric # include <sysexits.h> 176890Seric # include <errno.h> 186890Seric # include "sendmail.h" 1957135Seric /* 20298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 21298Seric ** 22298Seric ** Runs through a string and strips off unquoted quote 23298Seric ** characters and quote bits. This is done in place. 24298Seric ** 25298Seric ** Parameters: 26298Seric ** s -- the string to strip. 27298Seric ** 28298Seric ** Returns: 29298Seric ** none. 30298Seric ** 31298Seric ** Side Effects: 32298Seric ** none. 33298Seric ** 34298Seric ** Called By: 35298Seric ** deliver 36298Seric */ 37298Seric 3854983Seric stripquotes(s) 39298Seric char *s; 40298Seric { 41298Seric register char *p; 42298Seric register char *q; 43298Seric register char c; 44298Seric 454101Seric if (s == NULL) 464101Seric return; 474101Seric 4854983Seric p = q = s; 4954983Seric do 50298Seric { 5154983Seric c = *p++; 5254983Seric if (c == '\\') 5354983Seric c = *p++; 5454983Seric else if (c == '"') 5554983Seric continue; 5654983Seric *q++ = c; 5754983Seric } while (c != '\0'); 58298Seric } 59298Seric /* 602900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 612900Seric ** 622900Seric ** Parameters: 632900Seric ** s -- the string to capitalize. 642900Seric ** 652900Seric ** Returns: 662900Seric ** a pointer to a properly capitalized string. 672900Seric ** 682900Seric ** Side Effects: 692900Seric ** none. 702900Seric */ 712900Seric 722900Seric char * 732900Seric capitalize(s) 742900Seric register char *s; 752900Seric { 762900Seric static char buf[50]; 772900Seric register char *p; 782900Seric 792900Seric p = buf; 802900Seric 812900Seric for (;;) 822900Seric { 8358050Seric while (!(isascii(*s) && isalpha(*s)) && *s != '\0') 842900Seric *p++ = *s++; 852900Seric if (*s == '\0') 862900Seric break; 8740999Sbostic *p++ = toupper(*s); 8840999Sbostic s++; 8958050Seric while (isascii(*s) && isalpha(*s)) 902900Seric *p++ = *s++; 912900Seric } 922900Seric 932900Seric *p = '\0'; 942900Seric return (buf); 952900Seric } 962900Seric /* 97298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 98298Seric ** 99298Seric ** THIS IS A CLUDGE. This should be made to give a proper 100298Seric ** error -- but after all, what can we do? 101298Seric ** 102298Seric ** Parameters: 103298Seric ** sz -- size of area to allocate. 104298Seric ** 105298Seric ** Returns: 106298Seric ** pointer to data region. 107298Seric ** 108298Seric ** Side Effects: 109298Seric ** Memory is allocated. 110298Seric */ 111298Seric 112298Seric char * 113298Seric xalloc(sz) 1147007Seric register int sz; 115298Seric { 116298Seric register char *p; 117298Seric 11823121Seric p = malloc((unsigned) sz); 119298Seric if (p == NULL) 120298Seric { 121298Seric syserr("Out of memory!!"); 12210685Seric abort(); 12310685Seric /* exit(EX_UNAVAILABLE); */ 124298Seric } 125298Seric return (p); 126298Seric } 127298Seric /* 1283151Seric ** COPYPLIST -- copy list of pointers. 1293151Seric ** 1303151Seric ** This routine is the equivalent of newstr for lists of 1313151Seric ** pointers. 1323151Seric ** 1333151Seric ** Parameters: 1343151Seric ** list -- list of pointers to copy. 1353151Seric ** Must be NULL terminated. 1363151Seric ** copycont -- if TRUE, copy the contents of the vector 1373151Seric ** (which must be a string) also. 1383151Seric ** 1393151Seric ** Returns: 1403151Seric ** a copy of 'list'. 1413151Seric ** 1423151Seric ** Side Effects: 1433151Seric ** none. 1443151Seric */ 1453151Seric 1463151Seric char ** 1473151Seric copyplist(list, copycont) 1483151Seric char **list; 1493151Seric bool copycont; 1503151Seric { 1513151Seric register char **vp; 1523151Seric register char **newvp; 1533151Seric 1543151Seric for (vp = list; *vp != NULL; vp++) 1553151Seric continue; 1563151Seric 1573151Seric vp++; 1583151Seric 15916897Seric newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 16016897Seric bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 1613151Seric 1623151Seric if (copycont) 1633151Seric { 1643151Seric for (vp = newvp; *vp != NULL; vp++) 1653151Seric *vp = newstr(*vp); 1663151Seric } 1673151Seric 1683151Seric return (newvp); 1693151Seric } 1703151Seric /* 17158170Seric ** COPYQUEUE -- copy address queue. 17258170Seric ** 17358170Seric ** This routine is the equivalent of newstr for address queues 17458170Seric ** addresses marked with QDONTSEND aren't copied 17558170Seric ** 17658170Seric ** Parameters: 17758170Seric ** addr -- list of address structures to copy. 17858170Seric ** 17958170Seric ** Returns: 18058170Seric ** a copy of 'addr'. 18158170Seric ** 18258170Seric ** Side Effects: 18358170Seric ** none. 18458170Seric */ 18558170Seric 18658170Seric ADDRESS * 18758170Seric copyqueue(addr) 18858170Seric ADDRESS *addr; 18958170Seric { 19058170Seric register ADDRESS *newaddr; 19158170Seric ADDRESS *ret; 19258170Seric register ADDRESS **tail = &ret; 19358170Seric 19458170Seric while (addr != NULL) 19558170Seric { 19658170Seric if (!bitset(QDONTSEND, addr->q_flags)) 19758170Seric { 19858170Seric newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 19958170Seric STRUCTCOPY(*addr, *newaddr); 20058170Seric *tail = newaddr; 20158170Seric tail = &newaddr->q_next; 20258170Seric } 20358170Seric addr = addr->q_next; 20458170Seric } 20558170Seric *tail = NULL; 20658170Seric 20758170Seric return ret; 20858170Seric } 20958170Seric /* 2103151Seric ** PRINTAV -- print argument vector. 2113151Seric ** 2123151Seric ** Parameters: 2133151Seric ** av -- argument vector. 2143151Seric ** 2153151Seric ** Returns: 2163151Seric ** none. 2173151Seric ** 2183151Seric ** Side Effects: 2193151Seric ** prints av. 2203151Seric */ 2213151Seric 2223151Seric printav(av) 2233151Seric register char **av; 2243151Seric { 2253151Seric while (*av != NULL) 2263151Seric { 2278063Seric if (tTd(0, 44)) 2288063Seric printf("\n\t%08x=", *av); 2298063Seric else 23023105Seric (void) putchar(' '); 2313151Seric xputs(*av++); 2323151Seric } 23323105Seric (void) putchar('\n'); 2343151Seric } 2353151Seric /* 2363151Seric ** LOWER -- turn letter into lower case. 2373151Seric ** 2383151Seric ** Parameters: 2393151Seric ** c -- character to turn into lower case. 2403151Seric ** 2413151Seric ** Returns: 2423151Seric ** c, in lower case. 2433151Seric ** 2443151Seric ** Side Effects: 2453151Seric ** none. 2463151Seric */ 2473151Seric 2483151Seric char 2493151Seric lower(c) 2503151Seric register char c; 2513151Seric { 25258050Seric return((isascii(c) && isupper(c)) ? tolower(c) : c); 2533151Seric } 2543151Seric /* 2553151Seric ** XPUTS -- put string doing control escapes. 2563151Seric ** 2573151Seric ** Parameters: 2583151Seric ** s -- string to put. 2593151Seric ** 2603151Seric ** Returns: 2613151Seric ** none. 2623151Seric ** 2633151Seric ** Side Effects: 2643151Seric ** output to stdout 2653151Seric */ 2663151Seric 2673151Seric xputs(s) 2683151Seric register char *s; 2693151Seric { 27058050Seric register int c; 27151781Seric register struct metamac *mp; 27251781Seric extern struct metamac MetaMacros[]; 2733151Seric 2748055Seric if (s == NULL) 2758055Seric { 2768055Seric printf("<null>"); 2778055Seric return; 2788055Seric } 27958050Seric while ((c = (*s++ & 0377)) != '\0') 2803151Seric { 2813151Seric if (!isascii(c)) 2823151Seric { 28358050Seric if (c == MATCHREPL || c == MACROEXPAND) 28458050Seric { 28558050Seric putchar('$'); 28658050Seric continue; 28758050Seric } 28858050Seric for (mp = MetaMacros; mp->metaname != '\0'; mp++) 28958050Seric { 29058050Seric if ((mp->metaval & 0377) == c) 29158050Seric { 29258050Seric printf("$%c", mp->metaname); 29358050Seric break; 29458050Seric } 29558050Seric } 29658050Seric if (mp->metaname != '\0') 29758050Seric continue; 29823105Seric (void) putchar('\\'); 2993151Seric c &= 0177; 3003151Seric } 30157589Seric if (isprint(c)) 3023151Seric { 30357589Seric putchar(c); 30457589Seric continue; 30557589Seric } 30652050Seric 30757589Seric /* wasn't a meta-macro -- find another way to print it */ 30857589Seric switch (c) 30957589Seric { 31057589Seric case '\0': 31157589Seric continue; 31252050Seric 31357589Seric case '\n': 31457589Seric c = 'n'; 31557589Seric break; 31652050Seric 31757589Seric case '\r': 31857589Seric c = 'r'; 31957589Seric break; 32052637Seric 32157589Seric case '\t': 32257589Seric c = 't'; 32357589Seric break; 32457589Seric 32557589Seric default: 32657589Seric (void) putchar('^'); 32757589Seric (void) putchar(c ^ 0100); 32857589Seric continue; 3293151Seric } 3303151Seric } 3314086Seric (void) fflush(stdout); 3323151Seric } 3333151Seric /* 3343151Seric ** MAKELOWER -- Translate a line into lower case 3353151Seric ** 3363151Seric ** Parameters: 3373151Seric ** p -- the string to translate. If NULL, return is 3383151Seric ** immediate. 3393151Seric ** 3403151Seric ** Returns: 3413151Seric ** none. 3423151Seric ** 3433151Seric ** Side Effects: 3443151Seric ** String pointed to by p is translated to lower case. 3453151Seric ** 3463151Seric ** Called By: 3473151Seric ** parse 3483151Seric */ 3493151Seric 3503151Seric makelower(p) 3513151Seric register char *p; 3523151Seric { 3533151Seric register char c; 3543151Seric 3553151Seric if (p == NULL) 3563151Seric return; 3573151Seric for (; (c = *p) != '\0'; p++) 3583151Seric if (isascii(c) && isupper(c)) 35933724Sbostic *p = tolower(c); 3603151Seric } 3614059Seric /* 3625196Seric ** BUILDFNAME -- build full name from gecos style entry. 3634375Seric ** 3645196Seric ** This routine interprets the strange entry that would appear 3655196Seric ** in the GECOS field of the password file. 3665196Seric ** 3674375Seric ** Parameters: 3685196Seric ** p -- name to build. 3695196Seric ** login -- the login name of this user (for &). 3705196Seric ** buf -- place to put the result. 3714375Seric ** 3724375Seric ** Returns: 3734375Seric ** none. 3744375Seric ** 3754375Seric ** Side Effects: 3764375Seric ** none. 3774375Seric */ 3784375Seric 37954984Seric buildfname(gecos, login, buf) 38054984Seric register char *gecos; 3815196Seric char *login; 3824375Seric char *buf; 3834375Seric { 38454984Seric register char *p; 3854375Seric register char *bp = buf; 38654984Seric int l; 3874375Seric 38854984Seric if (*gecos == '*') 38954984Seric gecos++; 39054984Seric 39157123Seric /* find length of final string */ 39254984Seric l = 0; 39354984Seric for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 39454984Seric { 39554984Seric if (*p == '&') 39654984Seric l += strlen(login); 39754984Seric else 39854984Seric l++; 39954984Seric } 40054984Seric 40154984Seric /* now fill in buf */ 40255193Seric for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 4034375Seric { 4044375Seric if (*p == '&') 4054375Seric { 4065196Seric (void) strcpy(bp, login); 4074375Seric *bp = toupper(*bp); 4084375Seric while (*bp != '\0') 4094375Seric bp++; 4104375Seric } 4114375Seric else 41255193Seric *bp++ = *p; 4134375Seric } 4144375Seric *bp = '\0'; 4154375Seric } 4164375Seric /* 4174538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 4184538Seric ** 4194538Seric ** Parameters: 4204538Seric ** fn -- filename to check. 4214538Seric ** uid -- uid to compare against. 4224538Seric ** mode -- mode bits that must match. 4234538Seric ** 4244538Seric ** Returns: 425*58247Seric ** 0 if fn exists, is owned by uid, and matches mode. 426*58247Seric ** An errno otherwise. The actual errno is cleared. 4274538Seric ** 4284538Seric ** Side Effects: 4294538Seric ** none. 4304538Seric */ 4314538Seric 432*58247Seric int 4334538Seric safefile(fn, uid, mode) 4344538Seric char *fn; 43555372Seric uid_t uid; 4364538Seric int mode; 4374538Seric { 4384538Seric struct stat stbuf; 4394538Seric 440*58247Seric if (stat(fn, &stbuf) < 0) 441*58247Seric { 442*58247Seric int ret = errno; 443*58247Seric 444*58247Seric errno = 0; 445*58247Seric return ret; 446*58247Seric } 447*58247Seric if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) 448*58247Seric return 0; 449*58247Seric return EPERM; 4504538Seric } 4514538Seric /* 4524557Seric ** FIXCRLF -- fix <CR><LF> in line. 4534557Seric ** 4544557Seric ** Looks for the <CR><LF> combination and turns it into the 4554557Seric ** UNIX canonical <NL> character. It only takes one line, 4564557Seric ** i.e., it is assumed that the first <NL> found is the end 4574557Seric ** of the line. 4584557Seric ** 4594557Seric ** Parameters: 4604557Seric ** line -- the line to fix. 4614557Seric ** stripnl -- if true, strip the newline also. 4624557Seric ** 4634557Seric ** Returns: 4644557Seric ** none. 4654557Seric ** 4664557Seric ** Side Effects: 4674557Seric ** line is changed in place. 4684557Seric */ 4694557Seric 4704557Seric fixcrlf(line, stripnl) 4714557Seric char *line; 4724557Seric bool stripnl; 4734557Seric { 4744557Seric register char *p; 4754557Seric 47656795Seric p = strchr(line, '\n'); 4774557Seric if (p == NULL) 4784557Seric return; 47936291Sbostic if (p > line && p[-1] == '\r') 4804557Seric p--; 4814557Seric if (!stripnl) 4824557Seric *p++ = '\n'; 4834557Seric *p = '\0'; 4844557Seric } 4854557Seric /* 4866890Seric ** DFOPEN -- determined file open 4876890Seric ** 4886890Seric ** This routine has the semantics of fopen, except that it will 4896890Seric ** keep trying a few times to make this happen. The idea is that 4906890Seric ** on very loaded systems, we may run out of resources (inodes, 4916890Seric ** whatever), so this tries to get around it. 4926890Seric */ 4936890Seric 4946890Seric FILE * 4956890Seric dfopen(filename, mode) 4966890Seric char *filename; 4976890Seric char *mode; 4986890Seric { 4996890Seric register int tries; 5006890Seric register FILE *fp; 5016890Seric 5026890Seric for (tries = 0; tries < 10; tries++) 5036890Seric { 50425618Seric sleep((unsigned) (10 * tries)); 5056890Seric errno = 0; 5066890Seric fp = fopen(filename, mode); 5079376Seric if (fp != NULL) 5086890Seric break; 5099376Seric if (errno != ENFILE && errno != EINTR) 5109376Seric break; 5116890Seric } 51256328Seric if (fp != NULL) 51356328Seric { 51456328Seric #ifdef FLOCK 51556328Seric int locktype; 51656328Seric 51756328Seric /* lock the file to avoid accidental conflicts */ 51856328Seric if (*mode == 'w' || *mode == 'a') 51956328Seric locktype = LOCK_EX; 52056328Seric else 52156328Seric locktype = LOCK_SH; 52256328Seric (void) flock(fileno(fp), locktype); 52356328Seric #endif 52456328Seric errno = 0; 52556328Seric } 5266890Seric return (fp); 5276890Seric } 5287124Seric /* 5297124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 5307124Seric ** 5317753Seric ** This routine always guarantees outputing a newline (or CRLF, 5327753Seric ** as appropriate) at the end of the string. 5337753Seric ** 5347124Seric ** Parameters: 5357124Seric ** l -- line to put. 5367124Seric ** fp -- file to put it onto. 53710172Seric ** m -- the mailer used to control output. 5387124Seric ** 5397124Seric ** Returns: 5407124Seric ** none 5417124Seric ** 5427124Seric ** Side Effects: 5437124Seric ** output of l to fp. 5447124Seric */ 5457124Seric 54610172Seric putline(l, fp, m) 5477753Seric register char *l; 5487124Seric FILE *fp; 54910172Seric MAILER *m; 5507124Seric { 5517124Seric register char *p; 55247157Sbostic register char svchar; 5537124Seric 55411275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 55552106Seric if (bitnset(M_7BITS, m->m_flags)) 55611275Seric { 55747157Sbostic for (p = l; svchar = *p; ++p) 55847157Sbostic if (svchar & 0200) 55947157Sbostic *p = svchar &~ 0200; 56011275Seric } 56111275Seric 5627753Seric do 5637124Seric { 5647753Seric /* find the end of the line */ 56556795Seric p = strchr(l, '\n'); 5667753Seric if (p == NULL) 5677753Seric p = &l[strlen(l)]; 5687124Seric 5697753Seric /* check for line overflow */ 57052106Seric while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 5717753Seric { 57252106Seric register char *q = &l[m->m_linelimit - 1]; 5737124Seric 5747753Seric svchar = *q; 5757753Seric *q = '\0'; 57610685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 57723105Seric (void) putc('.', fp); 5787753Seric fputs(l, fp); 57923105Seric (void) putc('!', fp); 58010326Seric fputs(m->m_eol, fp); 5817753Seric *q = svchar; 5827753Seric l = q; 5837753Seric } 5847124Seric 5857753Seric /* output last part */ 58610685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 58723105Seric (void) putc('.', fp); 58847157Sbostic for ( ; l < p; ++l) 58947157Sbostic (void) putc(*l, fp); 59010326Seric fputs(m->m_eol, fp); 5917753Seric if (*l == '\n') 59247157Sbostic ++l; 5937753Seric } while (l[0] != '\0'); 5947124Seric } 5957676Seric /* 5967676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5977676Seric ** 5987676Seric ** Parameters: 5997676Seric ** f -- name of file to unlink. 6007676Seric ** 6017676Seric ** Returns: 6027676Seric ** none. 6037676Seric ** 6047676Seric ** Side Effects: 6057676Seric ** f is unlinked. 6067676Seric */ 6077676Seric 6087676Seric xunlink(f) 6097676Seric char *f; 6107676Seric { 6117676Seric register int i; 6127676Seric 6137676Seric # ifdef LOG 61458020Seric if (LogLevel > 98) 61558020Seric syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 61656795Seric # endif /* LOG */ 6177676Seric 6187676Seric i = unlink(f); 6197676Seric # ifdef LOG 62058020Seric if (i < 0 && LogLevel > 97) 6217942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 62256795Seric # endif /* LOG */ 6237676Seric } 6247685Seric /* 62514885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 6267685Seric ** 6277685Seric ** Parameters: 6287685Seric ** buf -- place to put the input line. 6297685Seric ** siz -- size of buf. 6307685Seric ** fp -- file to read from. 63157384Seric ** timeout -- the timeout before error occurs. 6327685Seric ** 6337685Seric ** Returns: 63415533Seric ** NULL on error (including timeout). This will also leave 63515533Seric ** buf containing a null string. 6367685Seric ** buf otherwise. 6377685Seric ** 6387685Seric ** Side Effects: 6397685Seric ** none. 6407685Seric */ 6417685Seric 64214885Seric static jmp_buf CtxReadTimeout; 6437685Seric 6447685Seric char * 64557384Seric sfgets(buf, siz, fp, timeout) 6467685Seric char *buf; 6477685Seric int siz; 6487685Seric FILE *fp; 64957384Seric time_t timeout; 6507685Seric { 6517942Seric register EVENT *ev = NULL; 6527685Seric register char *p; 65346928Sbostic static int readtimeout(); 6547685Seric 65514885Seric /* set the timeout */ 65657384Seric if (timeout != 0) 65714885Seric { 65814885Seric if (setjmp(CtxReadTimeout) != 0) 65914885Seric { 66036233Skarels # ifdef LOG 66136230Skarels syslog(LOG_NOTICE, 66236230Skarels "timeout waiting for input from %s\n", 66357642Seric CurHostName? CurHostName: "local"); 66436233Skarels # endif 66536230Skarels errno = 0; 66640964Sbostic usrerr("451 timeout waiting for input"); 66719037Seric buf[0] = '\0'; 66814885Seric return (NULL); 66914885Seric } 67057384Seric ev = setevent(timeout, readtimeout, 0); 67114885Seric } 67214885Seric 67314885Seric /* try to read */ 67415533Seric p = NULL; 67515533Seric while (p == NULL && !feof(fp) && !ferror(fp)) 6767942Seric { 6777942Seric errno = 0; 6787942Seric p = fgets(buf, siz, fp); 67915533Seric if (errno == EINTR) 68015533Seric clearerr(fp); 68115533Seric } 68214885Seric 68314885Seric /* clear the event if it has not sprung */ 6847685Seric clrevent(ev); 68514885Seric 68614885Seric /* clean up the books and exit */ 6878055Seric LineNumber++; 68815533Seric if (p == NULL) 68916880Seric { 69015533Seric buf[0] = '\0'; 69116880Seric return (NULL); 69216880Seric } 69352106Seric if (!EightBit) 69452106Seric for (p = buf; *p != '\0'; p++) 69552106Seric *p &= ~0200; 69616880Seric return (buf); 6977685Seric } 6987685Seric 6997685Seric static 7007685Seric readtimeout() 7017685Seric { 70214885Seric longjmp(CtxReadTimeout, 1); 7037685Seric } 7047786Seric /* 7057786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 7067786Seric ** 7077786Seric ** Parameters: 7087786Seric ** buf -- place to put result. 7097786Seric ** n -- bytes available. 7107786Seric ** f -- file to read from. 7117786Seric ** 7127786Seric ** Returns: 71357135Seric ** input line(s) on success, NULL on error or EOF. 71457135Seric ** This will normally be buf -- unless the line is too 71557135Seric ** long, when it will be xalloc()ed. 7167786Seric ** 7177786Seric ** Side Effects: 7187786Seric ** buf gets lines from f, with continuation lines (lines 7197786Seric ** with leading white space) appended. CRLF's are mapped 7207786Seric ** into single newlines. Any trailing NL is stripped. 7217786Seric */ 7227786Seric 7237786Seric char * 7247786Seric fgetfolded(buf, n, f) 7257786Seric char *buf; 7267786Seric register int n; 7277786Seric FILE *f; 7287786Seric { 7297786Seric register char *p = buf; 73057135Seric char *bp = buf; 7317786Seric register int i; 7327786Seric 7337786Seric n--; 73417350Seric while ((i = getc(f)) != EOF) 7357786Seric { 73617350Seric if (i == '\r') 73717350Seric { 73817350Seric i = getc(f); 73917350Seric if (i != '\n') 74017350Seric { 74117350Seric if (i != EOF) 74223105Seric (void) ungetc(i, f); 74317350Seric i = '\r'; 74417350Seric } 74517350Seric } 74657135Seric if (--n <= 0) 74757135Seric { 74857135Seric /* allocate new space */ 74957135Seric char *nbp; 75057135Seric int nn; 75157135Seric 75257135Seric nn = (p - bp); 75357232Seric if (nn < MEMCHUNKSIZE) 75457135Seric nn *= 2; 75557135Seric else 75657232Seric nn += MEMCHUNKSIZE; 75757135Seric nbp = xalloc(nn); 75857135Seric bcopy(bp, nbp, p - bp); 75957135Seric p = &nbp[p - bp]; 76057135Seric if (bp != buf) 76157135Seric free(bp); 76257135Seric bp = nbp; 76357135Seric n = nn - (p - bp); 76457135Seric } 76557135Seric *p++ = i; 76617350Seric if (i == '\n') 76717350Seric { 76817350Seric LineNumber++; 76917350Seric i = getc(f); 77017350Seric if (i != EOF) 77123105Seric (void) ungetc(i, f); 77217350Seric if (i != ' ' && i != '\t') 77352647Seric break; 77417350Seric } 7757786Seric } 77657135Seric if (p == bp) 77752647Seric return (NULL); 77852647Seric *--p = '\0'; 77957135Seric return (bp); 7807786Seric } 7817860Seric /* 7827886Seric ** CURTIME -- return current time. 7837886Seric ** 7847886Seric ** Parameters: 7857886Seric ** none. 7867886Seric ** 7877886Seric ** Returns: 7887886Seric ** the current time. 7897886Seric ** 7907886Seric ** Side Effects: 7917886Seric ** none. 7927886Seric */ 7937886Seric 7947886Seric time_t 7957886Seric curtime() 7967886Seric { 7977886Seric auto time_t t; 7987886Seric 7997886Seric (void) time(&t); 8007886Seric return (t); 8017886Seric } 8028264Seric /* 8038264Seric ** ATOBOOL -- convert a string representation to boolean. 8048264Seric ** 8058264Seric ** Defaults to "TRUE" 8068264Seric ** 8078264Seric ** Parameters: 8088264Seric ** s -- string to convert. Takes "tTyY" as true, 8098264Seric ** others as false. 8108264Seric ** 8118264Seric ** Returns: 8128264Seric ** A boolean representation of the string. 8138264Seric ** 8148264Seric ** Side Effects: 8158264Seric ** none. 8168264Seric */ 8178264Seric 8188264Seric bool 8198264Seric atobool(s) 8208264Seric register char *s; 8218264Seric { 82256795Seric if (*s == '\0' || strchr("tTyY", *s) != NULL) 8238264Seric return (TRUE); 8248264Seric return (FALSE); 8258264Seric } 8269048Seric /* 8279048Seric ** ATOOCT -- convert a string representation to octal. 8289048Seric ** 8299048Seric ** Parameters: 8309048Seric ** s -- string to convert. 8319048Seric ** 8329048Seric ** Returns: 8339048Seric ** An integer representing the string interpreted as an 8349048Seric ** octal number. 8359048Seric ** 8369048Seric ** Side Effects: 8379048Seric ** none. 8389048Seric */ 8399048Seric 8409048Seric atooct(s) 8419048Seric register char *s; 8429048Seric { 8439048Seric register int i = 0; 8449048Seric 8459048Seric while (*s >= '0' && *s <= '7') 8469048Seric i = (i << 3) | (*s++ - '0'); 8479048Seric return (i); 8489048Seric } 8499376Seric /* 8509376Seric ** WAITFOR -- wait for a particular process id. 8519376Seric ** 8529376Seric ** Parameters: 8539376Seric ** pid -- process id to wait for. 8549376Seric ** 8559376Seric ** Returns: 8569376Seric ** status of pid. 8579376Seric ** -1 if pid never shows up. 8589376Seric ** 8599376Seric ** Side Effects: 8609376Seric ** none. 8619376Seric */ 8629376Seric 8639376Seric waitfor(pid) 8649376Seric int pid; 8659376Seric { 8669376Seric auto int st; 8679376Seric int i; 8689376Seric 8699376Seric do 8709376Seric { 8719376Seric errno = 0; 8729376Seric i = wait(&st); 8739376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 8749376Seric if (i < 0) 8759376Seric st = -1; 8769376Seric return (st); 8779376Seric } 8789376Seric /* 87910685Seric ** BITINTERSECT -- tell if two bitmaps intersect 88010685Seric ** 88110685Seric ** Parameters: 88210685Seric ** a, b -- the bitmaps in question 88310685Seric ** 88410685Seric ** Returns: 88510685Seric ** TRUE if they have a non-null intersection 88610685Seric ** FALSE otherwise 88710685Seric ** 88810685Seric ** Side Effects: 88910685Seric ** none. 89010685Seric */ 89110685Seric 89210685Seric bool 89310685Seric bitintersect(a, b) 89410685Seric BITMAP a; 89510685Seric BITMAP b; 89610685Seric { 89710685Seric int i; 89810685Seric 89910685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 90010685Seric if ((a[i] & b[i]) != 0) 90110685Seric return (TRUE); 90210685Seric return (FALSE); 90310685Seric } 90410685Seric /* 90510685Seric ** BITZEROP -- tell if a bitmap is all zero 90610685Seric ** 90710685Seric ** Parameters: 90810685Seric ** map -- the bit map to check 90910685Seric ** 91010685Seric ** Returns: 91110685Seric ** TRUE if map is all zero. 91210685Seric ** FALSE if there are any bits set in map. 91310685Seric ** 91410685Seric ** Side Effects: 91510685Seric ** none. 91610685Seric */ 91710685Seric 91810685Seric bool 91910685Seric bitzerop(map) 92010685Seric BITMAP map; 92110685Seric { 92210685Seric int i; 92310685Seric 92410685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 92510685Seric if (map[i] != 0) 92610685Seric return (FALSE); 92710685Seric return (TRUE); 92810685Seric } 929*58247Seric /* 930*58247Seric ** TRANSIENTERROR -- tell if an error code indicates a transient failure 931*58247Seric ** 932*58247Seric ** This looks at an errno value and tells if this is likely to 933*58247Seric ** go away if retried later. 934*58247Seric ** 935*58247Seric ** Parameters: 936*58247Seric ** err -- the errno code to classify. 937*58247Seric ** 938*58247Seric ** Returns: 939*58247Seric ** TRUE if this is probably transient. 940*58247Seric ** FALSE otherwise. 941*58247Seric */ 942*58247Seric 943*58247Seric bool 944*58247Seric transienterror(err) 945*58247Seric int err; 946*58247Seric { 947*58247Seric switch (err) 948*58247Seric { 949*58247Seric case EIO: /* I/O error */ 950*58247Seric case ENXIO: /* Device not configured */ 951*58247Seric case EAGAIN: /* Resource temporarily unavailable */ 952*58247Seric case ENOMEM: /* Cannot allocate memory */ 953*58247Seric case ENODEV: /* Operation not supported by device */ 954*58247Seric case ENFILE: /* Too many open files in system */ 955*58247Seric case EMFILE: /* Too many open files */ 956*58247Seric case ENOSPC: /* No space left on device */ 957*58247Seric #ifdef ETIMEDOUT 958*58247Seric case ETIMEDOUT: /* Connection timed out */ 959*58247Seric #endif 960*58247Seric #ifdef ESTALE 961*58247Seric case ESTALE: /* Stale NFS file handle */ 962*58247Seric #endif 963*58247Seric #ifdef ENETDOWN 964*58247Seric case ENETDOWN: /* Network is down */ 965*58247Seric #endif 966*58247Seric #ifdef ENETUNREACH 967*58247Seric case ENETUNREACH: /* Network is unreachable */ 968*58247Seric #endif 969*58247Seric #ifdef ENETRESET 970*58247Seric case ENETRESET: /* Network dropped connection on reset */ 971*58247Seric #endif 972*58247Seric #ifdef ECONNABORTED 973*58247Seric case ECONNABORTED: /* Software caused connection abort */ 974*58247Seric #endif 975*58247Seric #ifdef ECONNRESET 976*58247Seric case ECONNRESET: /* Connection reset by peer */ 977*58247Seric #endif 978*58247Seric #ifdef ENOBUFS 979*58247Seric case ENOBUFS: /* No buffer space available */ 980*58247Seric #endif 981*58247Seric #ifdef ESHUTDOWN 982*58247Seric case ESHUTDOWN: /* Can't send after socket shutdown */ 983*58247Seric #endif 984*58247Seric #ifdef ECONNREFUSED 985*58247Seric case ECONNREFUSED: /* Connection refused */ 986*58247Seric #endif 987*58247Seric #ifdef EHOSTDOWN 988*58247Seric case EHOSTDOWN: /* Host is down */ 989*58247Seric #endif 990*58247Seric #ifdef EHOSTUNREACH 991*58247Seric case EHOSTUNREACH: /* No route to host */ 992*58247Seric #endif 993*58247Seric #ifdef EDQUOT 994*58247Seric case EDQUOT: /* Disc quota exceeded */ 995*58247Seric #endif 996*58247Seric #ifdef EPROCLIM 997*58247Seric case EPROCLIM: /* Too many processes */ 998*58247Seric #endif 999*58247Seric #ifdef EUSERS 1000*58247Seric case EUSERS: /* Too many users */ 1001*58247Seric #endif 1002*58247Seric #ifdef EDEADLK 1003*58247Seric case EDEADLK: /* Resource deadlock avoided */ 1004*58247Seric #endif 1005*58247Seric return TRUE; 1006*58247Seric } 1007*58247Seric 1008*58247Seric /* nope, must be permanent */ 1009*58247Seric return FALSE; 1010*58247Seric } 1011