quota.c revision 163599
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 163599 2006-10-21 23:57:38Z ru $"); 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> 70163599Sru#include <libutil.h> 7195624Smarkm#include <netdb.h> 7227888Scharnier#include <pwd.h> 731590Srgrimes#include <stdio.h> 7413236Sgraichen#include <stdlib.h> 7513236Sgraichen#include <string.h> 7616379Salex#include <unistd.h> 771590Srgrimes 7895624Smarkmconst char *qfname = QUOTAFILENAME; 7995624Smarkmconst char *qfextension[] = INITQFNAMES; 8013236Sgraichen 811590Srgrimesstruct quotause { 821590Srgrimes struct quotause *next; 831590Srgrimes long flags; 841590Srgrimes struct dqblk dqblk; 851590Srgrimes char fsname[MAXPATHLEN + 1]; 8613236Sgraichen}; 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 void showusrname(char *name); 9416379Salexstatic void showgrpname(char *name); 9595624Smarkmstatic void showquotas(int type, u_long id, const char *name); 9695624Smarkmstatic void heading(int type, u_long id, const char *name, const char *tag); 9716379Salexstatic int ufshasquota(struct fstab *fs, int type, char **qfnamep); 9895624Smarkmstatic int getufsquota(struct fstab *fs, struct quotause *qup, long id, 9995624Smarkm int quotatype); 10095624Smarkmstatic int getnfsquota(struct statfs *fst, struct quotause *qup, long id, 10195624Smarkm int quotatype); 10216379Salexstatic int callaurpc(char *host, int prognum, int versnum, int procnum, 10395624Smarkm xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10416379Salexstatic int alldigits(char *s); 10513236Sgraichen 106163599Sruint hflag; 107101545Siedowseint lflag; 1081590Srgrimesint qflag; 1091590Srgrimesint vflag; 1101590Srgrimes 11116379Salexint 11295624Smarkmmain(int argc, char *argv[]) 1131590Srgrimes{ 11413236Sgraichen int ngroups; 11513236Sgraichen gid_t mygid, gidset[NGROUPS]; 116133258Sstefanf int i, ch, gflag = 0, uflag = 0; 1171590Srgrimes 118163599Sru while ((ch = getopt(argc, argv, "ghlquv")) != -1) { 1191590Srgrimes switch(ch) { 1201590Srgrimes case 'g': 1211590Srgrimes gflag++; 1221590Srgrimes break; 123163599Sru case 'h': 124163599Sru hflag++; 125163599Sru break; 126101545Siedowse case 'l': 127101545Siedowse lflag++; 128101545Siedowse break; 129101544Siedowse case 'q': 130101544Siedowse qflag++; 131101544Siedowse break; 1321590Srgrimes case 'u': 1331590Srgrimes uflag++; 1341590Srgrimes break; 1351590Srgrimes case 'v': 1361590Srgrimes vflag++; 1371590Srgrimes break; 1381590Srgrimes default: 1391590Srgrimes usage(); 1401590Srgrimes } 1411590Srgrimes } 1421590Srgrimes argc -= optind; 1431590Srgrimes argv += optind; 1441590Srgrimes if (!uflag && !gflag) 1451590Srgrimes uflag++; 1461590Srgrimes if (argc == 0) { 1471590Srgrimes if (uflag) 1481590Srgrimes showuid(getuid()); 1491590Srgrimes if (gflag) { 15013236Sgraichen mygid = getgid(); 1511590Srgrimes ngroups = getgroups(NGROUPS, gidset); 15227888Scharnier if (ngroups < 0) 15327888Scharnier err(1, "getgroups"); 15413236Sgraichen showgid(mygid); 15513236Sgraichen for (i = 0; i < ngroups; i++) 15613236Sgraichen if (gidset[i] != mygid) 15713236Sgraichen showgid(gidset[i]); 1581590Srgrimes } 15916379Salex return(0); 1601590Srgrimes } 1611590Srgrimes if (uflag && gflag) 1621590Srgrimes usage(); 1631590Srgrimes if (uflag) { 1641590Srgrimes for (; argc > 0; argc--, argv++) { 1651590Srgrimes if (alldigits(*argv)) 1661590Srgrimes showuid(atoi(*argv)); 1671590Srgrimes else 1681590Srgrimes showusrname(*argv); 1691590Srgrimes } 17016379Salex return(0); 1711590Srgrimes } 1721590Srgrimes if (gflag) { 1731590Srgrimes for (; argc > 0; argc--, argv++) { 1741590Srgrimes if (alldigits(*argv)) 1751590Srgrimes showgid(atoi(*argv)); 1761590Srgrimes else 1771590Srgrimes showgrpname(*argv); 1781590Srgrimes } 1791590Srgrimes } 18016379Salex return(0); 1811590Srgrimes} 1821590Srgrimes 18316379Salexstatic void 18495624Smarkmusage(void) 1851590Srgrimes{ 1861590Srgrimes 1871590Srgrimes fprintf(stderr, "%s\n%s\n%s\n", 188163599Sru "usage: quota [-ghlu] [-v | -q]", 189163599Sru " quota [-hlu] [-v | -q] user ...", 190163599Sru " quota -g [-hl] [-v | -q] group ..."); 1911590Srgrimes exit(1); 1921590Srgrimes} 1931590Srgrimes 1941590Srgrimes/* 1951590Srgrimes * Print out quotas for a specified user identifier. 1961590Srgrimes */ 19716379Salexstatic void 19895624Smarkmshowuid(u_long uid) 1991590Srgrimes{ 2001590Srgrimes struct passwd *pwd = getpwuid(uid); 20195624Smarkm const char *name; 2021590Srgrimes 2031590Srgrimes if (pwd == NULL) 2041590Srgrimes name = "(no account)"; 2051590Srgrimes else 2061590Srgrimes name = pwd->pw_name; 2071590Srgrimes showquotas(USRQUOTA, uid, name); 2081590Srgrimes} 2091590Srgrimes 2101590Srgrimes/* 2111590Srgrimes * Print out quotas for a specifed user name. 2121590Srgrimes */ 21316379Salexstatic void 21495624Smarkmshowusrname(char *name) 2151590Srgrimes{ 2161590Srgrimes struct passwd *pwd = getpwnam(name); 2171590Srgrimes 2181590Srgrimes if (pwd == NULL) { 21927888Scharnier warnx("%s: unknown user", name); 2201590Srgrimes return; 2211590Srgrimes } 2221590Srgrimes showquotas(USRQUOTA, pwd->pw_uid, name); 2231590Srgrimes} 2241590Srgrimes 2251590Srgrimes/* 2261590Srgrimes * Print out quotas for a specified group identifier. 2271590Srgrimes */ 22816379Salexstatic void 22995624Smarkmshowgid(u_long gid) 2301590Srgrimes{ 2311590Srgrimes struct group *grp = getgrgid(gid); 23295624Smarkm const char *name; 2331590Srgrimes 2341590Srgrimes if (grp == NULL) 2351590Srgrimes name = "(no entry)"; 2361590Srgrimes else 2371590Srgrimes name = grp->gr_name; 2381590Srgrimes showquotas(GRPQUOTA, gid, name); 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimes/* 2421590Srgrimes * Print out quotas for a specifed group name. 2431590Srgrimes */ 24416379Salexstatic void 24595624Smarkmshowgrpname(char *name) 2461590Srgrimes{ 2471590Srgrimes struct group *grp = getgrnam(name); 2481590Srgrimes 2491590Srgrimes if (grp == NULL) { 25027888Scharnier warnx("%s: unknown group", name); 2511590Srgrimes return; 2521590Srgrimes } 2531590Srgrimes showquotas(GRPQUOTA, grp->gr_gid, name); 2541590Srgrimes} 2551590Srgrimes 25616379Salexstatic void 257163599Sruprthumanval(int len, int64_t bytes) 258163599Sru{ 259163599Sru char buf[len + 1]; 260163599Sru 261163599Sru humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, 262163599Sru HN_B | HN_NOSPACE | HN_DECIMAL); 263163599Sru 264163599Sru (void)printf(" %*s", len, buf); 265163599Sru} 266163599Sru 267163599Srustatic void 26895624Smarkmshowquotas(int type, u_long id, const char *name) 2691590Srgrimes{ 27095624Smarkm struct quotause *qup; 27113236Sgraichen struct quotause *quplist; 27295624Smarkm const char *msgi, *msgb; 27395624Smarkm const char *nam; 27416379Salex int lines = 0; 2751590Srgrimes static time_t now; 2761590Srgrimes 2771590Srgrimes if (now == 0) 2781590Srgrimes time(&now); 2791590Srgrimes quplist = getprivs(id, type); 2801590Srgrimes for (qup = quplist; qup; qup = qup->next) { 2811590Srgrimes if (!vflag && 2821590Srgrimes qup->dqblk.dqb_isoftlimit == 0 && 2831590Srgrimes qup->dqblk.dqb_ihardlimit == 0 && 2841590Srgrimes qup->dqblk.dqb_bsoftlimit == 0 && 2851590Srgrimes qup->dqblk.dqb_bhardlimit == 0) 2861590Srgrimes continue; 2871590Srgrimes msgi = (char *)0; 2881590Srgrimes if (qup->dqblk.dqb_ihardlimit && 2891590Srgrimes qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) 2901590Srgrimes msgi = "File limit reached on"; 2911590Srgrimes else if (qup->dqblk.dqb_isoftlimit && 29295624Smarkm qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 2931590Srgrimes if (qup->dqblk.dqb_itime > now) 2941590Srgrimes msgi = "In file grace period on"; 2951590Srgrimes else 2961590Srgrimes msgi = "Over file quota on"; 29795624Smarkm } 2981590Srgrimes msgb = (char *)0; 2991590Srgrimes if (qup->dqblk.dqb_bhardlimit && 3001590Srgrimes qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) 3011590Srgrimes msgb = "Block limit reached on"; 3021590Srgrimes else if (qup->dqblk.dqb_bsoftlimit && 30395624Smarkm qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 3041590Srgrimes if (qup->dqblk.dqb_btime > now) 3051590Srgrimes msgb = "In block grace period on"; 3061590Srgrimes else 3071590Srgrimes msgb = "Over block quota on"; 30895624Smarkm } 3091590Srgrimes if (qflag) { 3101590Srgrimes if ((msgi != (char *)0 || msgb != (char *)0) && 3111590Srgrimes lines++ == 0) 3121590Srgrimes heading(type, id, name, ""); 3131590Srgrimes if (msgi != (char *)0) 3141590Srgrimes printf("\t%s %s\n", msgi, qup->fsname); 3151590Srgrimes if (msgb != (char *)0) 3161590Srgrimes printf("\t%s %s\n", msgb, qup->fsname); 3171590Srgrimes continue; 3181590Srgrimes } 3191590Srgrimes if (vflag || 3201590Srgrimes qup->dqblk.dqb_curblocks || 3211590Srgrimes qup->dqblk.dqb_curinodes) { 3221590Srgrimes if (lines++ == 0) 3231590Srgrimes heading(type, id, name, ""); 32413236Sgraichen nam = qup->fsname; 32513236Sgraichen if (strlen(qup->fsname) > 15) { 32613236Sgraichen printf("%s\n", qup->fsname); 32713236Sgraichen nam = ""; 32813236Sgraichen } 329163599Sru printf("%15s", nam); 330163599Sru if (hflag) { 331163599Sru prthumanval(7, dbtob(qup->dqblk.dqb_curblocks)); 332163599Sru printf("%c", (msgb == (char *)0) ? ' ' : '*'); 333163599Sru prthumanval(6, dbtob(qup->dqblk.dqb_bsoftlimit)); 334163599Sru prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit)); 335163599Sru } else { 336163599Sru printf("%8lu%c%7lu%8lu" 337163599Sru , (u_long) (dbtob(qup->dqblk.dqb_curblocks) 338163599Sru / 1024) 339163599Sru , (msgb == (char *)0) ? ' ' : '*' 340163599Sru , (u_long) (dbtob(qup->dqblk.dqb_bsoftlimit) 341163599Sru / 1024) 342163599Sru , (u_long) (dbtob(qup->dqblk.dqb_bhardlimit) 343163599Sru / 1024)); 344163599Sru } 345163599Sru printf("%8s%8lu%c%7lu%8lu%8s\n" 3461590Srgrimes , (msgb == (char *)0) ? "" 347163599Sru :timeprt(qup->dqblk.dqb_btime) 348101544Siedowse , (u_long)qup->dqblk.dqb_curinodes 3491590Srgrimes , (msgi == (char *)0) ? ' ' : '*' 350101544Siedowse , (u_long)qup->dqblk.dqb_isoftlimit 351101544Siedowse , (u_long)qup->dqblk.dqb_ihardlimit 3521590Srgrimes , (msgi == (char *)0) ? "" 3531590Srgrimes : timeprt(qup->dqblk.dqb_itime) 3541590Srgrimes ); 3551590Srgrimes continue; 3561590Srgrimes } 3571590Srgrimes } 3581590Srgrimes if (!qflag && lines == 0) 3591590Srgrimes heading(type, id, name, "none"); 3601590Srgrimes} 3611590Srgrimes 36216379Salexstatic void 36395624Smarkmheading(int type, u_long id, const char *name, const char *tag) 3641590Srgrimes{ 3651590Srgrimes 36613365Sgraichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 3671590Srgrimes name, *qfextension[type], id, tag); 3681590Srgrimes if (!qflag && tag[0] == '\0') { 3691590Srgrimes printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 3701590Srgrimes , "Filesystem" 37177047Spirzyk , "usage" 3721590Srgrimes , "quota" 3731590Srgrimes , "limit" 3741590Srgrimes , "grace" 3751590Srgrimes , "files" 3761590Srgrimes , "quota" 3771590Srgrimes , "limit" 3781590Srgrimes , "grace" 3791590Srgrimes ); 3801590Srgrimes } 3811590Srgrimes} 3821590Srgrimes 3831590Srgrimes/* 3841590Srgrimes * Calculate the grace period and return a printable string for it. 3851590Srgrimes */ 38695624Smarkmstatic const char * 38795624Smarkmtimeprt(time_t seconds) 3881590Srgrimes{ 3891590Srgrimes time_t hours, minutes; 3901590Srgrimes static char buf[20]; 3911590Srgrimes static time_t now; 3921590Srgrimes 3931590Srgrimes if (now == 0) 3941590Srgrimes time(&now); 3951590Srgrimes if (now > seconds) 3961590Srgrimes return ("none"); 3971590Srgrimes seconds -= now; 3981590Srgrimes minutes = (seconds + 30) / 60; 3991590Srgrimes hours = (minutes + 30) / 60; 4001590Srgrimes if (hours >= 36) { 401101544Siedowse sprintf(buf, "%lddays", ((long)hours + 12) / 24); 4021590Srgrimes return (buf); 4031590Srgrimes } 4041590Srgrimes if (minutes >= 60) { 405101544Siedowse sprintf(buf, "%2ld:%ld", (long)minutes / 60, 406101544Siedowse (long)minutes % 60); 4071590Srgrimes return (buf); 4081590Srgrimes } 409101544Siedowse sprintf(buf, "%2ld", (long)minutes); 4101590Srgrimes return (buf); 4111590Srgrimes} 4121590Srgrimes 4131590Srgrimes/* 4141590Srgrimes * Collect the requested quota information. 4151590Srgrimes */ 41616379Salexstatic struct quotause * 41795624Smarkmgetprivs(long id, int quotatype) 4181590Srgrimes{ 419101544Siedowse struct quotause *qup, *quptail = NULL; 42095624Smarkm struct fstab *fs; 4211590Srgrimes struct quotause *quphead; 42213236Sgraichen struct statfs *fst; 42313236Sgraichen int nfst, i; 4241590Srgrimes 42513236Sgraichen qup = quphead = (struct quotause *)0; 42613236Sgraichen 42797764Siedowse nfst = getmntinfo(&fst, MNT_NOWAIT); 42827888Scharnier if (nfst == 0) 42927888Scharnier errx(2, "no filesystems mounted!"); 4301590Srgrimes setfsent(); 43113236Sgraichen for (i=0; i<nfst; i++) { 43213236Sgraichen if (qup == NULL) { 43313365Sgraichen if ((qup = (struct quotause *)malloc(sizeof *qup)) 43427888Scharnier == NULL) 43527888Scharnier errx(2, "out of memory"); 4361590Srgrimes } 43732651Sbde if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 438101545Siedowse if (lflag) 439101545Siedowse continue; 44095624Smarkm if (getnfsquota(&fst[i], qup, id, quotatype) 44113365Sgraichen == 0) 4421590Srgrimes continue; 44336880Sache } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 44413236Sgraichen /* 44513236Sgraichen * XXX 44613236Sgraichen * UFS filesystems must be in /etc/fstab, and must 44713236Sgraichen * indicate that they have quotas on (?!) This is quite 44813236Sgraichen * unlike SunOS where quotas can be enabled/disabled 44913236Sgraichen * on a filesystem independent of /etc/fstab, and it 45013236Sgraichen * will still print quotas for them. 45113236Sgraichen */ 45213236Sgraichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 4531590Srgrimes continue; 45495624Smarkm if (getufsquota(fs, qup, id, quotatype) == 0) 45513236Sgraichen continue; 45613236Sgraichen } else 45713236Sgraichen continue; 45813236Sgraichen strcpy(qup->fsname, fst[i].f_mntonname); 4591590Srgrimes if (quphead == NULL) 4601590Srgrimes quphead = qup; 4611590Srgrimes else 4621590Srgrimes quptail->next = qup; 4631590Srgrimes quptail = qup; 46413236Sgraichen quptail->next = 0; 46513236Sgraichen qup = NULL; 4661590Srgrimes } 46713236Sgraichen if (qup) 46813236Sgraichen free(qup); 4691590Srgrimes endfsent(); 4701590Srgrimes return (quphead); 4711590Srgrimes} 4721590Srgrimes 4731590Srgrimes/* 4741590Srgrimes * Check to see if a particular quota is to be enabled. 4751590Srgrimes */ 47616379Salexstatic int 47795624Smarkmufshasquota(struct fstab *fs, int type, char **qfnamep) 4781590Srgrimes{ 4791590Srgrimes static char initname, usrname[100], grpname[100]; 4801590Srgrimes static char buf[BUFSIZ]; 48113236Sgraichen char *opt, *cp; 4821590Srgrimes 4831590Srgrimes if (!initname) { 4841590Srgrimes sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 4851590Srgrimes sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 4861590Srgrimes initname = 1; 4871590Srgrimes } 4881590Srgrimes strcpy(buf, fs->fs_mntops); 4891590Srgrimes for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 49016379Salex if ((cp = index(opt, '='))) 4911590Srgrimes *cp++ = '\0'; 4921590Srgrimes if (type == USRQUOTA && strcmp(opt, usrname) == 0) 4931590Srgrimes break; 4941590Srgrimes if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 4951590Srgrimes break; 4961590Srgrimes } 4971590Srgrimes if (!opt) 4981590Srgrimes return (0); 4991590Srgrimes if (cp) { 5001590Srgrimes *qfnamep = cp; 5011590Srgrimes return (1); 5021590Srgrimes } 5031590Srgrimes (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 5041590Srgrimes *qfnamep = buf; 5051590Srgrimes return (1); 5061590Srgrimes} 5071590Srgrimes 50816379Salexstatic int 50995624Smarkmgetufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype) 51013236Sgraichen{ 51113236Sgraichen char *qfpathname; 51213236Sgraichen int fd, qcmd; 51313236Sgraichen 51413236Sgraichen qcmd = QCMD(Q_GETQUOTA, quotatype); 51513236Sgraichen if (!ufshasquota(fs, quotatype, &qfpathname)) 51613236Sgraichen return (0); 51713236Sgraichen 51816379Salex if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) { 51913236Sgraichen if ((fd = open(qfpathname, O_RDONLY)) < 0) { 52058618Scharnier warn("%s", qfpathname); 52113236Sgraichen return (0); 52213236Sgraichen } 52313236Sgraichen (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 52413236Sgraichen switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 52513236Sgraichen case 0: /* EOF */ 52613236Sgraichen /* 52713236Sgraichen * Convert implicit 0 quota (EOF) 52813236Sgraichen * into an explicit one (zero'ed dqblk) 52913236Sgraichen */ 53013236Sgraichen bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk)); 53113236Sgraichen break; 53213236Sgraichen case sizeof(struct dqblk): /* OK */ 53313236Sgraichen break; 53413236Sgraichen default: /* ERROR */ 53527888Scharnier warn("read error: %s", qfpathname); 53613236Sgraichen close(fd); 53713236Sgraichen return (0); 53813236Sgraichen } 53913236Sgraichen close(fd); 54013236Sgraichen } 54113236Sgraichen return (1); 54213236Sgraichen} 54313236Sgraichen 54416379Salexstatic int 54595624Smarkmgetnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype) 54613236Sgraichen{ 54713236Sgraichen struct getquota_args gq_args; 54813236Sgraichen struct getquota_rslt gq_rslt; 54913236Sgraichen struct dqblk *dqp = &qup->dqblk; 55013236Sgraichen struct timeval tv; 55113236Sgraichen char *cp; 55213236Sgraichen 55313236Sgraichen if (fst->f_flags & MNT_LOCAL) 55413236Sgraichen return (0); 55513236Sgraichen 55613236Sgraichen /* 55713236Sgraichen * rpc.rquotad does not support group quotas 55813236Sgraichen */ 55913236Sgraichen if (quotatype != USRQUOTA) 56013236Sgraichen return (0); 56113236Sgraichen 56213236Sgraichen /* 56313236Sgraichen * must be some form of "hostname:/path" 56413236Sgraichen */ 56513236Sgraichen cp = strchr(fst->f_mntfromname, ':'); 56613236Sgraichen if (cp == NULL) { 56758618Scharnier warnx("cannot find hostname for %s", fst->f_mntfromname); 56813236Sgraichen return (0); 56913236Sgraichen } 57013236Sgraichen 57113236Sgraichen *cp = '\0'; 57213236Sgraichen if (*(cp+1) != '/') { 57313236Sgraichen *cp = ':'; 57413236Sgraichen return (0); 57513236Sgraichen } 57613236Sgraichen 57797764Siedowse /* Avoid attempting the RPC for special amd(8) filesystems. */ 57897764Siedowse if (strncmp(fst->f_mntfromname, "pid", 3) == 0 && 57997764Siedowse strchr(fst->f_mntfromname, '@') != NULL) { 58097764Siedowse *cp = ':'; 58197764Siedowse return (0); 58297764Siedowse } 58397764Siedowse 58413236Sgraichen gq_args.gqa_pathp = cp + 1; 58513236Sgraichen gq_args.gqa_uid = id; 58613236Sgraichen if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS, 587101544Siedowse RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&gq_args, 588101544Siedowse (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) != 0) { 58913236Sgraichen *cp = ':'; 59013236Sgraichen return (0); 59113236Sgraichen } 59213236Sgraichen 59313236Sgraichen switch (gq_rslt.status) { 59413236Sgraichen case Q_NOQUOTA: 59513236Sgraichen break; 59613236Sgraichen case Q_EPERM: 59727888Scharnier warnx("quota permission error, host: %s", 59813236Sgraichen fst->f_mntfromname); 59913236Sgraichen break; 60013236Sgraichen case Q_OK: 60113236Sgraichen gettimeofday(&tv, NULL); 60213236Sgraichen /* blocks*/ 60313236Sgraichen dqp->dqb_bhardlimit = 60413236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * 605118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 60613236Sgraichen dqp->dqb_bsoftlimit = 60713236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * 608118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 60913236Sgraichen dqp->dqb_curblocks = 61013236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * 611118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 61213236Sgraichen /* inodes */ 61313236Sgraichen dqp->dqb_ihardlimit = 61413236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit; 61513236Sgraichen dqp->dqb_isoftlimit = 61613236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit; 61713236Sgraichen dqp->dqb_curinodes = 61813236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; 61913236Sgraichen /* grace times */ 62013236Sgraichen dqp->dqb_btime = 62113236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft; 62213236Sgraichen dqp->dqb_itime = 62313236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft; 62413236Sgraichen *cp = ':'; 62513236Sgraichen return (1); 62613236Sgraichen default: 62758618Scharnier warnx("bad rpc result, host: %s", fst->f_mntfromname); 62813236Sgraichen break; 62913236Sgraichen } 63013236Sgraichen *cp = ':'; 63113236Sgraichen return (0); 63213236Sgraichen} 63313236Sgraichen 63416379Salexstatic int 63595624Smarkmcallaurpc(char *host, int prognum, int versnum, int procnum, 63695624Smarkm xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 63713236Sgraichen{ 63813236Sgraichen struct sockaddr_in server_addr; 63913236Sgraichen enum clnt_stat clnt_stat; 64013236Sgraichen struct hostent *hp; 64113236Sgraichen struct timeval timeout, tottimeout; 64213236Sgraichen 64313236Sgraichen CLIENT *client = NULL; 64495624Smarkm int sock = RPC_ANYSOCK; 64513236Sgraichen 64613236Sgraichen if ((hp = gethostbyname(host)) == NULL) 64713236Sgraichen return ((int) RPC_UNKNOWNHOST); 64813236Sgraichen timeout.tv_usec = 0; 64913236Sgraichen timeout.tv_sec = 6; 65058618Scharnier bcopy(hp->h_addr, &server_addr.sin_addr, 65195624Smarkm MIN(hp->h_length,(int)sizeof(server_addr.sin_addr))); 65213236Sgraichen server_addr.sin_family = AF_INET; 65313236Sgraichen server_addr.sin_port = 0; 65413236Sgraichen 65513236Sgraichen if ((client = clntudp_create(&server_addr, prognum, 65695624Smarkm versnum, timeout, &sock)) == NULL) 65713236Sgraichen return ((int) rpc_createerr.cf_stat); 65813236Sgraichen 65913236Sgraichen client->cl_auth = authunix_create_default(); 66013236Sgraichen tottimeout.tv_sec = 25; 66113236Sgraichen tottimeout.tv_usec = 0; 66213236Sgraichen clnt_stat = clnt_call(client, procnum, inproc, in, 66313236Sgraichen outproc, out, tottimeout); 66413236Sgraichen 66513236Sgraichen return ((int) clnt_stat); 66613236Sgraichen} 66713236Sgraichen 66816379Salexstatic int 66995624Smarkmalldigits(char *s) 6701590Srgrimes{ 67195624Smarkm int c; 6721590Srgrimes 6731590Srgrimes c = *s++; 6741590Srgrimes do { 6751590Srgrimes if (!isdigit(c)) 6761590Srgrimes return (0); 67716379Salex } while ((c = *s++)); 6781590Srgrimes return (1); 6791590Srgrimes} 680