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

  1. /*
  2.  * Copyright (c) 1980, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Robert Elz at The University of Melbourne.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)edquota.c    5.15 (Berkeley) 9/27/90";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  * Disk quota editor.
  49.  */
  50. #include <sys/param.h>
  51. #include <sys/stat.h>
  52. #include <sys/file.h>
  53. #include <sys/wait.h>
  54. #include <ufs/quota.h>
  55. #include <errno.h>
  56. #include <fstab.h>
  57. #include <pwd.h>
  58. #include <grp.h>
  59. #include <ctype.h>
  60. #include <stdio.h>
  61. #include <string.h>
  62. #include "pathnames.h"
  63.  
  64. char *qfname = QUOTAFILENAME;
  65. char *qfextension[] = INITQFNAMES;
  66. char *quotagroup = QUOTAGROUP;
  67. char tmpfil[] = _PATH_TMP;
  68.  
  69. struct quotause {
  70.     struct    quotause *next;
  71.     long    flags;
  72.     struct    dqblk dqblk;
  73.     char    fsname[MAXPATHLEN + 1];
  74.     char    qfname[1];    /* actually longer */
  75. } *getprivs();
  76. #define    FOUND    0x01
  77.  
  78. main(argc, argv)
  79.     register char **argv;
  80.     int argc;
  81. {
  82.     register struct quotause *qup, *protoprivs, *curprivs;
  83.     extern char *optarg;
  84.     extern int optind;
  85.     register long id, protoid;
  86.     register int quotatype, tmpfd;
  87.     char *protoname, ch;
  88.     int tflag = 0, pflag = 0;
  89.  
  90.     if (argc < 2)
  91.         usage();
  92.     if (getuid()) {
  93.         fprintf(stderr, "edquota: permission denied\n");
  94.         exit(1);
  95.     }
  96.     quotatype = USRQUOTA;
  97.     while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
  98.         switch(ch) {
  99.         case 'p':
  100.             protoname = optarg;
  101.             pflag++;
  102.             break;
  103.         case 'g':
  104.             quotatype = GRPQUOTA;
  105.             break;
  106.         case 'u':
  107.             quotatype = USRQUOTA;
  108.             break;
  109.         case 't':
  110.             tflag++;
  111.             break;
  112.         default:
  113.             usage();
  114.         }
  115.     }
  116.     argc -= optind;
  117.     argv += optind;
  118.     if (pflag) {
  119.         if ((protoid = getentry(protoname, quotatype)) == -1)
  120.             exit(1);
  121.         protoprivs = getprivs(protoid, quotatype);
  122.         for (qup = protoprivs; qup; qup = qup->next) {
  123.             qup->dqblk.dqb_btime = 0;
  124.             qup->dqblk.dqb_itime = 0;
  125.         }
  126.         while (argc-- > 0) {
  127.             if ((id = getentry(*argv++, quotatype)) < 0)
  128.                 continue;
  129.             putprivs(id, quotatype, protoprivs);
  130.         }
  131.         exit(0);
  132.     }
  133.     tmpfd = mkstemp(tmpfil);
  134.     fchown(tmpfd, getuid(), getgid());
  135.     if (tflag) {
  136.         protoprivs = getprivs(0, quotatype);
  137.         if (writetimes(protoprivs, tmpfd, quotatype) == 0)
  138.             exit(1);
  139.         if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
  140.             putprivs(0, quotatype, protoprivs);
  141.         freeprivs(protoprivs);
  142.         exit(0);
  143.     }
  144.     for ( ; argc > 0; argc--, argv++) {
  145.         if ((id = getentry(*argv, quotatype)) == -1)
  146.             continue;
  147.         curprivs = getprivs(id, quotatype);
  148.         if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
  149.             continue;
  150.         if (editit(tmpfil) && readprivs(curprivs, tmpfd))
  151.             putprivs(id, quotatype, curprivs);
  152.         freeprivs(curprivs);
  153.     }
  154.     close(tmpfd);
  155.     unlink(tmpfil);
  156.     exit(0);
  157. }
  158.  
  159. usage()
  160. {
  161.     fprintf(stderr, "%s%s%s%s",
  162.         "Usage: edquota [-u] [-p username] username ...\n",
  163.         "\tedquota -g [-p groupname] groupname ...\n",
  164.         "\tedquota [-u] -t\n", "\tedquota -g -t\n");
  165.     exit(1);
  166. }
  167.  
  168. /*
  169.  * This routine converts a name for a particular quota type to
  170.  * an identifier. This routine must agree with the kernel routine
  171.  * getinoquota as to the interpretation of quota types.
  172.  */
  173. getentry(name, quotatype)
  174.     char *name;
  175.     int quotatype;
  176. {
  177.     struct passwd *pw;
  178.     struct group *gr;
  179.  
  180.     if (alldigits(name))
  181.         return (atoi(name));
  182.     switch(quotatype) {
  183.     case USRQUOTA:
  184.         if (pw = getpwnam(name))
  185.             return (pw->pw_uid);
  186.         fprintf(stderr, "%s: no such user\n", name);
  187.         break;
  188.     case GRPQUOTA:
  189.         if (gr = getgrnam(name))
  190.             return (gr->gr_gid);
  191.         fprintf(stderr, "%s: no such group\n", name);
  192.         break;
  193.     default:
  194.         fprintf(stderr, "%d: unknown quota type\n", quotatype);
  195.         break;
  196.     }
  197.     sleep(1);
  198.     return (-1);
  199. }
  200.  
  201. /*
  202.  * Collect the requested quota information.
  203.  */
  204. struct quotause *
  205. getprivs(id, quotatype)
  206.     register long id;
  207.     int quotatype;
  208. {
  209.     register struct fstab *fs;
  210.     register struct quotause *qup, *quptail;
  211.     struct quotause *quphead;
  212.     int qcmd, qupsize, fd;
  213.     char *qfpathname;
  214.     static int warned = 0;
  215.     extern int errno;
  216.  
  217.     setfsent();
  218.     quphead = (struct quotause *)0;
  219.     qcmd = QCMD(Q_GETQUOTA, quotatype);
  220.     while (fs = getfsent()) {
  221.         if (strcmp(fs->fs_vfstype, "ufs"))
  222.             continue;
  223.         if (!hasquota(fs, quotatype, &qfpathname))
  224.             continue;
  225.         qupsize = sizeof(*qup) + strlen(qfpathname);
  226.         if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
  227.             fprintf(stderr, "edquota: out of memory\n");
  228.             exit(2);
  229.         }
  230.         if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
  231.                 if (errno == EOPNOTSUPP && !warned) {
  232.                 warned++;
  233.                 fprintf(stderr, "Warning: %s\n",
  234.                     "Quotas are not compiled into this kernel");
  235.                 sleep(3);
  236.             }
  237.             if ((fd = open(qfpathname, O_RDONLY)) < 0) {
  238.                 fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
  239.                 if (fd < 0 && errno != ENOENT) {
  240.                     perror(qfpathname);
  241.                     free(qup);
  242.                     continue;
  243.                 }
  244.                 fprintf(stderr, "Creating quota file %s\n",
  245.                     qfpathname);
  246.                 sleep(3);
  247.                 (void) fchown(fd, getuid(),
  248.                     getentry(quotagroup, GRPQUOTA));
  249.                 (void) fchmod(fd, 0640);
  250.             }
  251.             lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
  252.             switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
  253.             case 0:            /* EOF */
  254.                 /*
  255.                  * Convert implicit 0 quota (EOF)
  256.                  * into an explicit one (zero'ed dqblk)
  257.                  */
  258.                 bzero((caddr_t)&qup->dqblk,
  259.                     sizeof(struct dqblk));
  260.                 break;
  261.  
  262.             case sizeof(struct dqblk):    /* OK */
  263.                 break;
  264.  
  265.             default:        /* ERROR */
  266.                 fprintf(stderr, "edquota: read error in ");
  267.                 perror(qfpathname);
  268.                 close(fd);
  269.                 free(qup);
  270.                 continue;
  271.             }
  272.             close(fd);
  273.         }
  274.         strcpy(qup->qfname, qfpathname);
  275.         strcpy(qup->fsname, fs->fs_file);
  276.         if (quphead == NULL)
  277.             quphead = qup;
  278.         else
  279.             quptail->next = qup;
  280.         quptail = qup;
  281.         qup->next = 0;
  282.     }
  283.     endfsent();
  284.     return (quphead);
  285. }
  286.  
  287. /*
  288.  * Store the requested quota information.
  289.  */
  290. putprivs(id, quotatype, quplist)
  291.     long id;
  292.     int quotatype;
  293.     struct quotause *quplist;
  294. {
  295.     register struct quotause *qup;
  296.     int qcmd, fd;
  297.  
  298.     qcmd = QCMD(Q_SETQUOTA, quotatype);
  299.     for (qup = quplist; qup; qup = qup->next) {
  300.         if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
  301.             continue;
  302.         if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
  303.             perror(qup->qfname);
  304.         } else {
  305.             lseek(fd, (long)id * (long)sizeof (struct dqblk), 0);
  306.             if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
  307.                 sizeof (struct dqblk)) {
  308.                 fprintf(stderr, "edquota: ");
  309.                 perror(qup->qfname);
  310.             }
  311.             close(fd);
  312.         }
  313.     }
  314. }
  315.  
  316. /*
  317.  * Take a list of priviledges and get it edited.
  318.  */
  319. editit(tmpfile)
  320.     char *tmpfile;
  321. {
  322.     long omask;
  323.     int pid, stat;
  324.     extern char *getenv();
  325.  
  326.     omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
  327.  top:
  328.     if ((pid = fork()) < 0) {
  329.         extern errno;
  330.  
  331.         if (errno == EPROCLIM) {
  332.             fprintf(stderr, "You have too many processes\n");
  333.             return(0);
  334.         }
  335.         if (errno == EAGAIN) {
  336.             sleep(1);
  337.             goto top;
  338.         }
  339.         perror("fork");
  340.         return (0);
  341.     }
  342.     if (pid == 0) {
  343.         register char *ed;
  344.  
  345.         sigsetmask(omask);
  346.         setgid(getgid());
  347.         setuid(getuid());
  348.         if ((ed = getenv("EDITOR")) == (char *)0)
  349.             ed = _PATH_VI;
  350.         execlp(ed, ed, tmpfile, 0);
  351.         perror(ed);
  352.         exit(1);
  353.     }
  354.     waitpid(pid, &stat, 0);
  355.     sigsetmask(omask);
  356.     if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
  357.         return (0);
  358.     return (1);
  359. }
  360.  
  361. /*
  362.  * Convert a quotause list to an ASCII file.
  363.  */
  364. writeprivs(quplist, outfd, name, quotatype)
  365.     struct quotause *quplist;
  366.     int outfd;
  367.     char *name;
  368.     int quotatype;
  369. {
  370.     register struct quotause *qup;
  371.     FILE *fd;
  372.  
  373.     ftruncate(outfd, 0);
  374.     lseek(outfd, 0, L_SET);
  375.     if ((fd = fdopen(dup(outfd), "w")) == NULL) {
  376.         fprintf(stderr, "edquota: ");
  377.         perror(tmpfil);
  378.         exit(1);
  379.     }
  380.     fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
  381.     for (qup = quplist; qup; qup = qup->next) {
  382.         fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
  383.             qup->fsname, "blocks in use:",
  384.             dbtob(qup->dqblk.dqb_curblocks) / 1024,
  385.             dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
  386.             dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
  387.         fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
  388.             "\tinodes in use:", qup->dqblk.dqb_curinodes,
  389.             qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
  390.     }
  391.     fclose(fd);
  392.     return (1);
  393. }
  394.  
  395. /*
  396.  * Merge changes to an ASCII file into a quotause list.
  397.  */
  398. readprivs(quplist, infd)
  399.     struct quotause *quplist;
  400.     int infd;
  401. {
  402.     register struct quotause *qup;
  403.     FILE *fd;
  404.     int cnt;
  405.     register char *cp;
  406.     struct dqblk dqblk;
  407.     char *fsp, line1[BUFSIZ], line2[BUFSIZ];
  408.  
  409.     lseek(infd, 0, L_SET);
  410.     fd = fdopen(dup(infd), "r");
  411.     if (fd == NULL) {
  412.         fprintf(stderr, "Can't re-read temp file!!\n");
  413.         return (0);
  414.     }
  415.     /*
  416.      * Discard title line, then read pairs of lines to process.
  417.      */
  418.     (void) fgets(line1, sizeof (line1), fd);
  419.     while (fgets(line1, sizeof (line1), fd) != NULL &&
  420.            fgets(line2, sizeof (line2), fd) != NULL) {
  421.         if ((fsp = strtok(line1, " \t:")) == NULL) {
  422.             fprintf(stderr, "%s: bad format\n", line1);
  423.             return (0);
  424.         }
  425.         if ((cp = strtok((char *)0, "\n")) == NULL) {
  426.             fprintf(stderr, "%s: %s: bad format\n", fsp,
  427.                 &fsp[strlen(fsp) + 1]);
  428.             return (0);
  429.         }
  430.         cnt = sscanf(cp,
  431.             " blocks in use: %d, limits (soft = %d, hard = %d)",
  432.             &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
  433.             &dqblk.dqb_bhardlimit);
  434.         if (cnt != 3) {
  435.             fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
  436.             return (0);
  437.         }
  438.         dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
  439.         dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
  440.         dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
  441.         if ((cp = strtok(line2, "\n")) == NULL) {
  442.             fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
  443.             return (0);
  444.         }
  445.         cnt = sscanf(cp,
  446.             "\tinodes in use: %d, limits (soft = %d, hard = %d)",
  447.             &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
  448.             &dqblk.dqb_ihardlimit);
  449.         if (cnt != 3) {
  450.             fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
  451.             return (0);
  452.         }
  453.         for (qup = quplist; qup; qup = qup->next) {
  454.             if (strcmp(fsp, qup->fsname))
  455.                 continue;
  456.             /*
  457.              * Cause time limit to be reset when the quota
  458.              * is next used if previously had no soft limit
  459.              * or were under it, but now have a soft limit
  460.              * and are over it.
  461.              */
  462.             if (dqblk.dqb_bsoftlimit &&
  463.                 qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
  464.                 (qup->dqblk.dqb_bsoftlimit == 0 ||
  465.                  qup->dqblk.dqb_curblocks <
  466.                  qup->dqblk.dqb_bsoftlimit))
  467.                 qup->dqblk.dqb_btime = 0;
  468.             if (dqblk.dqb_isoftlimit &&
  469.                 qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
  470.                 (qup->dqblk.dqb_isoftlimit == 0 ||
  471.                  qup->dqblk.dqb_curinodes <
  472.                  qup->dqblk.dqb_isoftlimit))
  473.                 qup->dqblk.dqb_itime = 0;
  474.             qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
  475.             qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
  476.             qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
  477.             qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
  478.             qup->flags |= FOUND;
  479.             if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
  480.                 dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
  481.                 break;
  482.             fprintf(stderr,
  483.                 "%s: cannot change current allocation\n", fsp);
  484.             break;
  485.         }
  486.     }
  487.     fclose(fd);
  488.     /*
  489.      * Disable quotas for any filesystems that have not been found.
  490.      */
  491.     for (qup = quplist; qup; qup = qup->next) {
  492.         if (qup->flags & FOUND) {
  493.             qup->flags &= ~FOUND;
  494.             continue;
  495.         }
  496.         qup->dqblk.dqb_bsoftlimit = 0;
  497.         qup->dqblk.dqb_bhardlimit = 0;
  498.         qup->dqblk.dqb_isoftlimit = 0;
  499.         qup->dqblk.dqb_ihardlimit = 0;
  500.     }
  501.     return (1);
  502. }
  503.  
  504. /*
  505.  * Convert a quotause list to an ASCII file of grace times.
  506.  */
  507. writetimes(quplist, outfd, quotatype)
  508.     struct quotause *quplist;
  509.     int outfd;
  510.     int quotatype;
  511. {
  512.     register struct quotause *qup;
  513.     char *cvtstoa();
  514.     FILE *fd;
  515.  
  516.     ftruncate(outfd, 0);
  517.     lseek(outfd, 0, L_SET);
  518.     if ((fd = fdopen(dup(outfd), "w")) == NULL) {
  519.         fprintf(stderr, "edquota: ");
  520.         perror(tmpfil);
  521.         exit(1);
  522.     }
  523.     fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
  524.     fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
  525.         qfextension[quotatype]);
  526.     for (qup = quplist; qup; qup = qup->next) {
  527.         fprintf(fd, "%s: block grace period: %s, ",
  528.             qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
  529.         fprintf(fd, "file grace period: %s\n",
  530.             cvtstoa(qup->dqblk.dqb_itime));
  531.     }
  532.     fclose(fd);
  533.     return (1);
  534. }
  535.  
  536. /*
  537.  * Merge changes of grace times in an ASCII file into a quotause list.
  538.  */
  539. readtimes(quplist, infd)
  540.     struct quotause *quplist;
  541.     int infd;
  542. {
  543.     register struct quotause *qup;
  544.     FILE *fd;
  545.     int cnt;
  546.     register char *cp;
  547.     time_t itime, btime, iseconds, bseconds;
  548.     char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
  549.  
  550.     lseek(infd, 0, L_SET);
  551.     fd = fdopen(dup(infd), "r");
  552.     if (fd == NULL) {
  553.         fprintf(stderr, "Can't re-read temp file!!\n");
  554.         return (0);
  555.     }
  556.     /*
  557.      * Discard two title lines, then read lines to process.
  558.      */
  559.     (void) fgets(line1, sizeof (line1), fd);
  560.     (void) fgets(line1, sizeof (line1), fd);
  561.     while (fgets(line1, sizeof (line1), fd) != NULL) {
  562.         if ((fsp = strtok(line1, " \t:")) == NULL) {
  563.             fprintf(stderr, "%s: bad format\n", line1);
  564.             return (0);
  565.         }
  566.         if ((cp = strtok((char *)0, "\n")) == NULL) {
  567.             fprintf(stderr, "%s: %s: bad format\n", fsp,
  568.                 &fsp[strlen(fsp) + 1]);
  569.             return (0);
  570.         }
  571.         cnt = sscanf(cp,
  572.             " block grace period: %d %s file grace period: %d %s",
  573.             &btime, bunits, &itime, iunits);
  574.         if (cnt != 4) {
  575.             fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
  576.             return (0);
  577.         }
  578.         if (cvtatos(btime, bunits, &bseconds) == 0)
  579.             return (0);
  580.         if (cvtatos(itime, iunits, &iseconds) == 0)
  581.             return (0);
  582.         for (qup = quplist; qup; qup = qup->next) {
  583.             if (strcmp(fsp, qup->fsname))
  584.                 continue;
  585.             qup->dqblk.dqb_btime = bseconds;
  586.             qup->dqblk.dqb_itime = iseconds;
  587.             qup->flags |= FOUND;
  588.             break;
  589.         }
  590.     }
  591.     fclose(fd);
  592.     /*
  593.      * reset default grace periods for any filesystems
  594.      * that have not been found.
  595.      */
  596.     for (qup = quplist; qup; qup = qup->next) {
  597.         if (qup->flags & FOUND) {
  598.             qup->flags &= ~FOUND;
  599.             continue;
  600.         }
  601.         qup->dqblk.dqb_btime = 0;
  602.         qup->dqblk.dqb_itime = 0;
  603.     }
  604.     return (1);
  605. }
  606.  
  607. /*
  608.  * Convert seconds to ASCII times.
  609.  */
  610. char *
  611. cvtstoa(time)
  612.     time_t time;
  613. {
  614.     static char buf[20];
  615.  
  616.     if (time % (24 * 60 * 60) == 0) {
  617.         time /= 24 * 60 * 60;
  618.         sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
  619.     } else if (time % (60 * 60) == 0) {
  620.         time /= 60 * 60;
  621.         sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
  622.     } else if (time % 60 == 0) {
  623.         time /= 60;
  624.         sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
  625.     } else
  626.         sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
  627.     return (buf);
  628. }
  629.  
  630. /*
  631.  * Convert ASCII input times to seconds.
  632.  */
  633. cvtatos(time, units, seconds)
  634.     time_t time;
  635.     char *units;
  636.     time_t *seconds;
  637. {
  638.  
  639.     if (bcmp(units, "second", 6) == 0)
  640.         *seconds = time;
  641.     else if (bcmp(units, "minute", 6) == 0)
  642.         *seconds = time * 60;
  643.     else if (bcmp(units, "hour", 4) == 0)
  644.         *seconds = time * 60 * 60;
  645.     else if (bcmp(units, "day", 3) == 0)
  646.         *seconds = time * 24 * 60 * 60;
  647.     else {
  648.         printf("%s: bad units, specify %s\n", units,
  649.             "days, hours, minutes, or seconds");
  650.         return (0);
  651.     }
  652.     return (1);
  653. }
  654.  
  655. /*
  656.  * Free a list of quotause structures.
  657.  */
  658. freeprivs(quplist)
  659.     struct quotause *quplist;
  660. {
  661.     register struct quotause *qup, *nextqup;
  662.  
  663.     for (qup = quplist; qup; qup = nextqup) {
  664.         nextqup = qup->next;
  665.         free(qup);
  666.     }
  667. }
  668.  
  669. /*
  670.  * Check whether a string is completely composed of digits.
  671.  */
  672. alldigits(s)
  673.     register char *s;
  674. {
  675.     register c;
  676.  
  677.     c = *s++;
  678.     do {
  679.         if (!isdigit(c))
  680.             return (0);
  681.     } while (c = *s++);
  682.     return (1);
  683. }
  684.  
  685. /*
  686.  * Check to see if a particular quota is to be enabled.
  687.  */
  688. hasquota(fs, type, qfnamep)
  689.     register struct fstab *fs;
  690.     int type;
  691.     char **qfnamep;
  692. {
  693.     register char *opt;
  694.     char *cp, *index(), *strtok();
  695.     static char initname, usrname[100], grpname[100];
  696.     static char buf[BUFSIZ];
  697.  
  698.     if (!initname) {
  699.         sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
  700.         sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
  701.         initname = 1;
  702.     }
  703.     strcpy(buf, fs->fs_mntops);
  704.     for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
  705.         if (cp = index(opt, '='))
  706.             *cp++ = '\0';
  707.         if (type == USRQUOTA && strcmp(opt, usrname) == 0)
  708.             break;
  709.         if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
  710.             break;
  711.     }
  712.     if (!opt)
  713.         return (0);
  714.     if (cp) {
  715.         *qfnamep = cp;
  716.         return (1);
  717.     }
  718.     (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
  719.     *qfnamep = buf;
  720.     return (1);
  721. }
  722.