home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / quota / quota.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  11.5 KB  |  511 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[] = "@(#)quota.c    5.12 (Berkeley) 9/27/90";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  * Disk quota reporting program.
  49.  */
  50. #include <sys/param.h>
  51. #include <sys/file.h>
  52. #include <sys/stat.h>
  53. #include <ufs/quota.h>
  54. #include <stdio.h>
  55. #include <fstab.h>
  56. #include <ctype.h>
  57. #include <pwd.h>
  58. #include <grp.h>
  59. #include <errno.h>
  60.  
  61. char *qfname = QUOTAFILENAME;
  62. char *qfextension[] = INITQFNAMES;
  63.  
  64. struct quotause {
  65.     struct    quotause *next;
  66.     long    flags;
  67.     struct    dqblk dqblk;
  68.     char    fsname[MAXPATHLEN + 1];
  69. } *getprivs();
  70. #define    FOUND    0x01
  71.  
  72. int    qflag;
  73. int    vflag;
  74.  
  75. main(argc, argv)
  76.     char *argv[];
  77. {
  78.     int ngroups, gidset[NGROUPS];
  79.     int i, gflag = 0, uflag = 0;
  80.     char ch;
  81.     extern char *optarg;
  82.     extern int optind, errno;
  83.  
  84.     if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) {
  85.         fprintf(stderr, "There are no quotas on this system\n");
  86.         exit(0);
  87.     }
  88.     while ((ch = getopt(argc, argv, "ugvq")) != EOF) {
  89.         switch(ch) {
  90.         case 'g':
  91.             gflag++;
  92.             break;
  93.         case 'u':
  94.             uflag++;
  95.             break;
  96.         case 'v':
  97.             vflag++;
  98.             break;
  99.         case 'q':
  100.             qflag++;
  101.             break;
  102.         default:
  103.             usage();
  104.         }
  105.     }
  106.     argc -= optind;
  107.     argv += optind;
  108.     if (!uflag && !gflag)
  109.         uflag++;
  110.     if (argc == 0) {
  111.         if (uflag)
  112.             showuid(getuid());
  113.         if (gflag) {
  114.             ngroups = getgroups(NGROUPS, gidset);
  115.             if (ngroups < 0) {
  116.                 perror("quota: getgroups");
  117.                 exit(1);
  118.             }
  119.             for (i = 1; i < ngroups; i++)
  120.                 showgid(gidset[i]);
  121.         }
  122.         exit(0);
  123.     }
  124.     if (uflag && gflag)
  125.         usage();
  126.     if (uflag) {
  127.         for (; argc > 0; argc--, argv++) {
  128.             if (alldigits(*argv))
  129.                 showuid(atoi(*argv));
  130.             else
  131.                 showusrname(*argv);
  132.         }
  133.         exit(0);
  134.     }
  135.     if (gflag) {
  136.         for (; argc > 0; argc--, argv++) {
  137.             if (alldigits(*argv))
  138.                 showgid(atoi(*argv));
  139.             else
  140.                 showgrpname(*argv);
  141.         }
  142.         exit(0);
  143.     }
  144. }
  145.  
  146. usage()
  147. {
  148.  
  149.     fprintf(stderr, "%s\n%s\n%s\n",
  150.         "Usage: quota [-guqv]",
  151.         "\tquota [-qv] -u username ...",
  152.         "\tquota [-qv] -g groupname ...");
  153.     exit(1);
  154. }
  155.  
  156. /*
  157.  * Print out quotas for a specified user identifier.
  158.  */
  159. showuid(uid)
  160.     u_long uid;
  161. {
  162.     struct passwd *pwd = getpwuid(uid);
  163.     u_long myuid;
  164.     char *name;
  165.  
  166.     if (pwd == NULL)
  167.         name = "(no account)";
  168.     else
  169.         name = pwd->pw_name;
  170.     myuid = getuid();
  171.     if (uid != myuid && myuid != 0) {
  172.         printf("quota: %s (uid %d): permission denied\n", name, uid);
  173.         return;
  174.     }
  175.     showquotas(USRQUOTA, uid, name);
  176. }
  177.  
  178. /*
  179.  * Print out quotas for a specifed user name.
  180.  */
  181. showusrname(name)
  182.     char *name;
  183. {
  184.     struct passwd *pwd = getpwnam(name);
  185.     u_long myuid;
  186.  
  187.     if (pwd == NULL) {
  188.         fprintf(stderr, "quota: %s: unknown user\n", name);
  189.         return;
  190.     }
  191.     myuid = getuid();
  192.     if (pwd->pw_uid != myuid && myuid != 0) {
  193.         fprintf(stderr, "quota: %s (uid %d): permission denied\n",
  194.             name, pwd->pw_uid);
  195.         return;
  196.     }
  197.     showquotas(USRQUOTA, pwd->pw_uid, name);
  198. }
  199.  
  200. /*
  201.  * Print out quotas for a specified group identifier.
  202.  */
  203. showgid(gid)
  204.     u_long gid;
  205. {
  206.     struct group *grp = getgrgid(gid);
  207.     int ngroups, gidset[NGROUPS];
  208.     register int i;
  209.     char *name;
  210.  
  211.     if (grp == NULL)
  212.         name = "(no entry)";
  213.     else
  214.         name = grp->gr_name;
  215.     ngroups = getgroups(NGROUPS, gidset);
  216.     if (ngroups < 0) {
  217.         perror("quota: getgroups");
  218.         return;
  219.     }
  220.     for (i = 1; i < ngroups; i++)
  221.         if (gid == gidset[i])
  222.             break;
  223.     if (i >= ngroups && getuid() != 0) {
  224.         fprintf(stderr, "quota: %s (gid %d): permission denied\n",
  225.             name, gid);
  226.         return;
  227.     }
  228.     showquotas(GRPQUOTA, gid, name);
  229. }
  230.  
  231. /*
  232.  * Print out quotas for a specifed group name.
  233.  */
  234. showgrpname(name)
  235.     char *name;
  236. {
  237.     struct group *grp = getgrnam(name);
  238.     int ngroups, gidset[NGROUPS];
  239.     register int i;
  240.  
  241.     if (grp == NULL) {
  242.         fprintf(stderr, "quota: %s: unknown group\n", name);
  243.         return;
  244.     }
  245.     ngroups = getgroups(NGROUPS, gidset);
  246.     if (ngroups < 0) {
  247.         perror("quota: getgroups");
  248.         return;
  249.     }
  250.     for (i = 1; i < ngroups; i++)
  251.         if (grp->gr_gid == gidset[i])
  252.             break;
  253.     if (i >= ngroups && getuid() != 0) {
  254.         fprintf(stderr, "quota: %s (gid %d): permission denied\n",
  255.             name, grp->gr_gid);
  256.         return;
  257.     }
  258.     showquotas(GRPQUOTA, grp->gr_gid, name);
  259. }
  260.  
  261. showquotas(type, id, name)
  262.     int type;
  263.     u_long id;
  264.     char *name;
  265. {
  266.     register struct quotause *qup;
  267.     struct quotause *quplist, *getprivs();
  268.     char *msgi, *msgb, *timeprt();
  269.     int myuid, fd, lines = 0;
  270.     static int first;
  271.     static time_t now;
  272.  
  273.     if (now == 0)
  274.         time(&now);
  275.     quplist = getprivs(id, type);
  276.     for (qup = quplist; qup; qup = qup->next) {
  277.         if (!vflag &&
  278.             qup->dqblk.dqb_isoftlimit == 0 &&
  279.             qup->dqblk.dqb_ihardlimit == 0 &&
  280.             qup->dqblk.dqb_bsoftlimit == 0 &&
  281.             qup->dqblk.dqb_bhardlimit == 0)
  282.             continue;
  283.         msgi = (char *)0;
  284.         if (qup->dqblk.dqb_ihardlimit &&
  285.             qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit)
  286.             msgi = "File limit reached on";
  287.         else if (qup->dqblk.dqb_isoftlimit &&
  288.             qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit)
  289.             if (qup->dqblk.dqb_itime > now)
  290.                 msgi = "In file grace period on";
  291.             else
  292.                 msgi = "Over file quota on";
  293.         msgb = (char *)0;
  294.         if (qup->dqblk.dqb_bhardlimit &&
  295.             qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit)
  296.             msgb = "Block limit reached on";
  297.         else if (qup->dqblk.dqb_bsoftlimit &&
  298.             qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit)
  299.             if (qup->dqblk.dqb_btime > now)
  300.                 msgb = "In block grace period on";
  301.             else
  302.                 msgb = "Over block quota on";
  303.         if (qflag) {
  304.             if ((msgi != (char *)0 || msgb != (char *)0) &&
  305.                 lines++ == 0)
  306.                 heading(type, id, name, "");
  307.             if (msgi != (char *)0)
  308.                 printf("\t%s %s\n", msgi, qup->fsname);
  309.             if (msgb != (char *)0)
  310.                 printf("\t%s %s\n", msgb, qup->fsname);
  311.             continue;
  312.         }
  313.         if (vflag ||
  314.             qup->dqblk.dqb_curblocks ||
  315.             qup->dqblk.dqb_curinodes) {
  316.             if (lines++ == 0)
  317.                 heading(type, id, name, "");
  318.             printf("%15s%8d%c%7d%8d%8s"
  319.                 , qup->fsname
  320.                 , dbtob(qup->dqblk.dqb_curblocks) / 1024
  321.                 , (msgb == (char *)0) ? ' ' : '*'
  322.                 , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024
  323.                 , dbtob(qup->dqblk.dqb_bhardlimit) / 1024
  324.                 , (msgb == (char *)0) ? ""
  325.                     : timeprt(qup->dqblk.dqb_btime));
  326.             printf("%8d%c%7d%8d%8s\n"
  327.                 , qup->dqblk.dqb_curinodes
  328.                 , (msgi == (char *)0) ? ' ' : '*'
  329.                 , qup->dqblk.dqb_isoftlimit
  330.                 , qup->dqblk.dqb_ihardlimit
  331.                 , (msgi == (char *)0) ? ""
  332.                     : timeprt(qup->dqblk.dqb_itime)
  333.             );
  334.             continue;
  335.         }
  336.     }
  337.     if (!qflag && lines == 0)
  338.         heading(type, id, name, "none");
  339. }
  340.  
  341. heading(type, id, name, tag)
  342.     int type;
  343.     u_long id;
  344.     char *name, *tag;
  345. {
  346.  
  347.     printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type],
  348.         name, *qfextension[type], id, tag);
  349.     if (!qflag && tag[0] == '\0') {
  350.         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
  351.             , "Filesystem"
  352.             , "blocks"
  353.             , "quota"
  354.             , "limit"
  355.             , "grace"
  356.             , "files"
  357.             , "quota"
  358.             , "limit"
  359.             , "grace"
  360.         );
  361.     }
  362. }
  363.  
  364. /*
  365.  * Calculate the grace period and return a printable string for it.
  366.  */
  367. char *
  368. timeprt(seconds)
  369.     time_t seconds;
  370. {
  371.     time_t hours, minutes;
  372.     static char buf[20];
  373.     static time_t now;
  374.  
  375.     if (now == 0)
  376.         time(&now);
  377.     if (now > seconds)
  378.         return ("none");
  379.     seconds -= now;
  380.     minutes = (seconds + 30) / 60;
  381.     hours = (minutes + 30) / 60;
  382.     if (hours >= 36) {
  383.         sprintf(buf, "%ddays", (hours + 12) / 24);
  384.         return (buf);
  385.     }
  386.     if (minutes >= 60) {
  387.         sprintf(buf, "%2d:%d", minutes / 60, minutes % 60);
  388.         return (buf);
  389.     }
  390.     sprintf(buf, "%2d", minutes);
  391.     return (buf);
  392. }
  393.  
  394. /*
  395.  * Collect the requested quota information.
  396.  */
  397. struct quotause *
  398. getprivs(id, quotatype)
  399.     register long id;
  400.     int quotatype;
  401. {
  402.     register struct fstab *fs;
  403.     register struct quotause *qup, *quptail;
  404.     struct quotause *quphead;
  405.     char *qfpathname;
  406.     int qcmd, fd;
  407.  
  408.     setfsent();
  409.     quphead = (struct quotause *)0;
  410.     qcmd = QCMD(Q_GETQUOTA, quotatype);
  411.     while (fs = getfsent()) {
  412.         if (strcmp(fs->fs_vfstype, "ufs"))
  413.             continue;
  414.         if (!hasquota(fs, quotatype, &qfpathname))
  415.             continue;
  416.         if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
  417.             fprintf(stderr, "quota: out of memory\n");
  418.             exit(2);
  419.         }
  420.         if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
  421.             if ((fd = open(qfpathname, O_RDONLY)) < 0) {
  422.                 perror(qfpathname);
  423.                 free(qup);
  424.                 continue;
  425.             }
  426.             lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
  427.             switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
  428.             case 0:            /* EOF */
  429.                 /*
  430.                  * Convert implicit 0 quota (EOF)
  431.                  * into an explicit one (zero'ed dqblk)
  432.                  */
  433.                 bzero((caddr_t)&qup->dqblk,
  434.                     sizeof(struct dqblk));
  435.                 break;
  436.  
  437.             case sizeof(struct dqblk):    /* OK */
  438.                 break;
  439.  
  440.             default:        /* ERROR */
  441.                 fprintf(stderr, "quota: read error");
  442.                 perror(qfpathname);
  443.                 close(fd);
  444.                 free(qup);
  445.                 continue;
  446.             }
  447.             close(fd);
  448.         }
  449.         strcpy(qup->fsname, fs->fs_file);
  450.         if (quphead == NULL)
  451.             quphead = qup;
  452.         else
  453.             quptail->next = qup;
  454.         quptail = qup;
  455.         qup->next = 0;
  456.     }
  457.     endfsent();
  458.     return (quphead);
  459. }
  460.  
  461. /*
  462.  * Check to see if a particular quota is to be enabled.
  463.  */
  464. hasquota(fs, type, qfnamep)
  465.     register struct fstab *fs;
  466.     int type;
  467.     char **qfnamep;
  468. {
  469.     register char *opt;
  470.     char *cp, *index(), *strtok();
  471.     static char initname, usrname[100], grpname[100];
  472.     static char buf[BUFSIZ];
  473.  
  474.     if (!initname) {
  475.         sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
  476.         sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
  477.         initname = 1;
  478.     }
  479.     strcpy(buf, fs->fs_mntops);
  480.     for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
  481.         if (cp = index(opt, '='))
  482.             *cp++ = '\0';
  483.         if (type == USRQUOTA && strcmp(opt, usrname) == 0)
  484.             break;
  485.         if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
  486.             break;
  487.     }
  488.     if (!opt)
  489.         return (0);
  490.     if (cp) {
  491.         *qfnamep = cp;
  492.         return (1);
  493.     }
  494.     (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
  495.     *qfnamep = buf;
  496.     return (1);
  497. }
  498.  
  499. alldigits(s)
  500.     register char *s;
  501. {
  502.     register c;
  503.  
  504.     c = *s++;
  505.     do {
  506.         if (!isdigit(c))
  507.             return (0);
  508.     } while (c = *s++);
  509.     return (1);
  510. }
  511.