121520Smckusick /* 241407Smckusick * Copyright (c) 1980, 1990 Regents of the University of California. 334372Sbostic * All rights reserved. 434372Sbostic * 541407Smckusick * This code is derived from software contributed to Berkeley by 641407Smckusick * Robert Elz at The University of Melbourne. 741407Smckusick * 834372Sbostic * Redistribution and use in source and binary forms are permitted 934911Sbostic * provided that the above copyright notice and this paragraph are 1034911Sbostic * duplicated in all such forms and that any documentation, 1134911Sbostic * advertising materials, and other materials related to such 1234911Sbostic * distribution and use acknowledge that the software was developed 1334911Sbostic * by the University of California, Berkeley. The name of the 1434911Sbostic * University may not be used to endorse or promote products derived 1534911Sbostic * from this software without specific prior written permission. 1634911Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734911Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834911Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1921520Smckusick */ 2021520Smckusick 2112710Smckusick #ifndef lint 2221520Smckusick char copyright[] = 2341407Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 2421520Smckusick All rights reserved.\n"; 2534372Sbostic #endif /* not lint */ 2612710Smckusick 2721520Smckusick #ifndef lint 28*41440Smckusick static char sccsid[] = "@(#)quota.c 5.10 (Berkeley) 05/06/90"; 2934372Sbostic #endif /* not lint */ 3021520Smckusick 3112710Smckusick /* 3212710Smckusick * Disk quota reporting program. 3312710Smckusick */ 3437078Sbostic #include <sys/param.h> 3537078Sbostic #include <sys/file.h> 3637078Sbostic #include <sys/stat.h> 3738515Sbostic #include <ufs/quota.h> 3812710Smckusick #include <stdio.h> 3912710Smckusick #include <fstab.h> 4012710Smckusick #include <ctype.h> 4112710Smckusick #include <pwd.h> 4241407Smckusick #include <grp.h> 4321392Smckusick #include <errno.h> 4412710Smckusick 4541407Smckusick struct quotause { 4641407Smckusick struct quotause *next; 4741407Smckusick long flags; 4841407Smckusick struct dqblk dqblk; 4941407Smckusick char fsname[MAXPATHLEN + 1]; 5041407Smckusick } *getprivs(); 5141407Smckusick #define FOUND 0x01 5212710Smckusick 5312710Smckusick int qflag; 5412710Smckusick int vflag; 5512710Smckusick 5612710Smckusick main(argc, argv) 5712710Smckusick char *argv[]; 5812710Smckusick { 5941407Smckusick int ngroups, gidset[NGROUPS]; 6041407Smckusick int i, gflag = 0, uflag = 0; 6141407Smckusick char ch; 6241407Smckusick extern char *optarg; 6341407Smckusick extern int optind, errno; 6412710Smckusick 6541407Smckusick if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) { 6621392Smckusick fprintf(stderr, "There are no quotas on this system\n"); 6721392Smckusick exit(0); 6821392Smckusick } 6941407Smckusick while ((ch = getopt(argc, argv, "ugvq")) != EOF) { 7041407Smckusick switch(ch) { 7141407Smckusick case 'g': 7241407Smckusick gflag++; 7312710Smckusick break; 7441407Smckusick case 'u': 7541407Smckusick uflag++; 7641407Smckusick break; 7741407Smckusick case 'v': 7841407Smckusick vflag++; 7941407Smckusick break; 8041407Smckusick case 'q': 8141407Smckusick qflag++; 8241407Smckusick break; 8341407Smckusick default: 8441407Smckusick usage(); 8541407Smckusick } 8612710Smckusick } 8741407Smckusick argc -= optind; 8841407Smckusick argv += optind; 8941407Smckusick if (!uflag && !gflag) 9041407Smckusick uflag++; 9112710Smckusick if (argc == 0) { 9241407Smckusick if (uflag) 9341407Smckusick showuid(getuid()); 9441407Smckusick if (gflag) { 9541407Smckusick ngroups = getgroups(NGROUPS, gidset); 9641407Smckusick if (ngroups < 0) { 9741407Smckusick perror("quota: getgroups"); 9841407Smckusick exit(1); 9941407Smckusick } 10041407Smckusick for (i = 1; i < ngroups; i++) 10141407Smckusick showgid(gidset[i]); 10241407Smckusick } 10312710Smckusick exit(0); 10412710Smckusick } 10541407Smckusick if (uflag && gflag) 10641407Smckusick usage(); 10741407Smckusick if (uflag) { 10841407Smckusick for (; argc > 0; argc--, argv++) { 10941407Smckusick if (alldigits(*argv)) 11041407Smckusick showuid(atoi(*argv)); 11141407Smckusick else 11241407Smckusick showusrname(*argv); 11341407Smckusick } 11441407Smckusick exit(0); 11512710Smckusick } 11641407Smckusick if (gflag) { 11741407Smckusick for (; argc > 0; argc--, argv++) { 11841407Smckusick if (alldigits(*argv)) 11941407Smckusick showgid(atoi(*argv)); 12041407Smckusick else 12141407Smckusick showgrpname(*argv); 12241407Smckusick } 12341407Smckusick exit(0); 12441407Smckusick } 12512710Smckusick } 12612710Smckusick 12741407Smckusick usage() 12841407Smckusick { 12941407Smckusick 13041407Smckusick fprintf(stderr, "%s\n%s\n%s\n", 13141407Smckusick "Usage: quota [-guqv]", 13241407Smckusick "\tquota [-qv] -u username ...", 13341407Smckusick "\tquota [-qv] -g groupname ..."); 13441407Smckusick exit(1); 13541407Smckusick } 13641407Smckusick 13741407Smckusick /* 13841407Smckusick * Print out quotas for a specified user identifier. 13941407Smckusick */ 14012710Smckusick showuid(uid) 14141407Smckusick u_long uid; 14212710Smckusick { 14312710Smckusick struct passwd *pwd = getpwuid(uid); 14441407Smckusick u_long myuid; 14541407Smckusick char *name; 14612710Smckusick 14712710Smckusick if (pwd == NULL) 14841407Smckusick name = "(no account)"; 14912710Smckusick else 15041407Smckusick name = pwd->pw_name; 15141407Smckusick myuid = getuid(); 15241407Smckusick if (uid != myuid && myuid != 0) { 15341407Smckusick printf("quota: %s (uid %d): permission denied\n", name, uid); 15441407Smckusick return; 15541407Smckusick } 15641407Smckusick showquotas(USRQUOTA, uid, name); 15712710Smckusick } 15812710Smckusick 15941407Smckusick /* 16041407Smckusick * Print out quotas for a specifed user name. 16141407Smckusick */ 16241407Smckusick showusrname(name) 16312710Smckusick char *name; 16412710Smckusick { 16512710Smckusick struct passwd *pwd = getpwnam(name); 16641407Smckusick u_long myuid; 16712710Smckusick 16812710Smckusick if (pwd == NULL) { 16912710Smckusick fprintf(stderr, "quota: %s: unknown user\n", name); 17012710Smckusick return; 17112710Smckusick } 17241407Smckusick myuid = getuid(); 17341407Smckusick if (pwd->pw_uid != myuid && myuid != 0) { 17441407Smckusick fprintf(stderr, "quota: %s (uid %d): permission denied\n", 17541407Smckusick name, pwd->pw_uid); 17641407Smckusick return; 17741407Smckusick } 17841407Smckusick showquotas(USRQUOTA, pwd->pw_uid, name); 17912710Smckusick } 18012710Smckusick 18141407Smckusick /* 18241407Smckusick * Print out quotas for a specified group identifier. 18341407Smckusick */ 18441407Smckusick showgid(gid) 18541407Smckusick u_long gid; 18641407Smckusick { 18741407Smckusick struct group *grp = getgrgid(gid); 18841407Smckusick int ngroups, gidset[NGROUPS]; 18941407Smckusick register int i; 19012710Smckusick char *name; 19141407Smckusick 19241407Smckusick if (grp == NULL) 19341407Smckusick name = "(no entry)"; 19441407Smckusick else 19541407Smckusick name = grp->gr_name; 19641407Smckusick ngroups = getgroups(NGROUPS, gidset); 19741407Smckusick if (ngroups < 0) { 19841407Smckusick perror("quota: getgroups"); 19941407Smckusick return; 20041407Smckusick } 20141407Smckusick for (i = 1; i < ngroups; i++) 20241407Smckusick if (gid == gidset[i]) 20341407Smckusick break; 20441407Smckusick if (i >= ngroups && getuid() != 0) { 20541407Smckusick fprintf(stderr, "quota: %s (gid %d): permission denied\n", 20641407Smckusick name, gid); 20741407Smckusick return; 20841407Smckusick } 20941407Smckusick showquotas(GRPQUOTA, gid, name); 21041407Smckusick } 21141407Smckusick 21241407Smckusick /* 21341407Smckusick * Print out quotas for a specifed group name. 21441407Smckusick */ 21541407Smckusick showgrpname(name) 21641407Smckusick char *name; 21712710Smckusick { 21841407Smckusick struct group *grp = getgrnam(name); 21941407Smckusick int ngroups, gidset[NGROUPS]; 22041407Smckusick register int i; 22112710Smckusick 22241407Smckusick if (grp == NULL) { 22341407Smckusick fprintf(stderr, "quota: %s: unknown group\n", name); 22412710Smckusick return; 22512710Smckusick } 22641407Smckusick ngroups = getgroups(NGROUPS, gidset); 22741407Smckusick if (ngroups < 0) { 22841407Smckusick perror("quota: getgroups"); 22941407Smckusick return; 23041407Smckusick } 23141407Smckusick for (i = 1; i < ngroups; i++) 23241407Smckusick if (grp->gr_gid == gidset[i]) 23341407Smckusick break; 23441407Smckusick if (i >= ngroups && getuid() != 0) { 23541407Smckusick fprintf(stderr, "quota: %s (gid %d): permission denied\n", 23641407Smckusick name, grp->gr_gid); 23741407Smckusick return; 23841407Smckusick } 23941407Smckusick showquotas(GRPQUOTA, grp->gr_gid, name); 24041407Smckusick } 24141407Smckusick 24241407Smckusick showquotas(type, id, name) 24341407Smckusick int type; 24441407Smckusick u_long id; 24541407Smckusick char *name; 24641407Smckusick { 24741407Smckusick register struct quotause *qup; 24841407Smckusick struct quotause *quplist, *getprivs(); 24941407Smckusick char *msgi, *msgb, *timeprt(); 25041407Smckusick int myuid, fd, lines = 0; 25141407Smckusick static int first; 25241407Smckusick static time_t now; 25341407Smckusick 25441407Smckusick if (now == 0) 25541407Smckusick time(&now); 25641407Smckusick quplist = getprivs(id, type); 25741407Smckusick for (qup = quplist; qup; qup = qup->next) { 25841407Smckusick if (!vflag && 25941407Smckusick qup->dqblk.dqb_isoftlimit == 0 && 26041407Smckusick qup->dqblk.dqb_ihardlimit == 0 && 26141407Smckusick qup->dqblk.dqb_bsoftlimit == 0 && 26241407Smckusick qup->dqblk.dqb_bhardlimit == 0) 26341407Smckusick continue; 26441407Smckusick msgi = (char *)0; 26541407Smckusick if (qup->dqblk.dqb_ihardlimit && 26641407Smckusick qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) 26741407Smckusick msgi = "File limit reached on"; 26841407Smckusick else if (qup->dqblk.dqb_isoftlimit && 26941407Smckusick qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) 27041407Smckusick if (qup->dqblk.dqb_itime > now) 27141407Smckusick msgi = "In file grace period on"; 27241407Smckusick else 27341407Smckusick msgi = "Over file quota on"; 27441407Smckusick msgb = (char *)0; 27541407Smckusick if (qup->dqblk.dqb_bhardlimit && 27641407Smckusick qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) 27741407Smckusick msgb = "Block limit reached on"; 27841407Smckusick else if (qup->dqblk.dqb_bsoftlimit && 27941407Smckusick qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) 28041407Smckusick if (qup->dqblk.dqb_btime > now) 28141407Smckusick msgb = "In block grace period on"; 28241407Smckusick else 28341407Smckusick msgb = "Over block quota on"; 28441407Smckusick if (qflag) { 28541407Smckusick if ((msgi != (char *)0 || msgb != (char *)0) && 28641407Smckusick lines++ == 0) 28741407Smckusick heading(type, id, name, ""); 28841407Smckusick if (msgi != (char *)0) 28941407Smckusick printf("\t%s %s\n", msgi, qup->fsname); 29041407Smckusick if (msgb != (char *)0) 29141407Smckusick printf("\t%s %s\n", msgb, qup->fsname); 29241407Smckusick continue; 29341407Smckusick } 29441407Smckusick if (vflag || 29541407Smckusick qup->dqblk.dqb_curblocks || 29641407Smckusick qup->dqblk.dqb_curinodes) { 29741407Smckusick if (lines++ == 0) 29841407Smckusick heading(type, id, name, ""); 29941407Smckusick printf("%15s%8d%c%7d%8d%8s" 30041407Smckusick , qup->fsname 30141407Smckusick , dbtob(qup->dqblk.dqb_curblocks) / 1024 30241407Smckusick , (msgb == (char *)0) ? ' ' : '*' 30341407Smckusick , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024 30441407Smckusick , dbtob(qup->dqblk.dqb_bhardlimit) / 1024 30541407Smckusick , (msgb == (char *)0) ? "" 30641407Smckusick : timeprt(qup->dqblk.dqb_btime)); 30741407Smckusick printf("%8d%c%7d%8d%8s\n" 30841407Smckusick , qup->dqblk.dqb_curinodes 30941407Smckusick , (msgi == (char *)0) ? ' ' : '*' 31041407Smckusick , qup->dqblk.dqb_isoftlimit 31141407Smckusick , qup->dqblk.dqb_ihardlimit 31241407Smckusick , (msgi == (char *)0) ? "" 31341407Smckusick : timeprt(qup->dqblk.dqb_itime) 31441407Smckusick ); 31541407Smckusick continue; 31641407Smckusick } 31741407Smckusick } 31841407Smckusick if (!qflag && lines == 0) 31941407Smckusick heading(type, id, name, "none"); 32041407Smckusick } 32141407Smckusick 32241407Smckusick heading(type, id, name, tag) 32341407Smckusick int type; 32441407Smckusick u_long id; 32541407Smckusick char *name, *tag; 32641407Smckusick { 32741407Smckusick 32841407Smckusick printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type], 32941407Smckusick name, *qfextension[type], id, tag); 33041407Smckusick if (!qflag && tag[0] == '\0') { 33141407Smckusick printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 33241407Smckusick , "Filesystem" 33341407Smckusick , "blocks" 33441407Smckusick , "quota" 33541407Smckusick , "limit" 33641407Smckusick , "grace" 33741407Smckusick , "files" 33841407Smckusick , "quota" 33941407Smckusick , "limit" 34041407Smckusick , "grace" 34141407Smckusick ); 34241407Smckusick } 34341407Smckusick } 34441407Smckusick 34541407Smckusick /* 34641407Smckusick * Calculate the grace period and return a printable string for it. 34741407Smckusick */ 34841407Smckusick char * 34941407Smckusick timeprt(seconds) 35041407Smckusick time_t seconds; 35141407Smckusick { 35241407Smckusick time_t hours, minutes; 35341407Smckusick static char buf[20]; 35441407Smckusick static time_t now; 35541407Smckusick 35641407Smckusick if (now == 0) 35741407Smckusick time(&now); 35841407Smckusick if (now > seconds) 35941407Smckusick return ("none"); 36041407Smckusick seconds -= now; 36141407Smckusick minutes = (seconds + 30) / 60; 36241407Smckusick hours = (minutes + 30) / 60; 36341407Smckusick if (hours >= 36) { 36441407Smckusick sprintf(buf, "%ddays", (hours + 12) / 24); 36541407Smckusick return (buf); 36641407Smckusick } 36741407Smckusick if (minutes >= 60) { 36841407Smckusick sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); 36941407Smckusick return (buf); 37041407Smckusick } 37141407Smckusick sprintf(buf, "%2d", minutes); 37241407Smckusick return (buf); 37341407Smckusick } 37441407Smckusick 37541407Smckusick /* 37641407Smckusick * Collect the requested quota information. 37741407Smckusick */ 37841407Smckusick struct quotause * 37941407Smckusick getprivs(id, quotatype) 38041407Smckusick register long id; 38141407Smckusick int quotatype; 38241407Smckusick { 38341407Smckusick register struct fstab *fs; 38441407Smckusick register struct quotause *qup, *quptail; 38541407Smckusick struct quotause *quphead; 386*41440Smckusick char *qfpathname; 38741407Smckusick int qcmd, fd; 38841407Smckusick 38941407Smckusick setfsent(); 39041407Smckusick quphead = (struct quotause *)0; 39141407Smckusick qcmd = QCMD(Q_GETQUOTA, quotatype); 39212710Smckusick while (fs = getfsent()) { 393*41440Smckusick if (strcmp(fs->fs_vfstype, "ufs")) 39412710Smckusick continue; 395*41440Smckusick if (!hasquota(fs, quotatype, &qfpathname)) 39612710Smckusick continue; 39741407Smckusick if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { 39841407Smckusick fprintf(stderr, "quota: out of memory\n"); 39941407Smckusick exit(2); 40041407Smckusick } 401*41440Smckusick if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 402*41440Smckusick if ((fd = open(qfpathname, O_RDONLY)) < 0) { 403*41440Smckusick perror(qfpathname); 404*41440Smckusick free(qup); 405*41440Smckusick continue; 406*41440Smckusick } 40741407Smckusick lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); 40841407Smckusick switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 40924684Sserge case 0: /* EOF */ 41024684Sserge /* 41124684Sserge * Convert implicit 0 quota (EOF) 41241407Smckusick * into an explicit one (zero'ed dqblk) 41324684Sserge */ 41441407Smckusick bzero((caddr_t)&qup->dqblk, 41541407Smckusick sizeof(struct dqblk)); 41624684Sserge break; 41724684Sserge 41841407Smckusick case sizeof(struct dqblk): /* OK */ 41924684Sserge break; 42024684Sserge 42124684Sserge default: /* ERROR */ 42241407Smckusick fprintf(stderr, "quota: read error"); 423*41440Smckusick perror(qfpathname); 42441407Smckusick close(fd); 42541407Smckusick free(qup); 42612710Smckusick continue; 42712710Smckusick } 428*41440Smckusick close(fd); 42912710Smckusick } 43041407Smckusick strcpy(qup->fsname, fs->fs_file); 43141407Smckusick if (quphead == NULL) 43241407Smckusick quphead = qup; 43312710Smckusick else 43441407Smckusick quptail->next = qup; 43541407Smckusick quptail = qup; 43641407Smckusick qup->next = 0; 43712710Smckusick } 43841407Smckusick endfsent(); 43941407Smckusick return (quphead); 44012710Smckusick } 44112710Smckusick 44241407Smckusick /* 44341407Smckusick * Check to see if a particular quota is to be enabled. 44441407Smckusick */ 445*41440Smckusick hasquota(fs, type, qfnamep) 446*41440Smckusick register struct fstab *fs; 44741407Smckusick int type; 448*41440Smckusick char **qfnamep; 44912710Smckusick { 45041407Smckusick register char *opt; 451*41440Smckusick char *cp, *index(), *strtok(); 45241407Smckusick static char initname, usrname[100], grpname[100]; 453*41440Smckusick static char buf[BUFSIZ]; 45412710Smckusick 45541407Smckusick if (!initname) { 45641407Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 45741407Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 45841407Smckusick initname = 1; 45912710Smckusick } 460*41440Smckusick strcpy(buf, fs->fs_mntops); 46141407Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 462*41440Smckusick if (cp = index(opt, '=')) 463*41440Smckusick *cp++ = '\0'; 46441407Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 465*41440Smckusick break; 46641407Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 467*41440Smckusick break; 46812710Smckusick } 469*41440Smckusick if (!opt) 470*41440Smckusick return (0); 471*41440Smckusick if (cp) { 472*41440Smckusick *qfnamep = cp; 473*41440Smckusick return (1); 474*41440Smckusick } 475*41440Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 476*41440Smckusick *qfnamep = buf; 477*41440Smckusick return (1); 47812710Smckusick } 47912710Smckusick 48012710Smckusick alldigits(s) 48112710Smckusick register char *s; 48212710Smckusick { 48312710Smckusick register c; 48412710Smckusick 48512710Smckusick c = *s++; 48612710Smckusick do { 48712710Smckusick if (!isdigit(c)) 48812710Smckusick return (0); 48912710Smckusick } while (c = *s++); 49012710Smckusick return (1); 49112710Smckusick } 492