home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / server / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  19.8 KB  |  991 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)$Header: misc.c,v 1.41 90/12/12 00:00:02 sob Exp $";
  3. #endif
  4.  
  5. #include "common.h"
  6.  
  7. /*
  8.  * open_valid_art -- determine if a given article name is valid;
  9.  *        if it is, return a file pointer to the open article,
  10.  *        along with a unique id of the article.
  11.  *
  12.  *    Parameters:    "artname" is a string containing the
  13.  *            name of the article.
  14.  *            "id" is space for us to put the article
  15.  *            id in.
  16.  *
  17.  *    Returns:    File pointer to the open article if the
  18.  *            article is valid; NULL otherwise
  19.  *
  20.  *    Side effects:    None.
  21.  */
  22.  
  23. FILE *
  24. open_valid_art(artname, id)
  25.     char        *artname;
  26.     char        *id;
  27. {
  28.     static int    crnt_art_num;
  29.     static char    crnt_art_id[MAXBUFLEN];
  30.     int        fd;
  31.     struct stat    statbuf;
  32.  
  33.     if (art_fp != NULL) {
  34.         if (crnt_art_num == atoi(artname)) {
  35.             if (fseek(art_fp, (long) 0, 0) < 0)
  36.                 close_crnt();
  37.             else {
  38.                 (void) strcpy(id, crnt_art_id);
  39.                 return (art_fp);
  40.             }
  41.         } else 
  42.             close_crnt();
  43.     }
  44.  
  45.     art_fp = fopen(artname, "r");
  46.  
  47.     if (art_fp == NULL)
  48.         return (NULL);
  49.  
  50.     fd = fileno(art_fp);
  51.  
  52.     if (fstat(fd, &statbuf) < 0) {
  53.         close_crnt();
  54.         return (NULL);
  55.     }
  56.  
  57.     if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
  58.         close_crnt();
  59.         return (NULL);
  60.     }
  61.  
  62.     get_id(art_fp, id);
  63.     (void) strcpy(crnt_art_id, id);
  64.     crnt_art_num = atoi(artname);
  65.     return (art_fp);
  66. }
  67.  
  68.  
  69. /*
  70.  * gethistent -- return the path name of an article if it's
  71.  * in the history file.
  72.  *
  73.  *    Parameters:    "msg_id" is the message ID of the
  74.  *            article, enclosed in <>'s.
  75.  *            "lookup", only check if article exists
  76.  *
  77.  *    Returns:    A char pointer to a static data area
  78.  *            containing the full pathname of the
  79.  *            article, or NULL if the message-id is not
  80.  *            in thef history file.
  81.  *
  82.  *    Side effects:    opens dbm database
  83.  *            (only once, keeps it open after that).
  84.  *            If running Bnews, converts "msg_id" to lower case.
  85.  *            If running Cnews, converts "msg_id" per rfc822.
  86.  *            
  87.  */
  88.  
  89. #ifndef NDBM
  90. # ifndef DBM
  91. #  ifndef USGHIST
  92. #   define USGHIST
  93. #  endif not USGHIST
  94. # endif not DBM
  95. #endif not DBM
  96.  
  97. char *
  98. gethistent(msg_id, lookup)
  99.     char        *msg_id;
  100.     int        lookup;
  101. {
  102.     char        line[MAXBUFLEN];
  103.     char        *tmp;
  104.     register char    *cp;
  105.     long        ltmp;
  106.     static char    path[MAXPATHLEN];
  107. #ifdef USGHIST
  108.     char        *histfile();
  109.     register int    len;
  110. #else not USGHIST
  111. #ifdef DBM
  112.     static int    dbopen = 0;
  113.     datum        fetch();
  114. #else not DBM
  115.     static DBM    *db = NULL;    /* History file, dbm version */
  116. #endif DBM
  117.     datum         key, content;
  118. #endif USGHIST
  119.     static FILE    *hfp = NULL;    /* history file, text version */
  120.  
  121. #ifdef CNEWS
  122.     cp = rindex(msg_id,'@');    /* look for @ in message id */
  123.     if( cp != NULL)
  124.     {    
  125.         for(;*cp != '\0';++cp)
  126. #else
  127.     {
  128.         for (cp = msg_id; *cp != '\0'; ++cp)
  129. #endif
  130.         if (isupper(*cp))
  131.             *cp = tolower(*cp);
  132. /* Make ctags happy */
  133. #ifdef CNEWS
  134.     }
  135. #else
  136.     }
  137. #endif
  138. #ifdef USGHIST
  139.     hfp = fopen(histfile(msg_id), "r");
  140.     if (hfp == NULL) {
  141. #ifdef SYSLOG
  142.         syslog(LOG_ERR, "gethistent: histfile: %m");
  143. #endif SYSLOG
  144.         return (NULL);
  145.     }
  146.  
  147.     len = strlen(msg_id);
  148.     while (fgets(line, sizeof (line), hfp))
  149.         if (!strncasecmp(msg_id, line, len))
  150.             break;
  151.  
  152.     if (feof(hfp)) {
  153.         (void) fclose(hfp);
  154.         return (NULL);
  155.     }
  156. #else not USGHIST
  157. #ifdef DBM
  158.     if (!dbopen) {
  159.         if (dbminit(historyfile) < 0) {
  160. #ifdef SYSLOG
  161.             syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
  162.                 historyfile);
  163. #endif SYSLOG
  164.             return (NULL);
  165.         } else
  166.             dbopen = 1;
  167.     }
  168. #else    /* ndbm */
  169.     if (db == NULL) {
  170.         db = dbm_open(historyfile, O_RDONLY, 0);
  171.         if (db == NULL) {
  172. #ifdef SYSLOG
  173.             syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
  174.                 historyfile);
  175. #endif SYSLOG
  176.             return (NULL);
  177.         }
  178.     }
  179. #endif DBM
  180.  
  181.     key.dptr = msg_id;
  182.     key.dsize = strlen(msg_id) + 1;
  183.  
  184. #ifdef DBM
  185.     content = fetch(key);
  186. #else    /* ndbm */
  187.     content = dbm_fetch(db, key);
  188. #endif DBM
  189.     if (content.dptr == NULL)
  190.         return (NULL);
  191.  
  192.     /*
  193.      * If we are just checking to see if it exists return a non-NULL
  194.      * result
  195.      */
  196.     if (lookup)
  197.         return ((char *)1);
  198.  
  199.     if (hfp == NULL) {
  200.         hfp = fopen(historyfile, "r");
  201.         if (hfp == NULL) {
  202. #ifdef SYSLOG
  203.             syslog(LOG_ERR, "message: fopen %s: %m",
  204.                 historyfile);
  205. #endif SYSLOG
  206.             return (NULL);
  207.         }
  208.     } else {
  209. /* Why do this if we are going to do an absolute fseek below? XXX */
  210.         rewind(hfp);
  211.     }
  212.  
  213.     bcopy(content.dptr, (char *)<mp, sizeof (long));
  214.     if (fseek(hfp, ltmp, 0) < 0) {
  215. #ifdef SYSLOG
  216.         syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m", 
  217.                historyfile, ltmp, hfp);
  218. #endif SYSLOG
  219.         return (NULL);
  220.     }
  221.  
  222.     (void) fgets(line, sizeof(line), hfp);
  223. #endif USGHIST
  224.  
  225.     if ((cp = index(line, '\n')) != NULL)
  226.         *cp = '\0';
  227.     cp = index(line, '\t');
  228.     if (cp != NULL)
  229.         cp = index(cp+1, '\t');
  230. #ifdef SYSLOG
  231.     else
  232.         syslog(LOG_ERR,
  233.         "message: malformed line in history file at %ld bytes, id %s",
  234.             ltmp, msg_id);
  235. #endif SYSLOG
  236.     if (cp == NULL) return(NULL); /* this article has expired */
  237.     tmp = cp+1;
  238.  
  239.     if ((cp = index(tmp, ' ')) != NULL)
  240.         *cp = '\0';
  241.     
  242.     while ((cp = index(tmp, '.')) != NULL)
  243.         *cp = '/';
  244.  
  245.     (void) strcpy(path, spooldir);
  246.     (void) strcat(path, "/");
  247.     (void) strcat(path, tmp);
  248. #ifdef USGHIST
  249.     (void) fclose(hfp);
  250. #endif
  251.     return (path);
  252. }
  253.  
  254. /*
  255.  * openartbyid -- open an article by message-id.
  256.  *
  257.  *    Arguments:    "msg_id" is the message-id of the article
  258.  *            to open.
  259.  *
  260.  *    Returns:    File pointer to opened article, or NULL if
  261.  *            the article was not in the history file or
  262.  *            could not be opened.
  263.  *
  264.  *    Side effects:    Opens article.
  265.  */
  266.  
  267. FILE *
  268. openartbyid(msg_id)
  269.     char    *msg_id;
  270. {
  271.     char    *path;
  272.  
  273.     path = gethistent(msg_id, 0);
  274.     if (path != NULL)
  275.         return (fopen(path, "r"));
  276.     else
  277.         return (NULL);
  278. }
  279.  
  280.  
  281. /*
  282.  * check_ngperm -- check to see if they're allowed to see this
  283.  * article by matching Newsgroups: and Distribution: line.
  284.  *
  285.  *    Parameters:    "fp" is the file pointer of this article.
  286.  *
  287.  *    Returns:    0 if they're not allowed to see it.
  288.  *            1 if they are.
  289.  *
  290.  *    Side effects:    None.
  291.  */
  292.  
  293. check_ngperm(fp)
  294.     register FILE    *fp;
  295. {
  296.     char        buf[MAXBUFLEN];
  297.     register char    *cp;
  298.     static char    **ngarray;
  299.     int        ngcount = 0;
  300.  
  301.     if (ngpermcount == 0) {
  302.         if (ALLBUT == 0)
  303.             return 0;
  304.         return (1);
  305.     }
  306.  
  307.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  308.         if (buf[0] == '\n')        /* End of header */
  309.             break;
  310.         if (buf[0] != 'N' && buf[0] != 'n')
  311.             continue;
  312.         cp = index(buf, '\n');
  313.         if (cp)
  314.             *cp = '\0';
  315.         cp = index(buf, ':');
  316.         if (cp == NULL)
  317.             continue;
  318.         *cp = '\0';
  319.         if (!strcasecmp(buf, "newsgroups")) {
  320.             ngcount = get_nglist(&ngarray, cp+2);
  321.             break;
  322.         }
  323.     }
  324.  
  325. #ifndef USG
  326.     (void) rewind(fp);
  327. #else
  328.     rewind(fp);
  329. #endif
  330.     if (ngcount == 0)    /* Either no newgroups or null entry */
  331.         return (1);
  332.  
  333.     return (ngmatch(s1strneql, ALLBUT,
  334.         ngpermlist, ngpermcount, ngarray, ngcount));
  335. }
  336.  
  337.  
  338. /*
  339.  * spew -- spew out the contents of a file to stdout, doing
  340.  * the necessary cr-lf additions at the end.  Finish with
  341.  * a "." on a line by itself, and an fflush(stdout).
  342.  *
  343.  *    Parameters:    "how" tells what part of the file we
  344.  *            want spewed:
  345.  *                ARTICLE   The entire thing.
  346.  *                HEAD      Just the first part.
  347.  *                BODY      Just the second part.
  348.  *            "fp" is the open file to spew from.
  349.  *
  350.  *    Returns:    Nothing.
  351.  *
  352.  *    Side effects:    Changes current position in file.
  353.  */
  354.  
  355. spew(fp, how)
  356.     FILE        *fp;
  357.     int        how;
  358. {
  359.     char        line[NNTP_STRLEN];
  360.     register char    *cp;
  361.  
  362. #ifdef LOG
  363.     ++arts_acsd;
  364. #endif
  365.  
  366.     if (how == STAT) {
  367.         (void) fflush(stdout);
  368.         return;
  369.     }
  370.  
  371.     while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') {
  372.         if (how == BODY)    /* We need to skip this anyway */
  373.             continue;
  374.         cp = index(line, '\n');
  375.         if (cp != NULL)
  376.             *cp = '\0';
  377.         if (*line == '.')
  378.             putchar('.');
  379.         putline(line);
  380.         if (cp == NULL) {
  381.             for (;;) {
  382.                 if ((fgets(line, sizeof(line)-6, fp) == NULL)
  383.                     || (index(line, '\n') != NULL))
  384.                     break;
  385.             }
  386.         }
  387.     }
  388.  
  389.     if (how == HEAD) {
  390.         putchar('.');
  391.         putchar('\r');
  392.         putchar('\n');
  393.         (void) fflush(stdout);
  394.         return;
  395.     } else if (how == ARTICLE) {
  396.         putchar('\r');
  397.         putchar('\n');
  398.     }
  399.  
  400.     while (fgets(line, sizeof(line)-6, fp) != NULL) {
  401.         cp = index(line, '\n');
  402.         if (cp != NULL)
  403.             *cp = '\0';
  404.         if (*line == '.')
  405.             putchar('.');
  406.         putline(line);
  407.  
  408.         if (cp == NULL) {
  409.             for (;;) {
  410.                 if ((fgets(line, sizeof(line)-6, fp) == NULL)
  411.                     || (index(line, '\n') != NULL))
  412.                     break;
  413.             }
  414.         }
  415.     }
  416.     putchar('.');
  417.     putchar('\r');
  418.     putchar('\n');
  419.     (void) fflush(stdout);
  420. }
  421.  
  422.  
  423. /*
  424.  * get_id -- get the message id of the current article.
  425.  *
  426.  *    Parameters:    "art_fp" is a pointer to the open file.
  427.  *            "id" is space for the message ID.
  428.  *
  429.  *    Returns:    Nothing.
  430.  *
  431.  *    Side effects:    Seeks and rewinds on "art_fp".
  432.  *            Changes space pointed to by "id".
  433.  */
  434.  
  435. get_id(art_fp, id)
  436.     register FILE    *art_fp;
  437.     char        *id;
  438. {
  439.     char        line[MAXBUFLEN];
  440.     register char    *cp;
  441.  
  442.     while (fgets(line, sizeof(line), art_fp) != NULL) {
  443.         if (*line == '\n')
  444.             break;
  445.         if (*line == 'M' || *line == 'm') {    /* "Message-ID" */
  446.             if ((cp = index(line, ' ')) != NULL) {
  447.                 *cp = '\0';
  448.                 if (!strcasecmp(line, "Message-ID:")) {
  449.                     (void) strcpy(id, cp + 1);
  450.                     if ((cp = index(id, '\n')) != NULL)
  451.                         *cp = '\0';
  452. #ifndef USG
  453.                     (void) rewind(art_fp);
  454. #else
  455.                     rewind(art_fp);
  456. #endif
  457.                     return;
  458.                 }
  459.             }
  460.         }
  461.     }
  462. #ifndef USG
  463.     (void) rewind(art_fp);
  464. #else
  465.     rewind(art_fp);
  466. #endif
  467.     (void) strcpy(id, "<0>");
  468. }
  469.         
  470.  
  471. /*
  472.  * close_crnt -- close the current article file pointer, if it's
  473.  *    open.
  474.  *
  475.  *    Parameters:    None.
  476.  *
  477.  *    Returns:    Nothing.
  478.  *
  479.  *    Side effects:    Closes "art_fp" if it's open; sets "art_fp" to NULL.
  480.  */
  481.  
  482. close_crnt()
  483. {
  484.     if (art_fp != NULL)
  485.         (void) fclose(art_fp);
  486.     art_fp = NULL;
  487. }
  488.  
  489.  
  490. /*
  491.  * findart -- find an article number in the article array.
  492.  *
  493.  *    Parameters:    "artname" is a string containing
  494.  *            the name of the article.
  495.  *
  496.  *    Returns:    An index into "art_array",
  497.  *            or -1 if "artname" isn't in "art_array".
  498.  *            
  499.  *    Side effects:    None.
  500.  *
  501.  *    Improvement:    Replace this linear search with a binary one.
  502.  */
  503.  
  504. findart(artname)
  505.     char        *artname;
  506. {
  507.     register int    i, artnum;
  508.  
  509.     artnum = atoi(artname);
  510.  
  511.     for (i = 0; i < num_arts; ++i)
  512.         if (art_array[i] == artnum)
  513.             return(i);
  514.  
  515.     return (-1);
  516. }
  517.  
  518.  
  519. /*
  520.  * get_distlist -- return a nicely set up array of distribution groups
  521.  * along with a count, when given an NNTP-spec distribution list
  522.  * in the form <dist1,dist2,...,distn>.
  523.  *
  524.  *    Parameters:        "array" is storage for our array,
  525.  *                set to point at some static data.
  526.  *                "list" is the NNTP distribution list.
  527.  *
  528.  *    Returns:        Number of distributions found.
  529.  *                -1 on error.
  530.  *
  531.  *    Side effects:        Changes static data area.
  532.  */
  533.  
  534. get_distlist(array, list)
  535.     char        ***array;
  536.     char        *list;
  537. {
  538.     char        *cp;
  539.     int        distcount;
  540.     static char    **dist_list = (char **) NULL;
  541.  
  542.     if (list[0] != '<')
  543.         return (-1);
  544.  
  545.     cp = index(list + 1, '>');
  546.     if (cp != NULL)
  547.         *cp = '\0';
  548.     else
  549.         return (-1);
  550.  
  551.     for (cp = list + 1; *cp != '\0'; ++cp)
  552.         if (*cp == ',')
  553.             *cp = ' ';
  554.     distcount = parsit(list + 1, &dist_list);
  555.     *array = dist_list;
  556.     return (distcount);
  557. }
  558.  
  559.  
  560. /*
  561.  * lower -- convert a character to lower case, if it's upper case.
  562.  *
  563.  *    Parameters:    "c" is the character to be
  564.  *            converted.
  565.  *
  566.  *    Returns:    "c" if the character is not
  567.  *            upper case, otherwise the lower
  568.  *            case equivalent of "c".
  569.  *
  570.  *    Side effects:    None.
  571.  */
  572.  
  573. char
  574. lower(c)
  575.     register char    c;
  576. {
  577.     if (isascii(c) && isupper(c))
  578.         c = c - 'A' + 'a';
  579.     return (c);
  580. }
  581.  
  582.  
  583. /* the following is from news 2.11 */
  584.  
  585. #ifdef USGHIST
  586. /*
  587. ** Generate the appropriate history subfile name
  588. */
  589. char *
  590. histfile(hline)
  591. char *hline;
  592. {
  593.     char chr;    /* least significant digit of article number */
  594.     static char subfile[BUFSIZ];
  595.  
  596.     chr = findhfdigit(hline);
  597.     sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
  598.     return subfile;
  599. }
  600.  
  601. findhfdigit(fn)
  602. char *fn;
  603. {
  604.     register char *p;
  605.     register int chr;
  606.  
  607.     p = index(fn, '@');
  608.     if (p != NULL && p > fn)
  609.         chr = *(p - 1);
  610.     else
  611.         chr = '0';
  612.     if (!isdigit(chr))
  613.         chr = '0';
  614.     return chr;
  615. }
  616. #endif USGHIST
  617. #if 0 /* was USG */
  618. #ifndef GAZETTE
  619. bcopy(s, d, l)
  620.     register char *s, *d;
  621.     register int l;
  622. {
  623.     while (l-- > 0)
  624.         *d++ = *s++;
  625. }
  626.  
  627. bcmp(s1, s2, l)
  628.     register char *s1, *s2;
  629.     register int l;
  630. {
  631.     if (l == 0)
  632.         return (0);
  633.  
  634.     do
  635.         if (*s1++ != *s2++)
  636.             break;
  637.     while (--l);
  638.  
  639.     return (l);
  640. }
  641.  
  642. bzero(p, l)
  643.     register char *p;
  644.     register int l;
  645. {
  646.     while (l-- > 0)
  647.         *p++ = 0;
  648. }
  649. #endif
  650.  
  651. dup2(x,y)
  652. int x,y;
  653.     close(y); 
  654.     return(fcntl(x, F_DUPFD,y ));
  655. }
  656.  
  657. #endif
  658.  
  659. /*
  660.  * The following is a mish-mosh of code submitted to the net
  661.  * by Stan Barber <sob@bcm.tmc.edu>, Tad Guy <tadguy@cs.odu.edu>,
  662.  * Chris Jepeway <jepeway@utkcs2.cs.utk.edu>, and Tom Lane <tgl@cs.cmu.edu>.
  663.  */
  664.  
  665. /*
  666.  * returns 1 if there are lots of free blocks for the nntp server to use;
  667.  * a zero value is the small number of blocks remaining (more or less).
  668.  */
  669. #define DFREE_OK    0
  670. #define DFREE_INODES    1
  671. #define DFREE_BLOCKS    2
  672. #define DFREE_ERR    3
  673.  
  674. int
  675. space(min_free)
  676. int min_free;
  677. {
  678.     int result, dfree();
  679.     return(1); /* No check for Linux !! - OLE */
  680.     result = dfree(SPOOLDIR,min_free);
  681.     if (result == DFREE_OK) return(1);
  682. #ifdef SYSLOG
  683.     switch (result) {
  684.     case DFREE_ERR:
  685.         syslog(LOG_ERR,"dfree failed due to syscall error");
  686.         break;
  687. #ifdef LOG
  688.     case DFREE_INODES:
  689.         syslog(LOG_INFO,"no inodes on %s",SPOOLDIR);
  690.         break;
  691.     case DFREE_BLOCKS:
  692.         syslog(LOG_INFO,"no space on %s",SPOOLDIR);
  693.         break;
  694. #endif
  695.         }    
  696. #endif
  697.     return(0);
  698. }
  699.  
  700. /*
  701.  * Now we define the dfree() routine, which returns the free space
  702.  * on the file system containing the specified directory.
  703.  * Space is measured in kilobytes.
  704.  * A negative value is returned on error.
  705.  */
  706. #ifndef READ_SUPER
  707. #if defined(sun) || defined(hpux) || defined(pyr) || defined(hp300) || defined(NeXT)
  708. #include <sys/vfs.h>
  709. #define statfilesys    statfs        /* routine to call when trying to  */
  710.                     /* stat a file system to get the # */
  711.                     /* of free blocks available       */
  712. typedef struct statfs statfs_type;    /* the data type into which statfs() */
  713.                     /* wants to return useful information*/
  714. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  715.                     /* a call to statfs() fails         */
  716. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  717.                     /* # of free blocks             */
  718. #define blkavail(fs)    ((fs).f_bavail)    /* given a statfs_type called fs,  */
  719.                     /* return # of blocks available to */
  720.                     /* a non-privileged user       */
  721. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  722.                      /* return number of free inodes       */
  723. #endif 
  724.  
  725. #if defined(apollo)
  726. #include <sys/types.h>
  727. #include <sys/statfs.h>
  728. #define statfilesys(a,b)    statfs(a,b, sizeof(struct statfs), 0)        /* routine to call when trying to  */
  729.                     /* stat a file system to get the # */
  730.                     /* of free blocks available       */
  731. typedef struct statfs statfs_type;    /* the data type into which statfs() */
  732.                     /* wants to return useful information*/
  733. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  734.                     /* a call to statfs() fails         */
  735. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  736.                     /* # of free blocks             */
  737. #define blkavail(fs)    ((fs).f_bfree)    /* given a statfs_type called fs,  */
  738.                     /* return # of blocks available to */
  739.                     /* a non-privileged user       */
  740. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  741.                      /* return number of free inodes       */
  742. #endif /* apollo */
  743.  
  744. #ifdef ultrix
  745. #include <sys/mount.h>
  746. typedef struct fs_data statfs_type;
  747. #define statfilesys    statfs
  748. #define bombed(call)    ((call) <= 0)
  749. #define blkfree(fs)    ((int)((fs).fd_req.bfree))
  750. #define blkavail(fs)    ((int)((fs).fd_req.bfreen))
  751. #define filfree(fs)    ((int)((fs).fd_req.gfree))
  752. #endif 
  753.  
  754. #if defined(USG) && !defined(hpux)
  755. #include <unistd.h>
  756. typedef struct ustat statfs_type;
  757. /*
  758.  * You've got to make calls to 2 functions to get
  759.  * free blocks on a USG system, so statfilesys can't just be a macro.
  760.  * written by Stan Barber <sob@watson.bcm.tmc.edu>
  761.  */
  762. int
  763. statfilesys(dir, fs)
  764. char *dir;
  765. statfs_type *fs;
  766. {
  767.     struct stat file;
  768.     if (stat(dir,&file)) return(-1);
  769.     if (ustat(file.st_dev, fs)) return(-2);
  770.     return(0);
  771. }
  772. #define bombed(call)    (call != 0)
  773. #define blkfree(fs)    ((fs).f_tfree)
  774. #define blkavail(fs)    ((fs).f_tfree)
  775.                 /* USG doesn't reserve blocks for root */
  776. #define filfree(fs)    ((fs).f_tinode)    
  777. #endif USG
  778.  
  779. #ifdef CMU_MACH
  780. /* This code supplied by Tom Lane <tgl@cs.cmu.edu> */
  781. #include <sys/ioctl.h>
  782. typedef struct fsparam statfs_type;
  783. int
  784. statfilesys(dir, fs)
  785. char *dir;
  786. statfs_type *fs;
  787. {
  788.     int fd;
  789.     fd = open(dir, O_RDONLY);
  790.     if (fd < 0) return(-1);
  791.     if (ioctl(fd, FIOCFSPARAM, fs) < 0) {
  792.     close(fd);
  793.     return(-2);
  794.     }
  795.     close(fd);
  796.     return(0);
  797. }
  798. #define bombed(call)    ((call) < 0)
  799. #define blkfree(fs)    ((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100)
  800. #define blkavail(fs)    (-1)
  801. #endif MACH
  802.  
  803. dfree(spool,free_space)
  804. char *spool;
  805. int free_space;
  806. {
  807.     statfs_type fsys;
  808.     int err;
  809.  
  810.     if (bombed(err = statfilesys(SPOOLDIR, &fsys)))
  811.     return(DFREE_ERR);        /* can't get file system info */
  812. # if defined(filfree) && defined(MINFILES)
  813.      if (filfree(fsys) < MINFILES )
  814.      return( DFREE_INODES );
  815. # endif
  816.     if (blkavail(fsys) < 0L) {
  817.     /* the bavail field doesn't apply to this file system */
  818.     if(blkfree(fsys) < free_space)
  819.         return( DFREE_BLOCKS );
  820.      } else {
  821.     if (blkavail(fsys) < free_space )
  822.         return( DFREE_BLOCKS );
  823.      }
  824.     return( DFREE_OK );
  825. }
  826.  
  827. #else READ_SUPER
  828. /*
  829.  * This code is used if you've got to directly read the superblock
  830.  * to determine how much space you've got left.  It's copied from
  831.  * patches posted by Tad Guy <tadguy@cs.odu.edu>
  832.  */
  833.  
  834. #include <sys/fs.h>
  835. #include <fstab.h>
  836.  
  837. /*
  838.  * return the number of free kilobytes remaining on the filesystem where
  839.  * the named file resides.  returns -1 on error.
  840.  */
  841.  
  842. off_t lseek();
  843.  
  844. dfree(name, free_space)
  845. char *name;
  846. int free_space;
  847. {
  848.     struct stat namest, fsst;
  849.     struct fstab *fsp;
  850.     char lname[MAXPATHLEN];
  851.     int fd;
  852.     union {
  853.     struct fs u_fs;
  854.     char dummy[SBSIZE];
  855.     } sb;
  856. #define sblock sb.u_fs
  857.  
  858.     strcpy(lname,name);
  859.     do {
  860.     if (stat(lname,&namest))        /* if stat fails, die */
  861.     {
  862. #ifdef SYSLOG
  863.       syslog(LOG_ERR,"dfree stat(%s) failed: %m", lname);
  864. #endif
  865.       return  DFREE_ERR;            
  866.     }
  867.     if ((namest.st_mode & S_IFMT) == S_IFLNK) { /* if symlink */
  868.         if ((fd = readlink(lname,lname,sizeof(lname))) < 0) 
  869.         {
  870. #ifdef SYSLOG
  871.           syslog(LOG_ERR,"dfree readlink() failed: %m");
  872. #endif
  873.           return DFREE_ERR;
  874.         }
  875.         lname[fd] = '\0';
  876.     }
  877.     } while ((namest.st_mode & S_IFMT) == S_IFLNK);
  878.  
  879.     (void) setfsent();
  880.  
  881.     while (fsp = getfsent()) {
  882.     if (stat(fsp->fs_spec,&fsst))
  883.       continue;
  884.     if (fsst.st_rdev == namest.st_dev)
  885.       break;
  886.     }
  887.  
  888.     if (!fsp ||    (fd = open(fsp->fs_spec,O_RDONLY)) < 0) {
  889.     (void) endfsent();
  890. #ifdef SYSLOG
  891.     syslog(LOG_ERR,"dfree open(%s,O_RDONLY) failed: %m", fsp->fs_spec);
  892. #endif
  893.     return DFREE_ERR;
  894.     }
  895.     (void) endfsent();
  896.  
  897.     (void) lseek(fd,SBLOCK*DEV_BSIZE,L_SET);
  898.     if (read(fd,(char *)&sblock,SBSIZE) != SBSIZE ||
  899.     (sblock.fs_magic != FS_MAGIC))
  900.     {
  901. #ifdef SYSLOG
  902.       syslog(LOG_ERR,"dfree read() failed: %m");
  903. #endif
  904.       return DFREE_ERR;
  905.     }
  906.     (void) close(fd);
  907.  
  908. # if defined(filfree) && defined(MINFILES)
  909.     if (filfree(fsys) < MINFILES )
  910.     return( DFREE_INODES );
  911. # endif
  912.     if( ((((sblock.fs_dsize) * ( 100 - sblock.fs_minfree) / 100)
  913.       - ((sblock.fs_dsize) 
  914.          - (sblock.fs_cstotal.cs_nbfree 
  915.         * sblock.fs_frag + sblock.fs_cstotal.cs_nffree))) 
  916.      * sblock.fs_fsize / 1024) < free_space )
  917.     return( DFREE_BLOCKS );
  918.    return( DFREE_OK );
  919. }
  920.  
  921. #endif READ_SUPER
  922.  
  923. #ifdef LOAD
  924. /*
  925. **  GETLA -- get the current load average
  926. **
  927. **    This code stolen from la.c. (And subsequently stolen from sendmail,
  928. **        conf.c for nntpd.)
  929. **
  930. **    Parameters:
  931. **        none.
  932. **
  933. **    Returns:
  934. **        The current load average as an integer.
  935. **
  936. **    Side Effects:
  937. **        none.
  938. */
  939.  
  940. #ifdef USG
  941. getla()
  942. {
  943.     return(0);
  944. }
  945. #else
  946. #include <nlist.h>
  947. #include <sys/ioctl.h>
  948.  
  949. struct    nlist Nl[] =
  950. {
  951.     { "_avenrun" },
  952. #define    X_AVENRUN    0
  953.     { 0 },
  954. };
  955.  
  956. getla()
  957. {
  958.     static int kmem = -1;
  959. # ifdef FSCALE
  960.     long avenrun[3];
  961. # else
  962.     double avenrun[3];
  963. # endif
  964.     extern off_t lseek();
  965.  
  966.     if (kmem < 0)
  967.     {
  968.         kmem = open("/dev/kmem", 0, 0);
  969.         if (kmem < 0)
  970.             return (-1);
  971.         (void) ioctl(kmem, (int) FIOCLEX, (char *) 0);
  972.         nlist("/vmunix", Nl);
  973.         if (Nl[0].n_type == 0)
  974.             return (-1);
  975.     }
  976.     if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
  977.         read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
  978.     {
  979.         /* thank you Ian */
  980.         return (-1);
  981.     }
  982. # ifdef FSCALE
  983.     return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
  984. # else
  985.     return ((int) (avenrun[0] + 0.5));
  986. # endif
  987. }
  988. #endif
  989. #endif LOAD
  990.