quota.c revision 101545
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"; 4195624Smarkm#endif 421590Srgrimes 431590Srgrimes#ifndef lint 4495624Smarkmstatic const char sccsid[] = "from: @(#)quota.c 8.1 (Berkeley) 6/6/93"; 451590Srgrimes#endif /* not lint */ 461590Srgrimes 471590Srgrimes/* 481590Srgrimes * Disk quota reporting program. 491590Srgrimes */ 5095624Smarkm#include <sys/cdefs.h> 5195624Smarkm__FBSDID("$FreeBSD: head/usr.bin/quota/quota.c 101545 2002-08-09 00:53:00Z iedowse $"); 5295624Smarkm 531590Srgrimes#include <sys/param.h> 5413236Sgraichen#include <sys/types.h> 551590Srgrimes#include <sys/file.h> 561590Srgrimes#include <sys/stat.h> 5713236Sgraichen#include <sys/mount.h> 5813236Sgraichen#include <sys/socket.h> 5995624Smarkm 6095624Smarkm#include <rpc/rpc.h> 6195624Smarkm#include <rpc/pmap_prot.h> 6295624Smarkm#include <rpcsvc/rquota.h> 6395624Smarkm 641590Srgrimes#include <ufs/ufs/quota.h> 6595624Smarkm 6627888Scharnier#include <ctype.h> 6727888Scharnier#include <err.h> 6827888Scharnier#include <fstab.h> 6927888Scharnier#include <grp.h> 7095624Smarkm#include <netdb.h> 7127888Scharnier#include <pwd.h> 721590Srgrimes#include <stdio.h> 7313236Sgraichen#include <stdlib.h> 7413236Sgraichen#include <string.h> 7516379Salex#include <unistd.h> 761590Srgrimes 7795624Smarkmconst char *qfname = QUOTAFILENAME; 7895624Smarkmconst char *qfextension[] = INITQFNAMES; 7913236Sgraichen 801590Srgrimesstruct quotause { 811590Srgrimes struct quotause *next; 821590Srgrimes long flags; 831590Srgrimes struct dqblk dqblk; 841590Srgrimes char fsname[MAXPATHLEN + 1]; 8513236Sgraichen}; 861590Srgrimes#define FOUND 0x01 871590Srgrimes 8895624Smarkmstatic const char *timeprt(time_t seconds); 8992921Simpstatic struct quotause *getprivs(long id, int quotatype); 9095624Smarkmstatic void usage(void); 9116379Salexstatic void showuid(u_long uid); 9216379Salexstatic void showgid(u_long gid); 9316379Salexstatic int alldigits(char *s); 9416379Salexstatic void showusrname(char *name); 9516379Salexstatic void showgrpname(char *name); 9695624Smarkmstatic void showquotas(int type, u_long id, const char *name); 9795624Smarkmstatic void heading(int type, u_long id, const char *name, const char *tag); 9816379Salexstatic struct quotause *getprivs(long id, int quotatype); 9916379Salexstatic int ufshasquota(struct fstab *fs, int type, char **qfnamep); 10095624Smarkmstatic int getufsquota(struct fstab *fs, struct quotause *qup, long id, 10195624Smarkm int quotatype); 10295624Smarkmstatic int getnfsquota(struct statfs *fst, struct quotause *qup, long id, 10395624Smarkm int quotatype); 10416379Salexstatic int callaurpc(char *host, int prognum, int versnum, int procnum, 10595624Smarkm xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10616379Salexstatic int alldigits(char *s); 10713236Sgraichen 108101545Siedowseint lflag; 1091590Srgrimesint qflag; 1101590Srgrimesint vflag; 1111590Srgrimes 11216379Salexint 11395624Smarkmmain(int argc, char *argv[]) 1141590Srgrimes{ 11513236Sgraichen int ngroups; 11613236Sgraichen gid_t mygid, gidset[NGROUPS]; 1171590Srgrimes int i, gflag = 0, uflag = 0; 1181590Srgrimes char ch; 1191590Srgrimes 120101545Siedowse while ((ch = getopt(argc, argv, "glquv")) != -1) { 1211590Srgrimes switch(ch) { 1221590Srgrimes case 'g': 1231590Srgrimes gflag++; 1241590Srgrimes break; 125101545Siedowse case 'l': 126101545Siedowse lflag++; 127101545Siedowse break; 128101544Siedowse case 'q': 129101544Siedowse qflag++; 130101544Siedowse break; 1311590Srgrimes case 'u': 1321590Srgrimes uflag++; 1331590Srgrimes break; 1341590Srgrimes case 'v': 1351590Srgrimes vflag++; 1361590Srgrimes break; 1371590Srgrimes default: 1381590Srgrimes usage(); 1391590Srgrimes } 1401590Srgrimes } 1411590Srgrimes argc -= optind; 1421590Srgrimes argv += optind; 1431590Srgrimes if (!uflag && !gflag) 1441590Srgrimes uflag++; 1451590Srgrimes if (argc == 0) { 1461590Srgrimes if (uflag) 1471590Srgrimes showuid(getuid()); 1481590Srgrimes if (gflag) { 14913236Sgraichen mygid = getgid(); 1501590Srgrimes ngroups = getgroups(NGROUPS, gidset); 15127888Scharnier if (ngroups < 0) 15227888Scharnier err(1, "getgroups"); 15313236Sgraichen showgid(mygid); 15413236Sgraichen for (i = 0; i < ngroups; i++) 15513236Sgraichen if (gidset[i] != mygid) 15613236Sgraichen showgid(gidset[i]); 1571590Srgrimes } 15816379Salex return(0); 1591590Srgrimes } 1601590Srgrimes if (uflag && gflag) 1611590Srgrimes usage(); 1621590Srgrimes if (uflag) { 1631590Srgrimes for (; argc > 0; argc--, argv++) { 1641590Srgrimes if (alldigits(*argv)) 1651590Srgrimes showuid(atoi(*argv)); 1661590Srgrimes else 1671590Srgrimes showusrname(*argv); 1681590Srgrimes } 16916379Salex return(0); 1701590Srgrimes } 1711590Srgrimes if (gflag) { 1721590Srgrimes for (; argc > 0; argc--, argv++) { 1731590Srgrimes if (alldigits(*argv)) 1741590Srgrimes showgid(atoi(*argv)); 1751590Srgrimes else 1761590Srgrimes showgrpname(*argv); 1771590Srgrimes } 1781590Srgrimes } 17916379Salex return(0); 1801590Srgrimes} 1811590Srgrimes 18216379Salexstatic void 18395624Smarkmusage(void) 1841590Srgrimes{ 1851590Srgrimes 1861590Srgrimes fprintf(stderr, "%s\n%s\n%s\n", 187101545Siedowse "usage: quota [-glu] [-v | -q]", 188101545Siedowse " quota [-lu] [-v | -q] user ...", 189101545Siedowse " quota -g [-l] [-v | -q] group ..."); 1901590Srgrimes exit(1); 1911590Srgrimes} 1921590Srgrimes 1931590Srgrimes/* 1941590Srgrimes * Print out quotas for a specified user identifier. 1951590Srgrimes */ 19616379Salexstatic void 19795624Smarkmshowuid(u_long uid) 1981590Srgrimes{ 1991590Srgrimes struct passwd *pwd = getpwuid(uid); 2001590Srgrimes u_long myuid; 20195624Smarkm const char *name; 2021590Srgrimes 2031590Srgrimes if (pwd == NULL) 2041590Srgrimes name = "(no account)"; 2051590Srgrimes else 2061590Srgrimes name = pwd->pw_name; 2071590Srgrimes myuid = getuid(); 2081590Srgrimes if (uid != myuid && myuid != 0) { 20913365Sgraichen printf("quota: %s (uid %lu): permission denied\n", name, uid); 2101590Srgrimes return; 2111590Srgrimes } 2121590Srgrimes showquotas(USRQUOTA, uid, name); 2131590Srgrimes} 2141590Srgrimes 2151590Srgrimes/* 2161590Srgrimes * Print out quotas for a specifed user name. 2171590Srgrimes */ 21816379Salexstatic void 21995624Smarkmshowusrname(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 24095624Smarkmshowgid(u_long gid) 2411590Srgrimes{ 2421590Srgrimes struct group *grp = getgrgid(gid); 24313236Sgraichen int ngroups; 24413236Sgraichen gid_t mygid, gidset[NGROUPS]; 24595624Smarkm int i; 24695624Smarkm const char *name; 2471590Srgrimes 2481590Srgrimes if (grp == NULL) 2491590Srgrimes name = "(no entry)"; 2501590Srgrimes else 2511590Srgrimes name = grp->gr_name; 25213236Sgraichen mygid = getgid(); 2531590Srgrimes ngroups = getgroups(NGROUPS, gidset); 2541590Srgrimes if (ngroups < 0) { 25527888Scharnier warn("getgroups"); 2561590Srgrimes return; 2571590Srgrimes } 25813236Sgraichen if (gid != mygid) { 25913236Sgraichen for (i = 0; i < ngroups; i++) 26013236Sgraichen if (gid == gidset[i]) 26113236Sgraichen break; 26213236Sgraichen if (i >= ngroups && getuid() != 0) { 26327888Scharnier warnx("%s (gid %lu): permission denied", name, gid); 26413236Sgraichen return; 26513236Sgraichen } 2661590Srgrimes } 2671590Srgrimes showquotas(GRPQUOTA, gid, name); 2681590Srgrimes} 2691590Srgrimes 2701590Srgrimes/* 2711590Srgrimes * Print out quotas for a specifed group name. 2721590Srgrimes */ 27316379Salexstatic void 27495624Smarkmshowgrpname(char *name) 2751590Srgrimes{ 2761590Srgrimes struct group *grp = getgrnam(name); 27713236Sgraichen int ngroups; 27813236Sgraichen gid_t mygid, gidset[NGROUPS]; 27995624Smarkm int i; 2801590Srgrimes 2811590Srgrimes if (grp == NULL) { 28227888Scharnier warnx("%s: unknown group", name); 2831590Srgrimes return; 2841590Srgrimes } 28513236Sgraichen mygid = getgid(); 2861590Srgrimes ngroups = getgroups(NGROUPS, gidset); 2871590Srgrimes if (ngroups < 0) { 28827888Scharnier warn("getgroups"); 2891590Srgrimes return; 2901590Srgrimes } 29113236Sgraichen if (grp->gr_gid != mygid) { 29213236Sgraichen for (i = 0; i < ngroups; i++) 29313236Sgraichen if (grp->gr_gid == gidset[i]) 29413236Sgraichen break; 29513236Sgraichen if (i >= ngroups && getuid() != 0) { 29658618Scharnier warnx("%s (gid %u): permission denied", name, 29758618Scharnier grp->gr_gid); 29813236Sgraichen return; 29913236Sgraichen } 3001590Srgrimes } 3011590Srgrimes showquotas(GRPQUOTA, grp->gr_gid, name); 3021590Srgrimes} 3031590Srgrimes 30416379Salexstatic void 30595624Smarkmshowquotas(int type, u_long id, const char *name) 3061590Srgrimes{ 30795624Smarkm struct quotause *qup; 30813236Sgraichen struct quotause *quplist; 30995624Smarkm const char *msgi, *msgb; 31095624Smarkm const char *nam; 31116379Salex int lines = 0; 3121590Srgrimes static time_t now; 3131590Srgrimes 3141590Srgrimes if (now == 0) 3151590Srgrimes time(&now); 3161590Srgrimes quplist = getprivs(id, type); 3171590Srgrimes for (qup = quplist; qup; qup = qup->next) { 3181590Srgrimes if (!vflag && 3191590Srgrimes qup->dqblk.dqb_isoftlimit == 0 && 3201590Srgrimes qup->dqblk.dqb_ihardlimit == 0 && 3211590Srgrimes qup->dqblk.dqb_bsoftlimit == 0 && 3221590Srgrimes qup->dqblk.dqb_bhardlimit == 0) 3231590Srgrimes continue; 3241590Srgrimes msgi = (char *)0; 3251590Srgrimes if (qup->dqblk.dqb_ihardlimit && 3261590Srgrimes qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) 3271590Srgrimes msgi = "File limit reached on"; 3281590Srgrimes else if (qup->dqblk.dqb_isoftlimit && 32995624Smarkm qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 3301590Srgrimes if (qup->dqblk.dqb_itime > now) 3311590Srgrimes msgi = "In file grace period on"; 3321590Srgrimes else 3331590Srgrimes msgi = "Over file quota on"; 33495624Smarkm } 3351590Srgrimes msgb = (char *)0; 3361590Srgrimes if (qup->dqblk.dqb_bhardlimit && 3371590Srgrimes qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) 3381590Srgrimes msgb = "Block limit reached on"; 3391590Srgrimes else if (qup->dqblk.dqb_bsoftlimit && 34095624Smarkm qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 3411590Srgrimes if (qup->dqblk.dqb_btime > now) 3421590Srgrimes msgb = "In block grace period on"; 3431590Srgrimes else 3441590Srgrimes msgb = "Over block quota on"; 34595624Smarkm } 3461590Srgrimes if (qflag) { 3471590Srgrimes if ((msgi != (char *)0 || msgb != (char *)0) && 3481590Srgrimes lines++ == 0) 3491590Srgrimes heading(type, id, name, ""); 3501590Srgrimes if (msgi != (char *)0) 3511590Srgrimes printf("\t%s %s\n", msgi, qup->fsname); 3521590Srgrimes if (msgb != (char *)0) 3531590Srgrimes printf("\t%s %s\n", msgb, qup->fsname); 3541590Srgrimes continue; 3551590Srgrimes } 3561590Srgrimes if (vflag || 3571590Srgrimes qup->dqblk.dqb_curblocks || 3581590Srgrimes qup->dqblk.dqb_curinodes) { 3591590Srgrimes if (lines++ == 0) 3601590Srgrimes heading(type, id, name, ""); 36113236Sgraichen nam = qup->fsname; 36213236Sgraichen if (strlen(qup->fsname) > 15) { 36313236Sgraichen printf("%s\n", qup->fsname); 36413236Sgraichen nam = ""; 36513236Sgraichen } 3668327Sbde printf("%15s%8lu%c%7lu%8lu%8s" 36713236Sgraichen , nam 36813365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_curblocks) 36913365Sgraichen / 1024) 3701590Srgrimes , (msgb == (char *)0) ? ' ' : '*' 37113365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_bsoftlimit) 37213365Sgraichen / 1024) 37313365Sgraichen , (u_long) (dbtob(qup->dqblk.dqb_bhardlimit) 37413365Sgraichen / 1024) 3751590Srgrimes , (msgb == (char *)0) ? "" 37613236Sgraichen :timeprt(qup->dqblk.dqb_btime)); 37713365Sgraichen printf("%8lu%c%7lu%8lu%8s\n" 378101544Siedowse , (u_long)qup->dqblk.dqb_curinodes 3791590Srgrimes , (msgi == (char *)0) ? ' ' : '*' 380101544Siedowse , (u_long)qup->dqblk.dqb_isoftlimit 381101544Siedowse , (u_long)qup->dqblk.dqb_ihardlimit 3821590Srgrimes , (msgi == (char *)0) ? "" 3831590Srgrimes : timeprt(qup->dqblk.dqb_itime) 3841590Srgrimes ); 3851590Srgrimes continue; 3861590Srgrimes } 3871590Srgrimes } 3881590Srgrimes if (!qflag && lines == 0) 3891590Srgrimes heading(type, id, name, "none"); 3901590Srgrimes} 3911590Srgrimes 39216379Salexstatic void 39395624Smarkmheading(int type, u_long id, const char *name, const char *tag) 3941590Srgrimes{ 3951590Srgrimes 39613365Sgraichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 3971590Srgrimes name, *qfextension[type], id, tag); 3981590Srgrimes if (!qflag && tag[0] == '\0') { 3991590Srgrimes printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 4001590Srgrimes , "Filesystem" 40177047Spirzyk , "usage" 4021590Srgrimes , "quota" 4031590Srgrimes , "limit" 4041590Srgrimes , "grace" 4051590Srgrimes , "files" 4061590Srgrimes , "quota" 4071590Srgrimes , "limit" 4081590Srgrimes , "grace" 4091590Srgrimes ); 4101590Srgrimes } 4111590Srgrimes} 4121590Srgrimes 4131590Srgrimes/* 4141590Srgrimes * Calculate the grace period and return a printable string for it. 4151590Srgrimes */ 41695624Smarkmstatic const char * 41795624Smarkmtimeprt(time_t seconds) 4181590Srgrimes{ 4191590Srgrimes time_t hours, minutes; 4201590Srgrimes static char buf[20]; 4211590Srgrimes static time_t now; 4221590Srgrimes 4231590Srgrimes if (now == 0) 4241590Srgrimes time(&now); 4251590Srgrimes if (now > seconds) 4261590Srgrimes return ("none"); 4271590Srgrimes seconds -= now; 4281590Srgrimes minutes = (seconds + 30) / 60; 4291590Srgrimes hours = (minutes + 30) / 60; 4301590Srgrimes if (hours >= 36) { 431101544Siedowse sprintf(buf, "%lddays", ((long)hours + 12) / 24); 4321590Srgrimes return (buf); 4331590Srgrimes } 4341590Srgrimes if (minutes >= 60) { 435101544Siedowse sprintf(buf, "%2ld:%ld", (long)minutes / 60, 436101544Siedowse (long)minutes % 60); 4371590Srgrimes return (buf); 4381590Srgrimes } 439101544Siedowse sprintf(buf, "%2ld", (long)minutes); 4401590Srgrimes return (buf); 4411590Srgrimes} 4421590Srgrimes 4431590Srgrimes/* 4441590Srgrimes * Collect the requested quota information. 4451590Srgrimes */ 44616379Salexstatic struct quotause * 44795624Smarkmgetprivs(long id, int quotatype) 4481590Srgrimes{ 449101544Siedowse struct quotause *qup, *quptail = NULL; 45095624Smarkm struct fstab *fs; 4511590Srgrimes struct quotause *quphead; 45213236Sgraichen struct statfs *fst; 45313236Sgraichen int nfst, i; 4541590Srgrimes 45513236Sgraichen qup = quphead = (struct quotause *)0; 45613236Sgraichen 45797764Siedowse nfst = getmntinfo(&fst, MNT_NOWAIT); 45827888Scharnier if (nfst == 0) 45927888Scharnier errx(2, "no filesystems mounted!"); 4601590Srgrimes setfsent(); 46113236Sgraichen for (i=0; i<nfst; i++) { 46213236Sgraichen if (qup == NULL) { 46313365Sgraichen if ((qup = (struct quotause *)malloc(sizeof *qup)) 46427888Scharnier == NULL) 46527888Scharnier errx(2, "out of memory"); 4661590Srgrimes } 46732651Sbde if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 468101545Siedowse if (lflag) 469101545Siedowse continue; 47095624Smarkm if (getnfsquota(&fst[i], qup, id, quotatype) 47113365Sgraichen == 0) 4721590Srgrimes continue; 47336880Sache } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 47413236Sgraichen /* 47513236Sgraichen * XXX 47613236Sgraichen * UFS filesystems must be in /etc/fstab, and must 47713236Sgraichen * indicate that they have quotas on (?!) This is quite 47813236Sgraichen * unlike SunOS where quotas can be enabled/disabled 47913236Sgraichen * on a filesystem independent of /etc/fstab, and it 48013236Sgraichen * will still print quotas for them. 48113236Sgraichen */ 48213236Sgraichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 4831590Srgrimes continue; 48495624Smarkm if (getufsquota(fs, qup, id, quotatype) == 0) 48513236Sgraichen continue; 48613236Sgraichen } else 48713236Sgraichen continue; 48813236Sgraichen strcpy(qup->fsname, fst[i].f_mntonname); 4891590Srgrimes if (quphead == NULL) 4901590Srgrimes quphead = qup; 4911590Srgrimes else 4921590Srgrimes quptail->next = qup; 4931590Srgrimes quptail = qup; 49413236Sgraichen quptail->next = 0; 49513236Sgraichen qup = NULL; 4961590Srgrimes } 49713236Sgraichen if (qup) 49813236Sgraichen free(qup); 4991590Srgrimes endfsent(); 5001590Srgrimes return (quphead); 5011590Srgrimes} 5021590Srgrimes 5031590Srgrimes/* 5041590Srgrimes * Check to see if a particular quota is to be enabled. 5051590Srgrimes */ 50616379Salexstatic int 50795624Smarkmufshasquota(struct fstab *fs, int type, char **qfnamep) 5081590Srgrimes{ 5091590Srgrimes static char initname, usrname[100], grpname[100]; 5101590Srgrimes static char buf[BUFSIZ]; 51113236Sgraichen char *opt, *cp; 5121590Srgrimes 5131590Srgrimes if (!initname) { 5141590Srgrimes sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 5151590Srgrimes sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 5161590Srgrimes initname = 1; 5171590Srgrimes } 5181590Srgrimes strcpy(buf, fs->fs_mntops); 5191590Srgrimes for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 52016379Salex if ((cp = index(opt, '='))) 5211590Srgrimes *cp++ = '\0'; 5221590Srgrimes if (type == USRQUOTA && strcmp(opt, usrname) == 0) 5231590Srgrimes break; 5241590Srgrimes if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 5251590Srgrimes break; 5261590Srgrimes } 5271590Srgrimes if (!opt) 5281590Srgrimes return (0); 5291590Srgrimes if (cp) { 5301590Srgrimes *qfnamep = cp; 5311590Srgrimes return (1); 5321590Srgrimes } 5331590Srgrimes (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 5341590Srgrimes *qfnamep = buf; 5351590Srgrimes return (1); 5361590Srgrimes} 5371590Srgrimes 53816379Salexstatic int 53995624Smarkmgetufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype) 54013236Sgraichen{ 54113236Sgraichen char *qfpathname; 54213236Sgraichen int fd, qcmd; 54313236Sgraichen 54413236Sgraichen qcmd = QCMD(Q_GETQUOTA, quotatype); 54513236Sgraichen if (!ufshasquota(fs, quotatype, &qfpathname)) 54613236Sgraichen return (0); 54713236Sgraichen 54816379Salex if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) { 54913236Sgraichen if ((fd = open(qfpathname, O_RDONLY)) < 0) { 55058618Scharnier warn("%s", qfpathname); 55113236Sgraichen return (0); 55213236Sgraichen } 55313236Sgraichen (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 55413236Sgraichen switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 55513236Sgraichen case 0: /* EOF */ 55613236Sgraichen /* 55713236Sgraichen * Convert implicit 0 quota (EOF) 55813236Sgraichen * into an explicit one (zero'ed dqblk) 55913236Sgraichen */ 56013236Sgraichen bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk)); 56113236Sgraichen break; 56213236Sgraichen case sizeof(struct dqblk): /* OK */ 56313236Sgraichen break; 56413236Sgraichen default: /* ERROR */ 56527888Scharnier warn("read error: %s", qfpathname); 56613236Sgraichen close(fd); 56713236Sgraichen return (0); 56813236Sgraichen } 56913236Sgraichen close(fd); 57013236Sgraichen } 57113236Sgraichen return (1); 57213236Sgraichen} 57313236Sgraichen 57416379Salexstatic int 57595624Smarkmgetnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype) 57613236Sgraichen{ 57713236Sgraichen struct getquota_args gq_args; 57813236Sgraichen struct getquota_rslt gq_rslt; 57913236Sgraichen struct dqblk *dqp = &qup->dqblk; 58013236Sgraichen struct timeval tv; 58113236Sgraichen char *cp; 58213236Sgraichen 58313236Sgraichen if (fst->f_flags & MNT_LOCAL) 58413236Sgraichen return (0); 58513236Sgraichen 58613236Sgraichen /* 58713236Sgraichen * rpc.rquotad does not support group quotas 58813236Sgraichen */ 58913236Sgraichen if (quotatype != USRQUOTA) 59013236Sgraichen return (0); 59113236Sgraichen 59213236Sgraichen /* 59313236Sgraichen * must be some form of "hostname:/path" 59413236Sgraichen */ 59513236Sgraichen cp = strchr(fst->f_mntfromname, ':'); 59613236Sgraichen if (cp == NULL) { 59758618Scharnier warnx("cannot find hostname for %s", fst->f_mntfromname); 59813236Sgraichen return (0); 59913236Sgraichen } 60013236Sgraichen 60113236Sgraichen *cp = '\0'; 60213236Sgraichen if (*(cp+1) != '/') { 60313236Sgraichen *cp = ':'; 60413236Sgraichen return (0); 60513236Sgraichen } 60613236Sgraichen 60797764Siedowse /* Avoid attempting the RPC for special amd(8) filesystems. */ 60897764Siedowse if (strncmp(fst->f_mntfromname, "pid", 3) == 0 && 60997764Siedowse strchr(fst->f_mntfromname, '@') != NULL) { 61097764Siedowse *cp = ':'; 61197764Siedowse return (0); 61297764Siedowse } 61397764Siedowse 61413236Sgraichen gq_args.gqa_pathp = cp + 1; 61513236Sgraichen gq_args.gqa_uid = id; 61613236Sgraichen if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS, 617101544Siedowse RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&gq_args, 618101544Siedowse (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) != 0) { 61913236Sgraichen *cp = ':'; 62013236Sgraichen return (0); 62113236Sgraichen } 62213236Sgraichen 62313236Sgraichen switch (gq_rslt.status) { 62413236Sgraichen case Q_NOQUOTA: 62513236Sgraichen break; 62613236Sgraichen case Q_EPERM: 62727888Scharnier warnx("quota permission error, host: %s", 62813236Sgraichen fst->f_mntfromname); 62913236Sgraichen break; 63013236Sgraichen case Q_OK: 63113236Sgraichen gettimeofday(&tv, NULL); 63213236Sgraichen /* blocks*/ 63313236Sgraichen dqp->dqb_bhardlimit = 63413236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * 63513236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 63613236Sgraichen dqp->dqb_bsoftlimit = 63713236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * 63813236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 63913236Sgraichen dqp->dqb_curblocks = 64013236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * 64113236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE; 64213236Sgraichen /* inodes */ 64313236Sgraichen dqp->dqb_ihardlimit = 64413236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit; 64513236Sgraichen dqp->dqb_isoftlimit = 64613236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit; 64713236Sgraichen dqp->dqb_curinodes = 64813236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; 64913236Sgraichen /* grace times */ 65013236Sgraichen dqp->dqb_btime = 65113236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft; 65213236Sgraichen dqp->dqb_itime = 65313236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft; 65413236Sgraichen *cp = ':'; 65513236Sgraichen return (1); 65613236Sgraichen default: 65758618Scharnier warnx("bad rpc result, host: %s", fst->f_mntfromname); 65813236Sgraichen break; 65913236Sgraichen } 66013236Sgraichen *cp = ':'; 66113236Sgraichen return (0); 66213236Sgraichen} 66313236Sgraichen 66416379Salexstatic int 66595624Smarkmcallaurpc(char *host, int prognum, int versnum, int procnum, 66695624Smarkm xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 66713236Sgraichen{ 66813236Sgraichen struct sockaddr_in server_addr; 66913236Sgraichen enum clnt_stat clnt_stat; 67013236Sgraichen struct hostent *hp; 67113236Sgraichen struct timeval timeout, tottimeout; 67213236Sgraichen 67313236Sgraichen CLIENT *client = NULL; 67495624Smarkm int sock = RPC_ANYSOCK; 67513236Sgraichen 67613236Sgraichen if ((hp = gethostbyname(host)) == NULL) 67713236Sgraichen return ((int) RPC_UNKNOWNHOST); 67813236Sgraichen timeout.tv_usec = 0; 67913236Sgraichen timeout.tv_sec = 6; 68058618Scharnier bcopy(hp->h_addr, &server_addr.sin_addr, 68195624Smarkm MIN(hp->h_length,(int)sizeof(server_addr.sin_addr))); 68213236Sgraichen server_addr.sin_family = AF_INET; 68313236Sgraichen server_addr.sin_port = 0; 68413236Sgraichen 68513236Sgraichen if ((client = clntudp_create(&server_addr, prognum, 68695624Smarkm versnum, timeout, &sock)) == NULL) 68713236Sgraichen return ((int) rpc_createerr.cf_stat); 68813236Sgraichen 68913236Sgraichen client->cl_auth = authunix_create_default(); 69013236Sgraichen tottimeout.tv_sec = 25; 69113236Sgraichen tottimeout.tv_usec = 0; 69213236Sgraichen clnt_stat = clnt_call(client, procnum, inproc, in, 69313236Sgraichen outproc, out, tottimeout); 69413236Sgraichen 69513236Sgraichen return ((int) clnt_stat); 69613236Sgraichen} 69713236Sgraichen 69816379Salexstatic int 69995624Smarkmalldigits(char *s) 7001590Srgrimes{ 70195624Smarkm int c; 7021590Srgrimes 7031590Srgrimes c = *s++; 7041590Srgrimes do { 7051590Srgrimes if (!isdigit(c)) 7061590Srgrimes return (0); 70716379Salex } while ((c = *s++)); 7081590Srgrimes return (1); 7091590Srgrimes} 710