home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  14.8 KB  |  853 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. #ifndef lint
  36. static char sccsid[] = "@(#)util.c    5.20 (Berkeley) 3/8/91";
  37. #endif /* not lint */
  38.  
  39. # include <stdio.h>
  40. # include <sys/types.h>
  41. # include <sys/stat.h>
  42. # include <sysexits.h>
  43. # include <errno.h>
  44. # include "sendmail.h"
  45.  
  46. /*
  47. **  STRIPQUOTES -- Strip quotes & quote bits from a string.
  48. **
  49. **    Runs through a string and strips off unquoted quote
  50. **    characters and quote bits.  This is done in place.
  51. **
  52. **    Parameters:
  53. **        s -- the string to strip.
  54. **        qf -- if set, remove actual `` " '' characters
  55. **            as well as the quote bits.
  56. **
  57. **    Returns:
  58. **        none.
  59. **
  60. **    Side Effects:
  61. **        none.
  62. **
  63. **    Called By:
  64. **        deliver
  65. */
  66.  
  67. stripquotes(s, qf)
  68.     char *s;
  69.     bool qf;
  70. {
  71.     register char *p;
  72.     register char *q;
  73.     register char c;
  74.  
  75.     if (s == NULL)
  76.         return;
  77.  
  78.     for (p = q = s; (c = *p++) != '\0'; )
  79.     {
  80.         if (c != '"' || !qf)
  81.             *q++ = c & 0177;
  82.     }
  83.     *q = '\0';
  84. }
  85. /*
  86. **  QSTRLEN -- give me the string length assuming 0200 bits add a char
  87. **
  88. **    Parameters:
  89. **        s -- the string to measure.
  90. **
  91. **    Reurns:
  92. **        The length of s, including space for backslash escapes.
  93. **
  94. **    Side Effects:
  95. **        none.
  96. */
  97.  
  98. qstrlen(s)
  99.     register char *s;
  100. {
  101.     register int l = 0;
  102.     register char c;
  103.  
  104.     while ((c = *s++) != '\0')
  105.     {
  106.         if (bitset(0200, c))
  107.             l++;
  108.         l++;
  109.     }
  110.     return (l);
  111. }
  112. /*
  113. **  CAPITALIZE -- return a copy of a string, properly capitalized.
  114. **
  115. **    Parameters:
  116. **        s -- the string to capitalize.
  117. **
  118. **    Returns:
  119. **        a pointer to a properly capitalized string.
  120. **
  121. **    Side Effects:
  122. **        none.
  123. */
  124.  
  125. char *
  126. capitalize(s)
  127.     register char *s;
  128. {
  129.     static char buf[50];
  130.     register char *p;
  131.  
  132.     p = buf;
  133.  
  134.     for (;;)
  135.     {
  136.         while (!isalpha(*s) && *s != '\0')
  137.             *p++ = *s++;
  138.         if (*s == '\0')
  139.             break;
  140.         *p++ = toupper(*s);
  141.         s++;
  142.         while (isalpha(*s))
  143.             *p++ = *s++;
  144.     }
  145.  
  146.     *p = '\0';
  147.     return (buf);
  148. }
  149. /*
  150. **  XALLOC -- Allocate memory and bitch wildly on failure.
  151. **
  152. **    THIS IS A CLUDGE.  This should be made to give a proper
  153. **    error -- but after all, what can we do?
  154. **
  155. **    Parameters:
  156. **        sz -- size of area to allocate.
  157. **
  158. **    Returns:
  159. **        pointer to data region.
  160. **
  161. **    Side Effects:
  162. **        Memory is allocated.
  163. */
  164.  
  165. char *
  166. xalloc(sz)
  167.     register int sz;
  168. {
  169.     register char *p;
  170.     extern char *malloc();
  171.  
  172.     p = malloc((unsigned) sz);
  173.     if (p == NULL)
  174.     {
  175.         syserr("Out of memory!!");
  176.         abort();
  177.         /* exit(EX_UNAVAILABLE); */
  178.     }
  179.     return (p);
  180. }
  181. /*
  182. **  COPYPLIST -- copy list of pointers.
  183. **
  184. **    This routine is the equivalent of newstr for lists of
  185. **    pointers.
  186. **
  187. **    Parameters:
  188. **        list -- list of pointers to copy.
  189. **            Must be NULL terminated.
  190. **        copycont -- if TRUE, copy the contents of the vector
  191. **            (which must be a string) also.
  192. **
  193. **    Returns:
  194. **        a copy of 'list'.
  195. **
  196. **    Side Effects:
  197. **        none.
  198. */
  199.  
  200. char **
  201. copyplist(list, copycont)
  202.     char **list;
  203.     bool copycont;
  204. {
  205.     register char **vp;
  206.     register char **newvp;
  207.  
  208.     for (vp = list; *vp != NULL; vp++)
  209.         continue;
  210.  
  211.     vp++;
  212.  
  213.     newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
  214.     bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
  215.  
  216.     if (copycont)
  217.     {
  218.         for (vp = newvp; *vp != NULL; vp++)
  219.             *vp = newstr(*vp);
  220.     }
  221.  
  222.     return (newvp);
  223. }
  224. /*
  225. **  PRINTAV -- print argument vector.
  226. **
  227. **    Parameters:
  228. **        av -- argument vector.
  229. **
  230. **    Returns:
  231. **        none.
  232. **
  233. **    Side Effects:
  234. **        prints av.
  235. */
  236.  
  237. printav(av)
  238.     register char **av;
  239. {
  240.     while (*av != NULL)
  241.     {
  242.         if (tTd(0, 44))
  243.             printf("\n\t%08x=", *av);
  244.         else
  245.             (void) putchar(' ');
  246.         xputs(*av++);
  247.     }
  248.     (void) putchar('\n');
  249. }
  250. /*
  251. **  LOWER -- turn letter into lower case.
  252. **
  253. **    Parameters:
  254. **        c -- character to turn into lower case.
  255. **
  256. **    Returns:
  257. **        c, in lower case.
  258. **
  259. **    Side Effects:
  260. **        none.
  261. */
  262.  
  263. char
  264. lower(c)
  265.     register char c;
  266. {
  267.     return(isascii(c) && isupper(c) ? tolower(c) : c);
  268. }
  269. /*
  270. **  XPUTS -- put string doing control escapes.
  271. **
  272. **    Parameters:
  273. **        s -- string to put.
  274. **
  275. **    Returns:
  276. **        none.
  277. **
  278. **    Side Effects:
  279. **        output to stdout
  280. */
  281.  
  282. xputs(s)
  283.     register char *s;
  284. {
  285.     register char c;
  286.  
  287.     if (s == NULL)
  288.     {
  289.         printf("<null>");
  290.         return;
  291.     }
  292.     (void) putchar('"');
  293.     while ((c = *s++) != '\0')
  294.     {
  295.         if (!isascii(c))
  296.         {
  297.             (void) putchar('\\');
  298.             c &= 0177;
  299.         }
  300.         if (c < 040 || c >= 0177)
  301.         {
  302.             (void) putchar('^');
  303.             c ^= 0100;
  304.         }
  305.         (void) putchar(c);
  306.     }
  307.     (void) putchar('"');
  308.     (void) fflush(stdout);
  309. }
  310. /*
  311. **  MAKELOWER -- Translate a line into lower case
  312. **
  313. **    Parameters:
  314. **        p -- the string to translate.  If NULL, return is
  315. **            immediate.
  316. **
  317. **    Returns:
  318. **        none.
  319. **
  320. **    Side Effects:
  321. **        String pointed to by p is translated to lower case.
  322. **
  323. **    Called By:
  324. **        parse
  325. */
  326.  
  327. makelower(p)
  328.     register char *p;
  329. {
  330.     register char c;
  331.  
  332.     if (p == NULL)
  333.         return;
  334.     for (; (c = *p) != '\0'; p++)
  335.         if (isascii(c) && isupper(c))
  336.             *p = tolower(c);
  337. }
  338. /*
  339. **  BUILDFNAME -- build full name from gecos style entry.
  340. **
  341. **    This routine interprets the strange entry that would appear
  342. **    in the GECOS field of the password file.
  343. **
  344. **    Parameters:
  345. **        p -- name to build.
  346. **        login -- the login name of this user (for &).
  347. **        buf -- place to put the result.
  348. **
  349. **    Returns:
  350. **        none.
  351. **
  352. **    Side Effects:
  353. **        none.
  354. */
  355.  
  356. buildfname(p, login, buf)
  357.     register char *p;
  358.     char *login;
  359.     char *buf;
  360. {
  361.     register char *bp = buf;
  362.  
  363.     if (*p == '*')
  364.         p++;
  365.     while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
  366.     {
  367.         if (*p == '&')
  368.         {
  369.             (void) strcpy(bp, login);
  370.             *bp = toupper(*bp);
  371.             while (*bp != '\0')
  372.                 bp++;
  373.             p++;
  374.         }
  375.         else
  376.             *bp++ = *p++;
  377.     }
  378.     *bp = '\0';
  379. }
  380. /*
  381. **  SAFEFILE -- return true if a file exists and is safe for a user.
  382. **
  383. **    Parameters:
  384. **        fn -- filename to check.
  385. **        uid -- uid to compare against.
  386. **        mode -- mode bits that must match.
  387. **
  388. **    Returns:
  389. **        TRUE if fn exists, is owned by uid, and matches mode.
  390. **        FALSE otherwise.
  391. **
  392. **    Side Effects:
  393. **        none.
  394. */
  395.  
  396. bool
  397. safefile(fn, uid, mode)
  398.     char *fn;
  399.     int uid;
  400.     int mode;
  401. {
  402.     struct stat stbuf;
  403.  
  404.     if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
  405.         (stbuf.st_mode & mode) == mode)
  406.         return (TRUE);
  407.     errno = 0;
  408.     return (FALSE);
  409. }
  410. /*
  411. **  FIXCRLF -- fix <CR><LF> in line.
  412. **
  413. **    Looks for the <CR><LF> combination and turns it into the
  414. **    UNIX canonical <NL> character.  It only takes one line,
  415. **    i.e., it is assumed that the first <NL> found is the end
  416. **    of the line.
  417. **
  418. **    Parameters:
  419. **        line -- the line to fix.
  420. **        stripnl -- if true, strip the newline also.
  421. **
  422. **    Returns:
  423. **        none.
  424. **
  425. **    Side Effects:
  426. **        line is changed in place.
  427. */
  428.  
  429. fixcrlf(line, stripnl)
  430.     char *line;
  431.     bool stripnl;
  432. {
  433.     register char *p;
  434.  
  435.     p = index(line, '\n');
  436.     if (p == NULL)
  437.         return;
  438.     if (p > line && p[-1] == '\r')
  439.         p--;
  440.     if (!stripnl)
  441.         *p++ = '\n';
  442.     *p = '\0';
  443. }
  444. /*
  445. **  DFOPEN -- determined file open
  446. **
  447. **    This routine has the semantics of fopen, except that it will
  448. **    keep trying a few times to make this happen.  The idea is that
  449. **    on very loaded systems, we may run out of resources (inodes,
  450. **    whatever), so this tries to get around it.
  451. */
  452.  
  453. FILE *
  454. dfopen(filename, mode)
  455.     char *filename;
  456.     char *mode;
  457. {
  458.     register int tries;
  459.     register FILE *fp;
  460.  
  461.     for (tries = 0; tries < 10; tries++)
  462.     {
  463.         sleep((unsigned) (10 * tries));
  464.         errno = 0;
  465.         fp = fopen(filename, mode);
  466.         if (fp != NULL)
  467.             break;
  468.         if (errno != ENFILE && errno != EINTR)
  469.             break;
  470.     }
  471.     errno = 0;
  472.     return (fp);
  473. }
  474. /*
  475. **  PUTLINE -- put a line like fputs obeying SMTP conventions
  476. **
  477. **    This routine always guarantees outputing a newline (or CRLF,
  478. **    as appropriate) at the end of the string.
  479. **
  480. **    Parameters:
  481. **        l -- line to put.
  482. **        fp -- file to put it onto.
  483. **        m -- the mailer used to control output.
  484. **
  485. **    Returns:
  486. **        none
  487. **
  488. **    Side Effects:
  489. **        output of l to fp.
  490. */
  491.  
  492. # define SMTPLINELIM    990    /* maximum line length */
  493.  
  494. putline(l, fp, m)
  495.     register char *l;
  496.     FILE *fp;
  497.     MAILER *m;
  498. {
  499.     register char *p;
  500.     register char svchar;
  501.  
  502.     /* strip out 0200 bits -- these can look like TELNET protocol */
  503.     if (bitnset(M_LIMITS, m->m_flags))
  504.     {
  505.         for (p = l; svchar = *p; ++p)
  506.             if (svchar & 0200)
  507.                 *p = svchar &~ 0200;
  508.     }
  509.  
  510.     do
  511.     {
  512.         /* find the end of the line */
  513.         p = index(l, '\n');
  514.         if (p == NULL)
  515.             p = &l[strlen(l)];
  516.  
  517.         /* check for line overflow */
  518.         while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
  519.         {
  520.             register char *q = &l[SMTPLINELIM - 1];
  521.  
  522.             svchar = *q;
  523.             *q = '\0';
  524.             if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
  525.                 (void) putc('.', fp);
  526.             fputs(l, fp);
  527.             (void) putc('!', fp);
  528.             fputs(m->m_eol, fp);
  529.             *q = svchar;
  530.             l = q;
  531.         }
  532.  
  533.         /* output last part */
  534.         if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
  535.             (void) putc('.', fp);
  536.         for ( ; l < p; ++l)
  537.             (void) putc(*l, fp);
  538.         fputs(m->m_eol, fp);
  539.         if (*l == '\n')
  540.             ++l;
  541.     } while (l[0] != '\0');
  542. }
  543. /*
  544. **  XUNLINK -- unlink a file, doing logging as appropriate.
  545. **
  546. **    Parameters:
  547. **        f -- name of file to unlink.
  548. **
  549. **    Returns:
  550. **        none.
  551. **
  552. **    Side Effects:
  553. **        f is unlinked.
  554. */
  555.  
  556. xunlink(f)
  557.     char *f;
  558. {
  559.     register int i;
  560.  
  561. # ifdef LOG
  562.     if (LogLevel > 20)
  563.         syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
  564. # endif LOG
  565.  
  566.     i = unlink(f);
  567. # ifdef LOG
  568.     if (i < 0 && LogLevel > 21)
  569.         syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
  570. # endif LOG
  571. }
  572. /*
  573. **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
  574. **
  575. **    Parameters:
  576. **        buf -- place to put the input line.
  577. **        siz -- size of buf.
  578. **        fp -- file to read from.
  579. **
  580. **    Returns:
  581. **        NULL on error (including timeout).  This will also leave
  582. **            buf containing a null string.
  583. **        buf otherwise.
  584. **
  585. **    Side Effects:
  586. **        none.
  587. */
  588.  
  589. static jmp_buf    CtxReadTimeout;
  590.  
  591. char *
  592. sfgets(buf, siz, fp)
  593.     char *buf;
  594.     int siz;
  595.     FILE *fp;
  596. {
  597.     register EVENT *ev = NULL;
  598.     register char *p;
  599.     static int readtimeout();
  600.  
  601.     /* set the timeout */
  602.     if (ReadTimeout != 0)
  603.     {
  604.         if (setjmp(CtxReadTimeout) != 0)
  605.         {
  606. # ifdef LOG
  607.             syslog(LOG_NOTICE,
  608.                 "timeout waiting for input from %s\n",
  609.                 RealHostName? RealHostName: "local");
  610. # endif
  611.             errno = 0;
  612.             usrerr("451 timeout waiting for input");
  613.             buf[0] = '\0';
  614.             return (NULL);
  615.         }
  616.         ev = setevent((time_t) ReadTimeout, readtimeout, 0);
  617.     }
  618.  
  619.     /* try to read */
  620.     p = NULL;
  621.     while (p == NULL && !feof(fp) && !ferror(fp))
  622.     {
  623.         errno = 0;
  624.         p = fgets(buf, siz, fp);
  625.         if (errno == EINTR)
  626.             clearerr(fp);
  627.     }
  628.  
  629.     /* clear the event if it has not sprung */
  630.     clrevent(ev);
  631.  
  632.     /* clean up the books and exit */
  633.     LineNumber++;
  634.     if (p == NULL)
  635.     {
  636.         buf[0] = '\0';
  637.         return (NULL);
  638.     }
  639.     for (p = buf; *p != '\0'; p++)
  640.         *p &= ~0200;
  641.     return (buf);
  642. }
  643.  
  644. static
  645. readtimeout()
  646. {
  647.     longjmp(CtxReadTimeout, 1);
  648. }
  649. /*
  650. **  FGETFOLDED -- like fgets, but know about folded lines.
  651. **
  652. **    Parameters:
  653. **        buf -- place to put result.
  654. **        n -- bytes available.
  655. **        f -- file to read from.
  656. **
  657. **    Returns:
  658. **        buf on success, NULL on error or EOF.
  659. **
  660. **    Side Effects:
  661. **        buf gets lines from f, with continuation lines (lines
  662. **        with leading white space) appended.  CRLF's are mapped
  663. **        into single newlines.  Any trailing NL is stripped.
  664. */
  665.  
  666. char *
  667. fgetfolded(buf, n, f)
  668.     char *buf;
  669.     register int n;
  670.     FILE *f;
  671. {
  672.     register char *p = buf;
  673.     register int i;
  674.  
  675.     n--;
  676.     while ((i = getc(f)) != EOF)
  677.     {
  678.         if (i == '\r')
  679.         {
  680.             i = getc(f);
  681.             if (i != '\n')
  682.             {
  683.                 if (i != EOF)
  684.                     (void) ungetc(i, f);
  685.                 i = '\r';
  686.             }
  687.         }
  688.         if (--n > 0)
  689.             *p++ = i;
  690.         if (i == '\n')
  691.         {
  692.             LineNumber++;
  693.             i = getc(f);
  694.             if (i != EOF)
  695.                 (void) ungetc(i, f);
  696.             if (i != ' ' && i != '\t')
  697.             {
  698.                 *--p = '\0';
  699.                 return (buf);
  700.             }
  701.         }
  702.     }
  703.     return (NULL);
  704. }
  705. /*
  706. **  CURTIME -- return current time.
  707. **
  708. **    Parameters:
  709. **        none.
  710. **
  711. **    Returns:
  712. **        the current time.
  713. **
  714. **    Side Effects:
  715. **        none.
  716. */
  717.  
  718. time_t
  719. curtime()
  720. {
  721.     auto time_t t;
  722.  
  723.     (void) time(&t);
  724.     return (t);
  725. }
  726. /*
  727. **  ATOBOOL -- convert a string representation to boolean.
  728. **
  729. **    Defaults to "TRUE"
  730. **
  731. **    Parameters:
  732. **        s -- string to convert.  Takes "tTyY" as true,
  733. **            others as false.
  734. **
  735. **    Returns:
  736. **        A boolean representation of the string.
  737. **
  738. **    Side Effects:
  739. **        none.
  740. */
  741.  
  742. bool
  743. atobool(s)
  744.     register char *s;
  745. {
  746.     if (*s == '\0' || index("tTyY", *s) != NULL)
  747.         return (TRUE);
  748.     return (FALSE);
  749. }
  750. /*
  751. **  ATOOCT -- convert a string representation to octal.
  752. **
  753. **    Parameters:
  754. **        s -- string to convert.
  755. **
  756. **    Returns:
  757. **        An integer representing the string interpreted as an
  758. **        octal number.
  759. **
  760. **    Side Effects:
  761. **        none.
  762. */
  763.  
  764. atooct(s)
  765.     register char *s;
  766. {
  767.     register int i = 0;
  768.  
  769.     while (*s >= '0' && *s <= '7')
  770.         i = (i << 3) | (*s++ - '0');
  771.     return (i);
  772. }
  773. /*
  774. **  WAITFOR -- wait for a particular process id.
  775. **
  776. **    Parameters:
  777. **        pid -- process id to wait for.
  778. **
  779. **    Returns:
  780. **        status of pid.
  781. **        -1 if pid never shows up.
  782. **
  783. **    Side Effects:
  784. **        none.
  785. */
  786.  
  787. waitfor(pid)
  788.     int pid;
  789. {
  790.     auto int st;
  791.     int i;
  792.  
  793.     do
  794.     {
  795.         errno = 0;
  796.         i = wait(&st);
  797.     } while ((i >= 0 || errno == EINTR) && i != pid);
  798.     if (i < 0)
  799.         st = -1;
  800.     return (st);
  801. }
  802. /*
  803. **  BITINTERSECT -- tell if two bitmaps intersect
  804. **
  805. **    Parameters:
  806. **        a, b -- the bitmaps in question
  807. **
  808. **    Returns:
  809. **        TRUE if they have a non-null intersection
  810. **        FALSE otherwise
  811. **
  812. **    Side Effects:
  813. **        none.
  814. */
  815.  
  816. bool
  817. bitintersect(a, b)
  818.     BITMAP a;
  819.     BITMAP b;
  820. {
  821.     int i;
  822.  
  823.     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
  824.         if ((a[i] & b[i]) != 0)
  825.             return (TRUE);
  826.     return (FALSE);
  827. }
  828. /*
  829. **  BITZEROP -- tell if a bitmap is all zero
  830. **
  831. **    Parameters:
  832. **        map -- the bit map to check
  833. **
  834. **    Returns:
  835. **        TRUE if map is all zero.
  836. **        FALSE if there are any bits set in map.
  837. **
  838. **    Side Effects:
  839. **        none.
  840. */
  841.  
  842. bool
  843. bitzerop(map)
  844.     BITMAP map;
  845. {
  846.     int i;
  847.  
  848.     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
  849.         if (map[i] != 0)
  850.             return (FALSE);
  851.     return (TRUE);
  852. }
  853.