quota.c revision 92921
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Robert Elz at The University of Melbourne. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 3827888Scharnierstatic const char copyright[] = 391590Srgrimes"@(#) Copyright (c) 1980, 1990, 1993\n\ 401590Srgrimes The Regents of the University of California. All rights reserved.\n"; 411590Srgrimes#endif /* not lint */ 421590Srgrimes 431590Srgrimes#ifndef lint 4427888Scharnier#if 0 4513365Sgraichenstatic char sccsid[] = "from: @(#)quota.c 8.1 (Berkeley) 6/6/93"; 4627888Scharnier#endif 4727888Scharnierstatic const char rcsid[] = 4850477Speter "$FreeBSD: head/usr.bin/quota/quota.c 92921 2002-03-22 01:33:25Z imp $"; 491590Srgrimes#endif /* not lint */ 501590Srgrimes 511590Srgrimes/* 521590Srgrimes * Disk quota reporting program. 531590Srgrimes */ 541590Srgrimes#include <sys/param.h> 5513236Sgraichen#include <sys/types.h> 561590Srgrimes#include <sys/file.h> 571590Srgrimes#include <sys/stat.h> 5813236Sgraichen#include <sys/mount.h> 5913236Sgraichen#include <sys/socket.h> 601590Srgrimes#include <ufs/ufs/quota.h> 6127888Scharnier#include <ctype.h> 6227888Scharnier#include <err.h> 6327888Scharnier#include <fstab.h> 6427888Scharnier#include <grp.h> 6527888Scharnier#include <pwd.h> 661590Srgrimes#include <stdio.h> 6713236Sgraichen#include <stdlib.h> 6813236Sgraichen#include <string.h> 6916379Salex#include <unistd.h> 701590Srgrimes 7113236Sgraichen#include <netdb.h> 7213236Sgraichen#include <rpc/rpc.h> 7313236Sgraichen#include <rpc/pmap_prot.h> 7413236Sgraichen#include <rpcsvc/rquota.h> 7513236Sgraichen 761590Srgrimeschar *qfname = QUOTAFILENAME; 771590Srgrimeschar *qfextension[] = INITQFNAMES; 781590Srgrimes 791590Srgrimesstruct quotause { 801590Srgrimes struct quotause *next; 811590Srgrimes long flags; 821590Srgrimes struct dqblk dqblk; 831590Srgrimes char fsname[MAXPATHLEN + 1]; 8413236Sgraichen}; 851590Srgrimes#define FOUND 0x01 861590Srgrimes 8792921Simpstatic char *timeprt(time_t seconds); 8892921Simpstatic struct quotause *getprivs(long id, int quotatype); 8916379Salexstatic void usage (); 9016379Salexstatic void showuid(u_long uid); 9116379Salexstatic void showgid(u_long gid); 9216379Salexstatic int alldigits(char *s); 9316379Salexstatic void showusrname(char *name); 9416379Salexstatic void showgrpname(char *name); 9516379Salexstatic void showquotas(int type, u_long id, char *name); 9616379Salexstatic void heading(int type, u_long id, char *name, char *tag); 9716379Salexstatic char *timeprt(time_t seconds); 9816379Salexstatic struct quotause *getprivs(long id, int quotatype); 9916379Salexstatic int ufshasquota(struct fstab *fs, int type, char **qfnamep); 10016379Salexstatic int getufsquota(struct statfs *fst, struct fstab *fs, 10116379Salex struct quotause *qup, long id, int quotatype); 10216379Salexstatic int getnfsquota(struct statfs *fst, struct fstab *fs, 10316379Salex struct quotause *qup, long id, int quotatype); 10416379Salexstatic int callaurpc(char *host, int prognum, int versnum, int procnum, 10516379Salex xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10616379Salexstatic int alldigits(char *s); 10713236Sgraichen 1081590Srgrimesint qflag; 1091590Srgrimesint vflag; 1101590Srgrimes 11116379Salexint 1121590Srgrimesmain(argc, argv) 11316379Salex int argc; 1141590Srgrimes char *argv[]; 1151590Srgrimes{ 11613236Sgraichen int ngroups; 11713236Sgraichen gid_t mygid, gidset[NGROUPS]; 1181590Srgrimes int i, gflag = 0, uflag = 0; 1191590Srgrimes char ch; 1201590Srgrimes 12124360Simp while ((ch = getopt(argc, argv, "ugvq")) != -1) { 1221590Srgrimes switch(ch) { 1231590Srgrimes case 'g': 1241590Srgrimes gflag++; 1251590Srgrimes break; 1261590Srgrimes case 'u': 1271590Srgrimes uflag++; 1281590Srgrimes break; 1291590Srgrimes case 'v': 1301590Srgrimes vflag++; 1311590Srgrimes break; 1321590Srgrimes case 'q': 1331590Srgrimes qflag++; 1341590Srgrimes break; 1351590Srgrimes default: 1361590Srgrimes usage(); 1371590Srgrimes } 1381590Srgrimes } 1391590Srgrimes argc -= optind; 1401590Srgrimes argv += optind; 1411590Srgrimes if (!uflag && !gflag) 1421590Srgrimes uflag++; 1431590Srgrimes if (argc == 0) { 1441590Srgrimes if (uflag) 1451590Srgrimes showuid(getuid()); 1461590Srgrimes if (gflag) { 14713236Sgraichen mygid = getgid(); 1481590Srgrimes ngroups = getgroups(NGROUPS, gidset); 14927888Scharnier if (ngroups < 0) 15027888Scharnier err(1, "getgroups"); 15113236Sgraichen showgid(mygid); 15213236Sgraichen for (i = 0; i < ngroups; i++) 15313236Sgraichen if (gidset[i] != mygid) 15413236Sgraichen showgid(gidset[i]); 1551590Srgrimes } 15616379Salex return(0); 1571590Srgrimes } 1581590Srgrimes if (uflag && gflag) 1591590Srgrimes usage(); 1601590Srgrimes if (uflag) { 1611590Srgrimes for (; argc > 0; argc--, argv++) { 1621590Srgrimes if (alldigits(*argv)) 1631590Srgrimes showuid(atoi(*argv)); 1641590Srgrimes else 1651590Srgrimes showusrname(*argv); 1661590Srgrimes } 16716379Salex return(0); 1681590Srgrimes } 1691590Srgrimes if (gflag) { 1701590Srgrimes for (; argc > 0; argc--, argv++) { 1711590Srgrimes if (alldigits(*argv)) 1721590Srgrimes showgid(atoi(*argv)); 1731590Srgrimes else 1741590Srgrimes showgrpname(*argv); 1751590Srgrimes } 1761590Srgrimes } 17716379Salex return(0); 1781590Srgrimes} 1791590Srgrimes 18016379Salexstatic void 1811590Srgrimesusage() 1821590Srgrimes{ 1831590Srgrimes 1841590Srgrimes fprintf(stderr, "%s\n%s\n%s\n", 18527888Scharnier "usage: quota [-guqv]", 18627888Scharnier " quota [-qv] -u username ...", 18727888Scharnier " quota [-qv] -g groupname ..."); 1881590Srgrimes exit(1); 1891590Srgrimes} 1901590Srgrimes 1911590Srgrimes/* 1921590Srgrimes * Print out quotas for a specified user identifier. 1931590Srgrimes */ 19416379Salexstatic void 1951590Srgrimesshowuid(uid) 1961590Srgrimes u_long uid; 1971590Srgrimes{ 1981590Srgrimes struct passwd *pwd = getpwuid(uid); 1991590Srgrimes u_long myuid; 2001590Srgrimes char *name; 2011590Srgrimes 2021590Srgrimes if (pwd == NULL) 2031590Srgrimes name = "(no account)"; 2041590Srgrimes else 2051590Srgrimes name = pwd->pw_name; 2061590Srgrimes myuid = getuid(); 2071590Srgrimes if (uid != myuid && myuid != 0) { 20813365Sgraichen printf("quota: %s (uid %lu): permission denied\n", name, uid); 2091590Srgrimes return; 2101590Srgrimes } 2111590Srgrimes showquotas(USRQUOTA, uid, name); 2121590Srgrimes} 2131590Srgrimes 2141590Srgrimes/* 2151590Srgrimes * Print out quotas for a specifed user name. 2161590Srgrimes */ 21716379Salexstatic void 2181590Srgrimesshowusrname(name) 2191590Srgrimes char *name; 2201590Srgrimes{ 2211590Srgrimes struct passwd *pwd = getpwnam(name); 2221590Srgrimes u_long myuid; 2231590Srgrimes 2241590Srgrimes if (pwd == NULL) { 22527888Scharnier warnx("%s: unknown user", name); 2261590Srgrimes return; 2271590Srgrimes } 2281590Srgrimes myuid = getuid(); 2291590Srgrimes if (pwd->pw_uid != myuid && myuid != 0) { 23027888Scharnier warnx("%s (uid %u): permission denied", name, pwd->pw_uid); 2311590Srgrimes return; 2321590Srgrimes } 2331590Srgrimes showquotas(USRQUOTA, pwd->pw_uid, name); 2341590Srgrimes} 2351590Srgrimes 2361590Srgrimes/* 2371590Srgrimes * Print out quotas for a specified group identifier. 2381590Srgrimes */ 23916379Salexstatic void 2401590Srgrimesshowgid(gid) 2411590Srgrimes u_long gid; 2421590Srgrimes{ 2431590Srgrimes struct group *grp = getgrgid(gid); 24413236Sgraichen int ngroups; 24513236Sgraichen gid_t mygid, gidset[NGROUPS]; 2461590Srgrimes register int i; 2471590Srgrimes char *name; 2481590Srgrimes 2491590Srgrimes if (grp == NULL) 2501590Srgrimes name = "(no entry)"; 2511590Srgrimes else 2521590Srgrimes name = grp->gr_name; 25313236Sgraichen mygid = getgid(); 2541590Srgrimes ngroups = getgroups(NGROUPS, gidset); 2551590Srgrimes if (ngroups < 0) { 25627888Scharnier warn("getgroups"); 2571590Srgrimes return; 2581590Srgrimes } 25913236Sgraichen if (gid != mygid) { 26013236Sgraichen for (i = 0; i < ngroups; i++) 26113236Sgraichen if (gid == gidset[i]) 26213236Sgraichen break; 26313236Sgraichen if (i >= ngroups && getuid() != 0) { 26427888Scharnier warnx("%s (gid %lu): permission denied", name, gid); 26513236Sgraichen return; 26613236Sgraichen } 2671590Srgrimes } 2681590Srgrimes showquotas(GRPQUOTA, gid, name); 2691590Srgrimes} 2701590Srgrimes 2711590Srgrimes/* 2721590Srgrimes * Print out quotas for a specifed group name. 2731590Srgrimes */ 27416379Salexstatic void 2751590Srgrimesshowgrpname(name) 2761590Srgrimes char *name; 2771590Srgrimes{ 2781590Srgrimes struct group *grp = getgrnam(name); 27913236Sgraichen int ngroups; 28013236Sgraichen gid_t mygid, gidset[NGROUPS]; 2811590Srgrimes register int i; 2821590Srgrimes 2831590Srgrimes if (grp == NULL) { 28427888Scharnier warnx("%s: unknown group", name); 2851590Srgrimes return; 2861590Srgrimes } 28713236Sgraichen mygid = getgid(); 2881590Srgrimes ngroups = getgroups(NGROUPS, gidset); 2891590Srgrimes if (ngroups < 0) { 29027888Scharnier warn("getgroups"); 2911590Srgrimes return; 2921590Srgrimes } 29313236Sgraichen if (grp->gr_gid != mygid) { 29413236Sgraichen for (i = 0; i < ngroups; i++) 29513236Sgraichen if (grp->gr_gid == gidset[i]) 29613236Sgraichen break; 29713236Sgraichen if (i >= ngroups && getuid() != 0) { 29858618Scharnier warnx("%s (gid %u): permission denied", name, 29958618Scharnier grp->gr_gid); 30013236Sgraichen return; 30113236Sgraichen } 3021590Srgrimes } 3031590Srgrimes showquotas(GRPQUOTA, grp->gr_gid, name); 3041590Srgrimes} 3051590Srgrimes 30616379Salexstatic void 3071590Srgrimesshowquotas(type, id, name) 3081590Srgrimes int type; 3091590Srgrimes u_long id; 3101590Srgrimes char *name; 3111590Srgrimes{ 3121590Srgrimes register struct quotause *qup; 31313236Sgraichen struct quotause *quplist; 31413236Sgraichen char *msgi, *msgb, *nam; 31516379Salex int lines = 0; 3161590Srgrimes static time_t now; 3171590Srgrimes 3181590Srgrimes if (now == 0) 3191590Srgrimes time(&now); 3201590Srgrimes quplist = getprivs(id, type); 3211590Srgrimes for (qup = quplist; qup; qup = qup->next) { 3221590Srgrimes if (!vflag && 3231590Srgrimes qup->dqblk.dqb_isoftlimit == 0 && 3241590Srgrimes qup->dqblk.dqb_ihardlimit == 0 && 3251590Srgrimes qup->dqblk.dqb_bsoftlimit == 0 && 3261590Srgrimes qup->dqblk.dqb_bhardlimit == 0) 3271590Srgrimes continue; 3281590Srgrimes msgi = (char *)0; 3291590Srgrimes if (qup->dqblk.dqb_ihardlimit && 3301590Srgrimes qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) 3311590Srgrimes msgi = "File limit reached on"; 3321590Srgrimes else if (qup->dqblk.dqb_isoftlimit && 3331590Srgrimes qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) 3341590Srgrimes if (qup->dqblk.dqb_itime > now) 3351590Srgrimes msgi = "In file grace period on"; 3361590Srgrimes else 3371590Srgrimes msgi = "Over file quota on"; 3381590Srgrimes msgb = (char *)0; 3391590Srgrimes if (qup->dqblk.dqb_bhardlimit && 3401590Srgrimes qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) 3411590Srgrimes msgb = "Block limit reached on"; 3421590Srgrimes else if (qup->dqblk.dqb_bsoftlimit && 3431590Srgrimes qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) 3441590Srgrimes if (qup->dqblk.dqb_btime > now) 3451590Srgrimes msgb = "In block grace period on"; 3461590Srgrimes else 3471590Srgrimes msgb = "Over block quota on"; 3481590Srgrimes if (qflag) { 3491590Srgrimes if ((msgi != (char *)0 || msgb != (char *)0) && 3501590Srgrimes lines++ == 0) 3511590Srgrimes heading(type, id, name, ""); 3521590Srgrimes if (msgi != (char *)0) 3531590Srgrimes printf("\t%s %s\n", msgi, qup->fsname); 3541590Srgrimes if (msgb != (char *)0) 3551590Srgrimes printf("\t%s %s\n", msgb, qup->fsname); 3561590Srgrimes continue; 3571590Srgrimes } 3581590Srgrimes if (vflag || 3591590Srgrimes qup->dqblk.dqb_curblocks || 3601590Srgrimes qup->dqblk.dqb_curinodes) { 3611590Srgrimes if (lines++ == 0) 3621590Srgrimes heading(type, id, name, ""); 36313236Sgraichen nam = qup->fsname; 36413236Sgraichen if (strlen(qup->fsname) > 15) { 36513236Sgraichen printf("%s\n", qup->fsname); 36613236Sgraichen nam = ""; 36713236Sgraichen } 3688327Sbde printf("%15s%8lu%c%7lu%8lu%8s" 36913236Sgraichen , nam 37013365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_curblocks) 37113365Sgraichen / 1024) 3721590Srgrimes , (msgb == (char *)0) ? ' ' : '*' 37313365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_bsoftlimit) 37413365Sgraichen / 1024) 37513365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_bhardlimit) 37613365Sgraichen / 1024) 3771590Srgrimes , (msgb == (char *)0) ? "" 37813236Sgraichen :timeprt(qup->dqblk.dqb_btime)); 37913365Sgraichen printf("%8lu%c%7lu%8lu%8s\n" 3801590Srgrimes , qup->dqblk.dqb_curinodes 3811590Srgrimes , (msgi == (char *)0) ? ' ' : '*' 3821590Srgrimes , qup->dqblk.dqb_isoftlimit 3831590Srgrimes , qup->dqblk.dqb_ihardlimit 3841590Srgrimes , (msgi == (char *)0) ? "" 3851590Srgrimes : timeprt(qup->dqblk.dqb_itime) 3861590Srgrimes ); 3871590Srgrimes continue; 3881590Srgrimes } 3891590Srgrimes } 3901590Srgrimes if (!qflag && lines == 0) 3911590Srgrimes heading(type, id, name, "none"); 3921590Srgrimes} 3931590Srgrimes 39416379Salexstatic void 3951590Srgrimesheading(type, id, name, tag) 3961590Srgrimes int type; 3971590Srgrimes u_long id; 3981590Srgrimes char *name, *tag; 3991590Srgrimes{ 4001590Srgrimes 40113365Sgraichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 4021590Srgrimes name, *qfextension[type], id, tag); 4031590Srgrimes if (!qflag && tag[0] == '\0') { 4041590Srgrimes printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 4051590Srgrimes , "Filesystem" 40677047Spirzyk , "usage" 4071590Srgrimes , "quota" 4081590Srgrimes , "limit" 4091590Srgrimes , "grace" 4101590Srgrimes , "files" 4111590Srgrimes , "quota" 4121590Srgrimes , "limit" 4131590Srgrimes , "grace" 4141590Srgrimes ); 4151590Srgrimes } 4161590Srgrimes} 4171590Srgrimes 4181590Srgrimes/* 4191590Srgrimes * Calculate the grace period and return a printable string for it. 4201590Srgrimes */ 42116379Salexstatic char * 4221590Srgrimestimeprt(seconds) 4231590Srgrimes time_t seconds; 4241590Srgrimes{ 4251590Srgrimes time_t hours, minutes; 4261590Srgrimes static char buf[20]; 4271590Srgrimes static time_t now; 4281590Srgrimes 4291590Srgrimes if (now == 0) 4301590Srgrimes time(&now); 4311590Srgrimes if (now > seconds) 4321590Srgrimes return ("none"); 4331590Srgrimes seconds -= now; 4341590Srgrimes minutes = (seconds + 30) / 60; 4351590Srgrimes hours = (minutes + 30) / 60; 4361590Srgrimes if (hours >= 36) { 43713365Sgraichen sprintf(buf, "%lddays", (hours + 12) / 24); 4381590Srgrimes return (buf); 4391590Srgrimes } 4401590Srgrimes if (minutes >= 60) { 44113365Sgraichen sprintf(buf, "%2ld:%ld", minutes / 60, minutes % 60); 4421590Srgrimes return (buf); 4431590Srgrimes } 44413365Sgraichen sprintf(buf, "%2ld", minutes); 4451590Srgrimes return (buf); 4461590Srgrimes} 4471590Srgrimes 4481590Srgrimes/* 4491590Srgrimes * Collect the requested quota information. 4501590Srgrimes */ 45116379Salexstatic struct quotause * 4521590Srgrimesgetprivs(id, quotatype) 4531590Srgrimes register long id; 4541590Srgrimes int quotatype; 4551590Srgrimes{ 45613236Sgraichen register struct quotause *qup, *quptail; 4571590Srgrimes register struct fstab *fs; 4581590Srgrimes struct quotause *quphead; 45913236Sgraichen struct statfs *fst; 46013236Sgraichen int nfst, i; 4611590Srgrimes 46213236Sgraichen qup = quphead = (struct quotause *)0; 46313236Sgraichen 46413236Sgraichen nfst = getmntinfo(&fst, MNT_WAIT); 46527888Scharnier if (nfst == 0) 46627888Scharnier errx(2, "no filesystems mounted!"); 4671590Srgrimes setfsent(); 46813236Sgraichen for (i=0; i<nfst; i++) { 46913236Sgraichen if (qup == NULL) { 47013365Sgraichen if ((qup = (struct quotause *)malloc(sizeof *qup)) 47127888Scharnier == NULL) 47227888Scharnier errx(2, "out of memory"); 4731590Srgrimes } 47432651Sbde if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 47513365Sgraichen if (getnfsquota(&fst[i], NULL, qup, id, quotatype) 47613365Sgraichen == 0) 4771590Srgrimes continue; 47836880Sache } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 47913236Sgraichen /* 48013236Sgraichen * XXX 48113236Sgraichen * UFS filesystems must be in /etc/fstab, and must 48213236Sgraichen * indicate that they have quotas on (?!) This is quite 48313236Sgraichen * unlike SunOS where quotas can be enabled/disabled 48413236Sgraichen * on a filesystem independent of /etc/fstab, and it 48513236Sgraichen * will still print quotas for them. 48613236Sgraichen */ 48713236Sgraichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 4881590Srgrimes continue; 48913236Sgraichen if (getufsquota(&fst[i], fs, qup, id, quotatype) == 0) 49013236Sgraichen continue; 49113236Sgraichen } else 49213236Sgraichen continue; 49313236Sgraichen strcpy(qup->fsname, fst[i].f_mntonname); 4941590Srgrimes if (quphead == NULL) 4951590Srgrimes quphead = qup; 4961590Srgrimes else 4971590Srgrimes quptail->next = qup; 4981590Srgrimes quptail = qup; 49913236Sgraichen quptail->next = 0; 50013236Sgraichen qup = NULL; 5011590Srgrimes } 50213236Sgraichen if (qup) 50313236Sgraichen free(qup); 5041590Srgrimes endfsent(); 5051590Srgrimes return (quphead); 5061590Srgrimes} 5071590Srgrimes 5081590Srgrimes/* 5091590Srgrimes * Check to see if a particular quota is to be enabled. 5101590Srgrimes */ 51116379Salexstatic int 51213236Sgraichenufshasquota(fs, type, qfnamep) 5131590Srgrimes register struct fstab *fs; 5141590Srgrimes int type; 5151590Srgrimes char **qfnamep; 5161590Srgrimes{ 5171590Srgrimes static char initname, usrname[100], grpname[100]; 5181590Srgrimes static char buf[BUFSIZ]; 51913236Sgraichen char *opt, *cp; 5201590Srgrimes 5211590Srgrimes if (!initname) { 5221590Srgrimes sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 5231590Srgrimes sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 5241590Srgrimes initname = 1; 5251590Srgrimes } 5261590Srgrimes strcpy(buf, fs->fs_mntops); 5271590Srgrimes for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 52816379Salex if ((cp = index(opt, '='))) 5291590Srgrimes *cp++ = '\0'; 5301590Srgrimes if (type == USRQUOTA && strcmp(opt, usrname) == 0) 5311590Srgrimes break; 5321590Srgrimes if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 5331590Srgrimes break; 5341590Srgrimes } 5351590Srgrimes if (!opt) 5361590Srgrimes return (0); 5371590Srgrimes if (cp) { 5381590Srgrimes *qfnamep = cp; 5391590Srgrimes return (1); 5401590Srgrimes } 5411590Srgrimes (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 5421590Srgrimes *qfnamep = buf; 5431590Srgrimes return (1); 5441590Srgrimes} 5451590Srgrimes 54616379Salexstatic int 54713236Sgraichengetufsquota(fst, fs, qup, id, quotatype) 54813236Sgraichen struct statfs *fst; 54913236Sgraichen struct fstab *fs; 55013236Sgraichen struct quotause *qup; 55113236Sgraichen long id; 55213236Sgraichen int quotatype; 55313236Sgraichen{ 55413236Sgraichen char *qfpathname; 55513236Sgraichen int fd, qcmd; 55613236Sgraichen 55713236Sgraichen qcmd = QCMD(Q_GETQUOTA, quotatype); 55813236Sgraichen if (!ufshasquota(fs, quotatype, &qfpathname)) 55913236Sgraichen return (0); 56013236Sgraichen 56116379Salex if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) { 56213236Sgraichen if ((fd = open(qfpathname, O_RDONLY)) < 0) { 56358618Scharnier warn("%s", qfpathname); 56413236Sgraichen return (0); 56513236Sgraichen } 56613236Sgraichen (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 56713236Sgraichen switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 56813236Sgraichen case 0: /* EOF */ 56913236Sgraichen /* 57013236Sgraichen * Convert implicit 0 quota (EOF) 57113236Sgraichen * into an explicit one (zero'ed dqblk) 57213236Sgraichen */ 57313236Sgraichen bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk)); 57413236Sgraichen break; 57513236Sgraichen case sizeof(struct dqblk): /* OK */ 57613236Sgraichen break; 57713236Sgraichen default: /* ERROR */ 57827888Scharnier warn("read error: %s", qfpathname); 57913236Sgraichen close(fd); 58013236Sgraichen return (0); 58113236Sgraichen } 58213236Sgraichen close(fd); 58313236Sgraichen } 58413236Sgraichen return (1); 58513236Sgraichen} 58613236Sgraichen 58716379Salexstatic int 58813236Sgraichengetnfsquota(fst, fs, qup, id, quotatype) 58913236Sgraichen struct statfs *fst; 59013236Sgraichen struct fstab *fs; 59113236Sgraichen struct quotause *qup; 59213236Sgraichen long id; 59313236Sgraichen int quotatype; 59413236Sgraichen{ 59513236Sgraichen struct getquota_args gq_args; 59613236Sgraichen struct getquota_rslt gq_rslt; 59713236Sgraichen struct dqblk *dqp = &qup->dqblk; 59813236Sgraichen struct timeval tv; 59913236Sgraichen char *cp; 60013236Sgraichen 60113236Sgraichen if (fst->f_flags & MNT_LOCAL) 60213236Sgraichen return (0); 60313236Sgraichen 60413236Sgraichen /* 60513236Sgraichen * rpc.rquotad does not support group quotas 60613236Sgraichen */ 60713236Sgraichen if (quotatype != USRQUOTA) 60813236Sgraichen return (0); 60913236Sgraichen 61013236Sgraichen /* 61113236Sgraichen * must be some form of "hostname:/path" 61213236Sgraichen */ 61313236Sgraichen cp = strchr(fst->f_mntfromname, ':'); 61413236Sgraichen if (cp == NULL) { 61558618Scharnier warnx("cannot find hostname for %s", fst->f_mntfromname); 61613236Sgraichen return (0); 61713236Sgraichen } 61813236Sgraichen 61913236Sgraichen *cp = '\0'; 62013236Sgraichen if (*(cp+1) != '/') { 62113236Sgraichen *cp = ':'; 62213236Sgraichen return (0); 62313236Sgraichen } 62413236Sgraichen 62513236Sgraichen gq_args.gqa_pathp = cp + 1; 62613236Sgraichen gq_args.gqa_uid = id; 62713236Sgraichen if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS, 62816379Salex RQUOTAPROC_GETQUOTA, xdr_getquota_args, (char *)&gq_args, 62916379Salex xdr_getquota_rslt, (char *)&gq_rslt) != 0) { 63013236Sgraichen *cp = ':'; 63113236Sgraichen return (0); 63213236Sgraichen } 63313236Sgraichen 63413236Sgraichen switch (gq_rslt.status) { 63513236Sgraichen case Q_NOQUOTA: 63613236Sgraichen break; 63713236Sgraichen case Q_EPERM: 63827888Scharnier warnx("quota permission error, host: %s", 63913236Sgraichen fst->f_mntfromname); 64013236Sgraichen break; 64113236Sgraichen case Q_OK: 64213236Sgraichen gettimeofday(&tv, NULL); 64313236Sgraichen /* blocks*/ 64413236Sgraichen dqp->dqb_bhardlimit = 64513236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * 64613236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 64713236Sgraichen dqp->dqb_bsoftlimit = 64813236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * 64913236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 65013236Sgraichen dqp->dqb_curblocks = 65113236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * 65213236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 65313236Sgraichen /* inodes */ 65413236Sgraichen dqp->dqb_ihardlimit = 65513236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit; 65613236Sgraichen dqp->dqb_isoftlimit = 65713236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit; 65813236Sgraichen dqp->dqb_curinodes = 65913236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; 66013236Sgraichen /* grace times */ 66113236Sgraichen dqp->dqb_btime = 66213236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft; 66313236Sgraichen dqp->dqb_itime = 66413236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft; 66513236Sgraichen *cp = ':'; 66613236Sgraichen return (1); 66713236Sgraichen default: 66858618Scharnier warnx("bad rpc result, host: %s", fst->f_mntfromname); 66913236Sgraichen break; 67013236Sgraichen } 67113236Sgraichen *cp = ':'; 67213236Sgraichen return (0); 67313236Sgraichen} 67413236Sgraichen 67516379Salexstatic int 67613236Sgraichencallaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out) 67713236Sgraichen char *host; 67813236Sgraichen xdrproc_t inproc, outproc; 67913236Sgraichen char *in, *out; 68016379Salex int prognum, versnum, procnum; 68113236Sgraichen{ 68213236Sgraichen struct sockaddr_in server_addr; 68313236Sgraichen enum clnt_stat clnt_stat; 68413236Sgraichen struct hostent *hp; 68513236Sgraichen struct timeval timeout, tottimeout; 68613236Sgraichen 68713236Sgraichen CLIENT *client = NULL; 68813236Sgraichen int socket = RPC_ANYSOCK; 68913236Sgraichen 69013236Sgraichen if ((hp = gethostbyname(host)) == NULL) 69113236Sgraichen return ((int) RPC_UNKNOWNHOST); 69213236Sgraichen timeout.tv_usec = 0; 69313236Sgraichen timeout.tv_sec = 6; 69458618Scharnier bcopy(hp->h_addr, &server_addr.sin_addr, 69558618Scharnier MIN(hp->h_length,sizeof(server_addr.sin_addr))); 69613236Sgraichen server_addr.sin_family = AF_INET; 69713236Sgraichen server_addr.sin_port = 0; 69813236Sgraichen 69913236Sgraichen if ((client = clntudp_create(&server_addr, prognum, 70013236Sgraichen versnum, timeout, &socket)) == NULL) 70113236Sgraichen return ((int) rpc_createerr.cf_stat); 70213236Sgraichen 70313236Sgraichen client->cl_auth = authunix_create_default(); 70413236Sgraichen tottimeout.tv_sec = 25; 70513236Sgraichen tottimeout.tv_usec = 0; 70613236Sgraichen clnt_stat = clnt_call(client, procnum, inproc, in, 70713236Sgraichen outproc, out, tottimeout); 70813236Sgraichen 70913236Sgraichen return ((int) clnt_stat); 71013236Sgraichen} 71113236Sgraichen 71216379Salexstatic int 7131590Srgrimesalldigits(s) 7141590Srgrimes register char *s; 7151590Srgrimes{ 7161590Srgrimes register c; 7171590Srgrimes 7181590Srgrimes c = *s++; 7191590Srgrimes do { 7201590Srgrimes if (!isdigit(c)) 7211590Srgrimes return (0); 72216379Salex } while ((c = *s++)); 7231590Srgrimes return (1); 7241590Srgrimes} 725