home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / repquota / repquota.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-19  |  9.5 KB  |  380 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[] = "@(#)repquota.c    5.11 (Berkeley) 9/27/90";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  * Quota report
  49.  */
  50. #include <sys/param.h>
  51. #include <sys/stat.h>
  52. #include <ufs/quota.h>
  53. #include <fstab.h>
  54. #include <pwd.h>
  55. #include <grp.h>
  56. #include <stdio.h>
  57. #include <errno.h>
  58.  
  59. char *qfname = QUOTAFILENAME;
  60. char *qfextension[] = INITQFNAMES;
  61.  
  62. struct fileusage {
  63.     struct    fileusage *fu_next;
  64.     struct    dqblk fu_dqblk;
  65.     u_long    fu_id;
  66.     char    fu_name[1];
  67.     /* actually bigger */
  68. };
  69. #define FUHASH 1024    /* must be power of two */
  70. struct fileusage *fuhead[MAXQUOTAS][FUHASH];
  71. struct fileusage *lookup();
  72. struct fileusage *addid();
  73. u_long highid[MAXQUOTAS];    /* highest addid()'ed identifier per type */
  74.  
  75. int    vflag;            /* verbose */
  76. int    aflag;            /* all file systems */
  77.  
  78. main(argc, argv)
  79.     int argc;
  80.     char **argv;
  81. {
  82.     register struct fstab *fs;
  83.     register struct passwd *pw;
  84.     register struct group *gr;
  85.     int gflag = 0, uflag = 0, errs = 0;
  86.     long i, argnum, done = 0;
  87.     extern char *optarg;
  88.     extern int optind;
  89.     char ch, *qfnp;
  90.  
  91.     while ((ch = getopt(argc, argv, "aguv")) != EOF) {
  92.         switch(ch) {
  93.         case 'a':
  94.             aflag++;
  95.             break;
  96.         case 'g':
  97.             gflag++;
  98.             break;
  99.         case 'u':
  100.             uflag++;
  101.             break;
  102.         case 'v':
  103.             vflag++;
  104.             break;
  105.         default:
  106.             usage();
  107.         }
  108.     }
  109.     argc -= optind;
  110.     argv += optind;
  111.     if (argc == 0 && !aflag)
  112.         usage();
  113.     if (!gflag && !uflag) {
  114.         if (aflag)
  115.             gflag++;
  116.         uflag++;
  117.     }
  118.     if (gflag) {
  119.         setgrent();
  120.         while ((gr = getgrent()) != 0)
  121.             (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
  122.         endgrent();
  123.     }
  124.     if (uflag) {
  125.         setpwent();
  126.         while ((pw = getpwent()) != 0)
  127.             (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
  128.         endpwent();
  129.     }
  130.     setfsent();
  131.     while ((fs = getfsent()) != NULL) {
  132.         if (strcmp(fs->fs_vfstype, "ufs"))
  133.             continue;
  134.         if (aflag) {
  135.             if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
  136.                 errs += repquota(fs, GRPQUOTA, qfnp);
  137.             if (uflag && hasquota(fs, USRQUOTA, &qfnp))
  138.                 errs += repquota(fs, USRQUOTA, qfnp);
  139.             continue;
  140.         }
  141.         if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
  142.             (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
  143.             done |= 1 << argnum;
  144.             if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
  145.                 errs += repquota(fs, GRPQUOTA, qfnp);
  146.             if (uflag && hasquota(fs, USRQUOTA, &qfnp))
  147.                 errs += repquota(fs, USRQUOTA, qfnp);
  148.         }
  149.     }
  150.     endfsent();
  151.     for (i = 0; i < argc; i++)
  152.         if ((done & (1 << i)) == 0)
  153.             fprintf(stderr, "%s not found in fstab\n", argv[i]);
  154.     exit(errs);
  155. }
  156.  
  157. usage()
  158. {
  159.     fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
  160.         "repquota [-v] [-g] [-u] -a",
  161.         "repquota [-v] [-g] [-u] filesys ...");
  162.     exit(1);
  163. }
  164.  
  165. repquota(fs, type, qfpathname)
  166.     register struct fstab *fs;
  167.     int type;
  168.     char *qfpathname;
  169. {
  170.     register struct fileusage *fup;
  171.     FILE *qf;
  172.     u_long id;
  173.     struct dqblk dqbuf;
  174.     char *timeprt();
  175.     static struct dqblk zerodqblk;
  176.     static int warned = 0;
  177.     static int multiple = 0;
  178.     extern int errno;
  179.  
  180.     if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
  181.         errno == EOPNOTSUPP && !warned && vflag) {
  182.         warned++;
  183.         fprintf(stdout,
  184.             "*** Warning: Quotas are not compiled into this kernel\n");
  185.     }
  186.     if (multiple++)
  187.         printf("\n");
  188.     if (vflag)
  189.         fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
  190.             qfextension[type], fs->fs_file, fs->fs_spec);
  191.     if ((qf = fopen(qfpathname, "r")) == NULL) {
  192.         perror(qfpathname);
  193.         return (1);
  194.     }
  195.     for (id = 0; ; id++) {
  196.         fread(&dqbuf, sizeof(struct dqblk), 1, qf);
  197.         if (feof(qf))
  198.             break;
  199.         if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
  200.             continue;
  201.         if ((fup = lookup(id, type)) == 0)
  202.             fup = addid(id, type, (char *)0);
  203.         fup->fu_dqblk = dqbuf;
  204.     }
  205.     fclose(qf);
  206.     printf("                        Block limits               File limits\n");
  207.     printf("User            used    soft    hard  grace    used  soft  hard  grace\n");
  208.     for (id = 0; id <= highid[type]; id++) {
  209.         fup = lookup(id, type);
  210.         if (fup == 0)
  211.             continue;
  212.         if (fup->fu_dqblk.dqb_curinodes == 0 &&
  213.             fup->fu_dqblk.dqb_curblocks == 0)
  214.             continue;
  215.         printf("%-10s", fup->fu_name);
  216.         printf("%c%c%8d%8d%8d%7s",
  217.             fup->fu_dqblk.dqb_bsoftlimit && 
  218.                 fup->fu_dqblk.dqb_curblocks >= 
  219.                 fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-',
  220.             fup->fu_dqblk.dqb_isoftlimit &&
  221.                 fup->fu_dqblk.dqb_curinodes >=
  222.                 fup->fu_dqblk.dqb_isoftlimit ? '+' : '-',
  223.             dbtob(fup->fu_dqblk.dqb_curblocks) / 1024,
  224.             dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024,
  225.             dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024,
  226.             fup->fu_dqblk.dqb_bsoftlimit && 
  227.                 fup->fu_dqblk.dqb_curblocks >= 
  228.                 fup->fu_dqblk.dqb_bsoftlimit ?
  229.                 timeprt(fup->fu_dqblk.dqb_btime) : "");
  230.         printf("  %6d%6d%6d%7s\n",
  231.             fup->fu_dqblk.dqb_curinodes,
  232.             fup->fu_dqblk.dqb_isoftlimit,
  233.             fup->fu_dqblk.dqb_ihardlimit,
  234.             fup->fu_dqblk.dqb_isoftlimit &&
  235.                 fup->fu_dqblk.dqb_curinodes >=
  236.                 fup->fu_dqblk.dqb_isoftlimit ?
  237.                 timeprt(fup->fu_dqblk.dqb_itime) : "");
  238.         fup->fu_dqblk = zerodqblk;
  239.     }
  240.     return (0);
  241. }
  242.  
  243. /*
  244.  * Check to see if target appears in list of size cnt.
  245.  */
  246. oneof(target, list, cnt)
  247.     register char *target, *list[];
  248.     int cnt;
  249. {
  250.     register int i;
  251.  
  252.     for (i = 0; i < cnt; i++)
  253.         if (strcmp(target, list[i]) == 0)
  254.             return (i);
  255.     return (-1);
  256. }
  257.  
  258. /*
  259.  * Check to see if a particular quota is to be enabled.
  260.  */
  261. hasquota(fs, type, qfnamep)
  262.     register struct fstab *fs;
  263.     int type;
  264.     char **qfnamep;
  265. {
  266.     register char *opt;
  267.     char *cp, *index(), *strtok();
  268.     static char initname, usrname[100], grpname[100];
  269.     static char buf[BUFSIZ];
  270.  
  271.     if (!initname) {
  272.         sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
  273.         sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
  274.         initname = 1;
  275.     }
  276.     strcpy(buf, fs->fs_mntops);
  277.     for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
  278.         if (cp = index(opt, '='))
  279.             *cp++ = '\0';
  280.         if (type == USRQUOTA && strcmp(opt, usrname) == 0)
  281.             break;
  282.         if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
  283.             break;
  284.     }
  285.     if (!opt)
  286.         return (0);
  287.     if (cp) {
  288.         *qfnamep = cp;
  289.         return (1);
  290.     }
  291.     (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
  292.     *qfnamep = buf;
  293.     return (1);
  294. }
  295.  
  296. /*
  297.  * Routines to manage the file usage table.
  298.  *
  299.  * Lookup an id of a specific type.
  300.  */
  301. struct fileusage *
  302. lookup(id, type)
  303.     u_long id;
  304.     int type;
  305. {
  306.     register struct fileusage *fup;
  307.  
  308.     for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
  309.         if (fup->fu_id == id)
  310.             return (fup);
  311.     return ((struct fileusage *)0);
  312. }
  313.  
  314. /*
  315.  * Add a new file usage id if it does not already exist.
  316.  */
  317. struct fileusage *
  318. addid(id, type, name)
  319.     u_long id;
  320.     int type;
  321.     char *name;
  322. {
  323.     struct fileusage *fup, **fhp;
  324.     int len;
  325.     extern char *calloc();
  326.  
  327.     if (fup = lookup(id, type))
  328.         return (fup);
  329.     if (name)
  330.         len = strlen(name);
  331.     else
  332.         len = 10;
  333.     if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
  334.         fprintf(stderr, "out of memory for fileusage structures\n");
  335.         exit(1);
  336.     }
  337.     fhp = &fuhead[type][id & (FUHASH - 1)];
  338.     fup->fu_next = *fhp;
  339.     *fhp = fup;
  340.     fup->fu_id = id;
  341.     if (id > highid[type])
  342.         highid[type] = id;
  343.     if (name) {
  344.         bcopy(name, fup->fu_name, len + 1);
  345.     } else {
  346.         sprintf(fup->fu_name, "%u", id);
  347.     }
  348.     return (fup);
  349. }
  350.  
  351. /*
  352.  * Calculate the grace period and return a printable string for it.
  353.  */
  354. char *
  355. timeprt(seconds)
  356.     time_t seconds;
  357. {
  358.     time_t hours, minutes;
  359.     static char buf[20];
  360.     static time_t now;
  361.  
  362.     if (now == 0)
  363.         time(&now);
  364.     if (now > seconds)
  365.         return ("none");
  366.     seconds -= now;
  367.     minutes = (seconds + 30) / 60;
  368.     hours = (minutes + 30) / 60;
  369.     if (hours >= 36) {
  370.         sprintf(buf, "%ddays", (hours + 12) / 24);
  371.         return (buf);
  372.     }
  373.     if (minutes >= 60) {
  374.         sprintf(buf, "%2d:%d", minutes / 60, minutes % 60);
  375.         return (buf);
  376.     }
  377.     sprintf(buf, "%2d", minutes);
  378.     return (buf);
  379. }
  380.