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 * 8*42759Sbostic * %sccs.include.redist.c% 921520Smckusick */ 1021520Smckusick 1112710Smckusick #ifndef lint 1221520Smckusick char copyright[] = 1341407Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 1421520Smckusick All rights reserved.\n"; 1534372Sbostic #endif /* not lint */ 1612710Smckusick 1721520Smckusick #ifndef lint 18*42759Sbostic static char sccsid[] = "@(#)quota.c 5.11 (Berkeley) 06/01/90"; 1934372Sbostic #endif /* not lint */ 2021520Smckusick 2112710Smckusick /* 2212710Smckusick * Disk quota reporting program. 2312710Smckusick */ 2437078Sbostic #include <sys/param.h> 2537078Sbostic #include <sys/file.h> 2637078Sbostic #include <sys/stat.h> 2738515Sbostic #include <ufs/quota.h> 2812710Smckusick #include <stdio.h> 2912710Smckusick #include <fstab.h> 3012710Smckusick #include <ctype.h> 3112710Smckusick #include <pwd.h> 3241407Smckusick #include <grp.h> 3321392Smckusick #include <errno.h> 3412710Smckusick 3541407Smckusick struct quotause { 3641407Smckusick struct quotause *next; 3741407Smckusick long flags; 3841407Smckusick struct dqblk dqblk; 3941407Smckusick char fsname[MAXPATHLEN + 1]; 4041407Smckusick } *getprivs(); 4141407Smckusick #define FOUND 0x01 4212710Smckusick 4312710Smckusick int qflag; 4412710Smckusick int vflag; 4512710Smckusick 4612710Smckusick main(argc, argv) 4712710Smckusick char *argv[]; 4812710Smckusick { 4941407Smckusick int ngroups, gidset[NGROUPS]; 5041407Smckusick int i, gflag = 0, uflag = 0; 5141407Smckusick char ch; 5241407Smckusick extern char *optarg; 5341407Smckusick extern int optind, errno; 5412710Smckusick 5541407Smckusick if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) { 5621392Smckusick fprintf(stderr, "There are no quotas on this system\n"); 5721392Smckusick exit(0); 5821392Smckusick } 5941407Smckusick while ((ch = getopt(argc, argv, "ugvq")) != EOF) { 6041407Smckusick switch(ch) { 6141407Smckusick case 'g': 6241407Smckusick gflag++; 6312710Smckusick break; 6441407Smckusick case 'u': 6541407Smckusick uflag++; 6641407Smckusick break; 6741407Smckusick case 'v': 6841407Smckusick vflag++; 6941407Smckusick break; 7041407Smckusick case 'q': 7141407Smckusick qflag++; 7241407Smckusick break; 7341407Smckusick default: 7441407Smckusick usage(); 7541407Smckusick } 7612710Smckusick } 7741407Smckusick argc -= optind; 7841407Smckusick argv += optind; 7941407Smckusick if (!uflag && !gflag) 8041407Smckusick uflag++; 8112710Smckusick if (argc == 0) { 8241407Smckusick if (uflag) 8341407Smckusick showuid(getuid()); 8441407Smckusick if (gflag) { 8541407Smckusick ngroups = getgroups(NGROUPS, gidset); 8641407Smckusick if (ngroups < 0) { 8741407Smckusick perror("quota: getgroups"); 8841407Smckusick exit(1); 8941407Smckusick } 9041407Smckusick for (i = 1; i < ngroups; i++) 9141407Smckusick showgid(gidset[i]); 9241407Smckusick } 9312710Smckusick exit(0); 9412710Smckusick } 9541407Smckusick if (uflag && gflag) 9641407Smckusick usage(); 9741407Smckusick if (uflag) { 9841407Smckusick for (; argc > 0; argc--, argv++) { 9941407Smckusick if (alldigits(*argv)) 10041407Smckusick showuid(atoi(*argv)); 10141407Smckusick else 10241407Smckusick showusrname(*argv); 10341407Smckusick } 10441407Smckusick exit(0); 10512710Smckusick } 10641407Smckusick if (gflag) { 10741407Smckusick for (; argc > 0; argc--, argv++) { 10841407Smckusick if (alldigits(*argv)) 10941407Smckusick showgid(atoi(*argv)); 11041407Smckusick else 11141407Smckusick showgrpname(*argv); 11241407Smckusick } 11341407Smckusick exit(0); 11441407Smckusick } 11512710Smckusick } 11612710Smckusick 11741407Smckusick usage() 11841407Smckusick { 11941407Smckusick 12041407Smckusick fprintf(stderr, "%s\n%s\n%s\n", 12141407Smckusick "Usage: quota [-guqv]", 12241407Smckusick "\tquota [-qv] -u username ...", 12341407Smckusick "\tquota [-qv] -g groupname ..."); 12441407Smckusick exit(1); 12541407Smckusick } 12641407Smckusick 12741407Smckusick /* 12841407Smckusick * Print out quotas for a specified user identifier. 12941407Smckusick */ 13012710Smckusick showuid(uid) 13141407Smckusick u_long uid; 13212710Smckusick { 13312710Smckusick struct passwd *pwd = getpwuid(uid); 13441407Smckusick u_long myuid; 13541407Smckusick char *name; 13612710Smckusick 13712710Smckusick if (pwd == NULL) 13841407Smckusick name = "(no account)"; 13912710Smckusick else 14041407Smckusick name = pwd->pw_name; 14141407Smckusick myuid = getuid(); 14241407Smckusick if (uid != myuid && myuid != 0) { 14341407Smckusick printf("quota: %s (uid %d): permission denied\n", name, uid); 14441407Smckusick return; 14541407Smckusick } 14641407Smckusick showquotas(USRQUOTA, uid, name); 14712710Smckusick } 14812710Smckusick 14941407Smckusick /* 15041407Smckusick * Print out quotas for a specifed user name. 15141407Smckusick */ 15241407Smckusick showusrname(name) 15312710Smckusick char *name; 15412710Smckusick { 15512710Smckusick struct passwd *pwd = getpwnam(name); 15641407Smckusick u_long myuid; 15712710Smckusick 15812710Smckusick if (pwd == NULL) { 15912710Smckusick fprintf(stderr, "quota: %s: unknown user\n", name); 16012710Smckusick return; 16112710Smckusick } 16241407Smckusick myuid = getuid(); 16341407Smckusick if (pwd->pw_uid != myuid && myuid != 0) { 16441407Smckusick fprintf(stderr, "quota: %s (uid %d): permission denied\n", 16541407Smckusick name, pwd->pw_uid); 16641407Smckusick return; 16741407Smckusick } 16841407Smckusick showquotas(USRQUOTA, pwd->pw_uid, name); 16912710Smckusick } 17012710Smckusick 17141407Smckusick /* 17241407Smckusick * Print out quotas for a specified group identifier. 17341407Smckusick */ 17441407Smckusick showgid(gid) 17541407Smckusick u_long gid; 17641407Smckusick { 17741407Smckusick struct group *grp = getgrgid(gid); 17841407Smckusick int ngroups, gidset[NGROUPS]; 17941407Smckusick register int i; 18012710Smckusick char *name; 18141407Smckusick 18241407Smckusick if (grp == NULL) 18341407Smckusick name = "(no entry)"; 18441407Smckusick else 18541407Smckusick name = grp->gr_name; 18641407Smckusick ngroups = getgroups(NGROUPS, gidset); 18741407Smckusick if (ngroups < 0) { 18841407Smckusick perror("quota: getgroups"); 18941407Smckusick return; 19041407Smckusick } 19141407Smckusick for (i = 1; i < ngroups; i++) 19241407Smckusick if (gid == gidset[i]) 19341407Smckusick break; 19441407Smckusick if (i >= ngroups && getuid() != 0) { 19541407Smckusick fprintf(stderr, "quota: %s (gid %d): permission denied\n", 19641407Smckusick name, gid); 19741407Smckusick return; 19841407Smckusick } 19941407Smckusick showquotas(GRPQUOTA, gid, name); 20041407Smckusick } 20141407Smckusick 20241407Smckusick /* 20341407Smckusick * Print out quotas for a specifed group name. 20441407Smckusick */ 20541407Smckusick showgrpname(name) 20641407Smckusick char *name; 20712710Smckusick { 20841407Smckusick struct group *grp = getgrnam(name); 20941407Smckusick int ngroups, gidset[NGROUPS]; 21041407Smckusick register int i; 21112710Smckusick 21241407Smckusick if (grp == NULL) { 21341407Smckusick fprintf(stderr, "quota: %s: unknown group\n", name); 21412710Smckusick return; 21512710Smckusick } 21641407Smckusick ngroups = getgroups(NGROUPS, gidset); 21741407Smckusick if (ngroups < 0) { 21841407Smckusick perror("quota: getgroups"); 21941407Smckusick return; 22041407Smckusick } 22141407Smckusick for (i = 1; i < ngroups; i++) 22241407Smckusick if (grp->gr_gid == gidset[i]) 22341407Smckusick break; 22441407Smckusick if (i >= ngroups && getuid() != 0) { 22541407Smckusick fprintf(stderr, "quota: %s (gid %d): permission denied\n", 22641407Smckusick name, grp->gr_gid); 22741407Smckusick return; 22841407Smckusick } 22941407Smckusick showquotas(GRPQUOTA, grp->gr_gid, name); 23041407Smckusick } 23141407Smckusick 23241407Smckusick showquotas(type, id, name) 23341407Smckusick int type; 23441407Smckusick u_long id; 23541407Smckusick char *name; 23641407Smckusick { 23741407Smckusick register struct quotause *qup; 23841407Smckusick struct quotause *quplist, *getprivs(); 23941407Smckusick char *msgi, *msgb, *timeprt(); 24041407Smckusick int myuid, fd, lines = 0; 24141407Smckusick static int first; 24241407Smckusick static time_t now; 24341407Smckusick 24441407Smckusick if (now == 0) 24541407Smckusick time(&now); 24641407Smckusick quplist = getprivs(id, type); 24741407Smckusick for (qup = quplist; qup; qup = qup->next) { 24841407Smckusick if (!vflag && 24941407Smckusick qup->dqblk.dqb_isoftlimit == 0 && 25041407Smckusick qup->dqblk.dqb_ihardlimit == 0 && 25141407Smckusick qup->dqblk.dqb_bsoftlimit == 0 && 25241407Smckusick qup->dqblk.dqb_bhardlimit == 0) 25341407Smckusick continue; 25441407Smckusick msgi = (char *)0; 25541407Smckusick if (qup->dqblk.dqb_ihardlimit && 25641407Smckusick qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) 25741407Smckusick msgi = "File limit reached on"; 25841407Smckusick else if (qup->dqblk.dqb_isoftlimit && 25941407Smckusick qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) 26041407Smckusick if (qup->dqblk.dqb_itime > now) 26141407Smckusick msgi = "In file grace period on"; 26241407Smckusick else 26341407Smckusick msgi = "Over file quota on"; 26441407Smckusick msgb = (char *)0; 26541407Smckusick if (qup->dqblk.dqb_bhardlimit && 26641407Smckusick qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) 26741407Smckusick msgb = "Block limit reached on"; 26841407Smckusick else if (qup->dqblk.dqb_bsoftlimit && 26941407Smckusick qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) 27041407Smckusick if (qup->dqblk.dqb_btime > now) 27141407Smckusick msgb = "In block grace period on"; 27241407Smckusick else 27341407Smckusick msgb = "Over block quota on"; 27441407Smckusick if (qflag) { 27541407Smckusick if ((msgi != (char *)0 || msgb != (char *)0) && 27641407Smckusick lines++ == 0) 27741407Smckusick heading(type, id, name, ""); 27841407Smckusick if (msgi != (char *)0) 27941407Smckusick printf("\t%s %s\n", msgi, qup->fsname); 28041407Smckusick if (msgb != (char *)0) 28141407Smckusick printf("\t%s %s\n", msgb, qup->fsname); 28241407Smckusick continue; 28341407Smckusick } 28441407Smckusick if (vflag || 28541407Smckusick qup->dqblk.dqb_curblocks || 28641407Smckusick qup->dqblk.dqb_curinodes) { 28741407Smckusick if (lines++ == 0) 28841407Smckusick heading(type, id, name, ""); 28941407Smckusick printf("%15s%8d%c%7d%8d%8s" 29041407Smckusick , qup->fsname 29141407Smckusick , dbtob(qup->dqblk.dqb_curblocks) / 1024 29241407Smckusick , (msgb == (char *)0) ? ' ' : '*' 29341407Smckusick , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024 29441407Smckusick , dbtob(qup->dqblk.dqb_bhardlimit) / 1024 29541407Smckusick , (msgb == (char *)0) ? "" 29641407Smckusick : timeprt(qup->dqblk.dqb_btime)); 29741407Smckusick printf("%8d%c%7d%8d%8s\n" 29841407Smckusick , qup->dqblk.dqb_curinodes 29941407Smckusick , (msgi == (char *)0) ? ' ' : '*' 30041407Smckusick , qup->dqblk.dqb_isoftlimit 30141407Smckusick , qup->dqblk.dqb_ihardlimit 30241407Smckusick , (msgi == (char *)0) ? "" 30341407Smckusick : timeprt(qup->dqblk.dqb_itime) 30441407Smckusick ); 30541407Smckusick continue; 30641407Smckusick } 30741407Smckusick } 30841407Smckusick if (!qflag && lines == 0) 30941407Smckusick heading(type, id, name, "none"); 31041407Smckusick } 31141407Smckusick 31241407Smckusick heading(type, id, name, tag) 31341407Smckusick int type; 31441407Smckusick u_long id; 31541407Smckusick char *name, *tag; 31641407Smckusick { 31741407Smckusick 31841407Smckusick printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type], 31941407Smckusick name, *qfextension[type], id, tag); 32041407Smckusick if (!qflag && tag[0] == '\0') { 32141407Smckusick printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 32241407Smckusick , "Filesystem" 32341407Smckusick , "blocks" 32441407Smckusick , "quota" 32541407Smckusick , "limit" 32641407Smckusick , "grace" 32741407Smckusick , "files" 32841407Smckusick , "quota" 32941407Smckusick , "limit" 33041407Smckusick , "grace" 33141407Smckusick ); 33241407Smckusick } 33341407Smckusick } 33441407Smckusick 33541407Smckusick /* 33641407Smckusick * Calculate the grace period and return a printable string for it. 33741407Smckusick */ 33841407Smckusick char * 33941407Smckusick timeprt(seconds) 34041407Smckusick time_t seconds; 34141407Smckusick { 34241407Smckusick time_t hours, minutes; 34341407Smckusick static char buf[20]; 34441407Smckusick static time_t now; 34541407Smckusick 34641407Smckusick if (now == 0) 34741407Smckusick time(&now); 34841407Smckusick if (now > seconds) 34941407Smckusick return ("none"); 35041407Smckusick seconds -= now; 35141407Smckusick minutes = (seconds + 30) / 60; 35241407Smckusick hours = (minutes + 30) / 60; 35341407Smckusick if (hours >= 36) { 35441407Smckusick sprintf(buf, "%ddays", (hours + 12) / 24); 35541407Smckusick return (buf); 35641407Smckusick } 35741407Smckusick if (minutes >= 60) { 35841407Smckusick sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); 35941407Smckusick return (buf); 36041407Smckusick } 36141407Smckusick sprintf(buf, "%2d", minutes); 36241407Smckusick return (buf); 36341407Smckusick } 36441407Smckusick 36541407Smckusick /* 36641407Smckusick * Collect the requested quota information. 36741407Smckusick */ 36841407Smckusick struct quotause * 36941407Smckusick getprivs(id, quotatype) 37041407Smckusick register long id; 37141407Smckusick int quotatype; 37241407Smckusick { 37341407Smckusick register struct fstab *fs; 37441407Smckusick register struct quotause *qup, *quptail; 37541407Smckusick struct quotause *quphead; 37641440Smckusick char *qfpathname; 37741407Smckusick int qcmd, fd; 37841407Smckusick 37941407Smckusick setfsent(); 38041407Smckusick quphead = (struct quotause *)0; 38141407Smckusick qcmd = QCMD(Q_GETQUOTA, quotatype); 38212710Smckusick while (fs = getfsent()) { 38341440Smckusick if (strcmp(fs->fs_vfstype, "ufs")) 38412710Smckusick continue; 38541440Smckusick if (!hasquota(fs, quotatype, &qfpathname)) 38612710Smckusick continue; 38741407Smckusick if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { 38841407Smckusick fprintf(stderr, "quota: out of memory\n"); 38941407Smckusick exit(2); 39041407Smckusick } 39141440Smckusick if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 39241440Smckusick if ((fd = open(qfpathname, O_RDONLY)) < 0) { 39341440Smckusick perror(qfpathname); 39441440Smckusick free(qup); 39541440Smckusick continue; 39641440Smckusick } 39741407Smckusick lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); 39841407Smckusick switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 39924684Sserge case 0: /* EOF */ 40024684Sserge /* 40124684Sserge * Convert implicit 0 quota (EOF) 40241407Smckusick * into an explicit one (zero'ed dqblk) 40324684Sserge */ 40441407Smckusick bzero((caddr_t)&qup->dqblk, 40541407Smckusick sizeof(struct dqblk)); 40624684Sserge break; 40724684Sserge 40841407Smckusick case sizeof(struct dqblk): /* OK */ 40924684Sserge break; 41024684Sserge 41124684Sserge default: /* ERROR */ 41241407Smckusick fprintf(stderr, "quota: read error"); 41341440Smckusick perror(qfpathname); 41441407Smckusick close(fd); 41541407Smckusick free(qup); 41612710Smckusick continue; 41712710Smckusick } 41841440Smckusick close(fd); 41912710Smckusick } 42041407Smckusick strcpy(qup->fsname, fs->fs_file); 42141407Smckusick if (quphead == NULL) 42241407Smckusick quphead = qup; 42312710Smckusick else 42441407Smckusick quptail->next = qup; 42541407Smckusick quptail = qup; 42641407Smckusick qup->next = 0; 42712710Smckusick } 42841407Smckusick endfsent(); 42941407Smckusick return (quphead); 43012710Smckusick } 43112710Smckusick 43241407Smckusick /* 43341407Smckusick * Check to see if a particular quota is to be enabled. 43441407Smckusick */ 43541440Smckusick hasquota(fs, type, qfnamep) 43641440Smckusick register struct fstab *fs; 43741407Smckusick int type; 43841440Smckusick char **qfnamep; 43912710Smckusick { 44041407Smckusick register char *opt; 44141440Smckusick char *cp, *index(), *strtok(); 44241407Smckusick static char initname, usrname[100], grpname[100]; 44341440Smckusick static char buf[BUFSIZ]; 44412710Smckusick 44541407Smckusick if (!initname) { 44641407Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 44741407Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 44841407Smckusick initname = 1; 44912710Smckusick } 45041440Smckusick strcpy(buf, fs->fs_mntops); 45141407Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 45241440Smckusick if (cp = index(opt, '=')) 45341440Smckusick *cp++ = '\0'; 45441407Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 45541440Smckusick break; 45641407Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 45741440Smckusick break; 45812710Smckusick } 45941440Smckusick if (!opt) 46041440Smckusick return (0); 46141440Smckusick if (cp) { 46241440Smckusick *qfnamep = cp; 46341440Smckusick return (1); 46441440Smckusick } 46541440Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 46641440Smckusick *qfnamep = buf; 46741440Smckusick return (1); 46812710Smckusick } 46912710Smckusick 47012710Smckusick alldigits(s) 47112710Smckusick register char *s; 47212710Smckusick { 47312710Smckusick register c; 47412710Smckusick 47512710Smckusick c = *s++; 47612710Smckusick do { 47712710Smckusick if (!isdigit(c)) 47812710Smckusick return (0); 47912710Smckusick } while (c = *s++); 48012710Smckusick return (1); 48112710Smckusick } 482