quota.c revision 166485
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 166485 2007-02-04 06:33:15Z mpp $"); 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); 91166388Smppstatic int showuid(u_long uid); 92166388Smppstatic int showgid(u_long gid); 93166388Smppstatic int showusrname(char *name); 94166388Smppstatic int showgrpname(char *name); 95166388Smppstatic int 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]; 116166388Smpp int i, ch, gflag = 0, uflag = 0, errflag = 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) 148166388Smpp errflag += showuid(getuid()); 1491590Srgrimes if (gflag) { 15013236Sgraichen mygid = getgid(); 1511590Srgrimes ngroups = getgroups(NGROUPS, gidset); 15227888Scharnier if (ngroups < 0) 15327888Scharnier err(1, "getgroups"); 154166388Smpp errflag += showgid(mygid); 15513236Sgraichen for (i = 0; i < ngroups; i++) 15613236Sgraichen if (gidset[i] != mygid) 157166388Smpp errflag += showgid(gidset[i]); 1581590Srgrimes } 159166388Smpp return(errflag); 1601590Srgrimes } 1611590Srgrimes if (uflag && gflag) 1621590Srgrimes usage(); 1631590Srgrimes if (uflag) { 1641590Srgrimes for (; argc > 0; argc--, argv++) { 1651590Srgrimes if (alldigits(*argv)) 166166388Smpp errflag += showuid(atoi(*argv)); 1671590Srgrimes else 168166388Smpp errflag += showusrname(*argv); 1691590Srgrimes } 170166388Smpp return(errflag); 1711590Srgrimes } 1721590Srgrimes if (gflag) { 1731590Srgrimes for (; argc > 0; argc--, argv++) { 1741590Srgrimes if (alldigits(*argv)) 175166388Smpp errflag += showgid(atoi(*argv)); 1761590Srgrimes else 177166388Smpp errflag += showgrpname(*argv); 1781590Srgrimes } 1791590Srgrimes } 180166388Smpp return(errflag); 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 */ 197166388Smppstatic int 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; 207166388Smpp return(showquotas(USRQUOTA, uid, name)); 2081590Srgrimes} 2091590Srgrimes 2101590Srgrimes/* 2111590Srgrimes * Print out quotas for a specifed user name. 2121590Srgrimes */ 213166388Smppstatic int 21495624Smarkmshowusrname(char *name) 2151590Srgrimes{ 2161590Srgrimes struct passwd *pwd = getpwnam(name); 2171590Srgrimes 2181590Srgrimes if (pwd == NULL) { 21927888Scharnier warnx("%s: unknown user", name); 220166388Smpp return(1); 2211590Srgrimes } 222166388Smpp return(showquotas(USRQUOTA, pwd->pw_uid, name)); 2231590Srgrimes} 2241590Srgrimes 2251590Srgrimes/* 2261590Srgrimes * Print out quotas for a specified group identifier. 2271590Srgrimes */ 228166388Smppstatic int 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; 238166388Smpp return(showquotas(GRPQUOTA, gid, name)); 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimes/* 2421590Srgrimes * Print out quotas for a specifed group name. 2431590Srgrimes */ 244166388Smppstatic int 24595624Smarkmshowgrpname(char *name) 2461590Srgrimes{ 2471590Srgrimes struct group *grp = getgrnam(name); 2481590Srgrimes 2491590Srgrimes if (grp == NULL) { 25027888Scharnier warnx("%s: unknown group", name); 251166388Smpp return(1); 2521590Srgrimes } 253166388Smpp return(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 267166388Smppstatic int 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; 274166388Smpp int lines = 0, overquota = 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 && 289166388Smpp qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) { 290166388Smpp overquota++; 2911590Srgrimes msgi = "File limit reached on"; 292166388Smpp } 2931590Srgrimes else if (qup->dqblk.dqb_isoftlimit && 29495624Smarkm qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 295166388Smpp overquota++; 2961590Srgrimes if (qup->dqblk.dqb_itime > now) 2971590Srgrimes msgi = "In file grace period on"; 2981590Srgrimes else 2991590Srgrimes msgi = "Over file quota on"; 30095624Smarkm } 3011590Srgrimes msgb = (char *)0; 3021590Srgrimes if (qup->dqblk.dqb_bhardlimit && 303166388Smpp qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) { 304166388Smpp overquota++; 3051590Srgrimes msgb = "Block limit reached on"; 306166388Smpp } 3071590Srgrimes else if (qup->dqblk.dqb_bsoftlimit && 30895624Smarkm qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 309166388Smpp overquota++; 3101590Srgrimes if (qup->dqblk.dqb_btime > now) 3111590Srgrimes msgb = "In block grace period on"; 3121590Srgrimes else 3131590Srgrimes msgb = "Over block quota on"; 31495624Smarkm } 3151590Srgrimes if (qflag) { 3161590Srgrimes if ((msgi != (char *)0 || msgb != (char *)0) && 3171590Srgrimes lines++ == 0) 3181590Srgrimes heading(type, id, name, ""); 3191590Srgrimes if (msgi != (char *)0) 3201590Srgrimes printf("\t%s %s\n", msgi, qup->fsname); 3211590Srgrimes if (msgb != (char *)0) 3221590Srgrimes printf("\t%s %s\n", msgb, qup->fsname); 3231590Srgrimes continue; 3241590Srgrimes } 3251590Srgrimes if (vflag || 3261590Srgrimes qup->dqblk.dqb_curblocks || 3271590Srgrimes qup->dqblk.dqb_curinodes) { 3281590Srgrimes if (lines++ == 0) 3291590Srgrimes heading(type, id, name, ""); 33013236Sgraichen nam = qup->fsname; 33113236Sgraichen if (strlen(qup->fsname) > 15) { 33213236Sgraichen printf("%s\n", qup->fsname); 33313236Sgraichen nam = ""; 33413236Sgraichen } 335163599Sru printf("%15s", nam); 336163599Sru if (hflag) { 337163599Sru prthumanval(7, dbtob(qup->dqblk.dqb_curblocks)); 338163599Sru printf("%c", (msgb == (char *)0) ? ' ' : '*'); 339163599Sru prthumanval(6, dbtob(qup->dqblk.dqb_bsoftlimit)); 340163599Sru prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit)); 341163599Sru } else { 342163599Sru printf("%8lu%c%7lu%8lu" 343163599Sru , (u_long) (dbtob(qup->dqblk.dqb_curblocks) 344163599Sru / 1024) 345163599Sru , (msgb == (char *)0) ? ' ' : '*' 346163599Sru , (u_long) (dbtob(qup->dqblk.dqb_bsoftlimit) 347163599Sru / 1024) 348163599Sru , (u_long) (dbtob(qup->dqblk.dqb_bhardlimit) 349163599Sru / 1024)); 350163599Sru } 351163599Sru printf("%8s%8lu%c%7lu%8lu%8s\n" 3521590Srgrimes , (msgb == (char *)0) ? "" 353163599Sru :timeprt(qup->dqblk.dqb_btime) 354101544Siedowse , (u_long)qup->dqblk.dqb_curinodes 3551590Srgrimes , (msgi == (char *)0) ? ' ' : '*' 356101544Siedowse , (u_long)qup->dqblk.dqb_isoftlimit 357101544Siedowse , (u_long)qup->dqblk.dqb_ihardlimit 3581590Srgrimes , (msgi == (char *)0) ? "" 3591590Srgrimes : timeprt(qup->dqblk.dqb_itime) 3601590Srgrimes ); 3611590Srgrimes continue; 3621590Srgrimes } 3631590Srgrimes } 3641590Srgrimes if (!qflag && lines == 0) 3651590Srgrimes heading(type, id, name, "none"); 366166388Smpp return(overquota); 3671590Srgrimes} 3681590Srgrimes 36916379Salexstatic void 37095624Smarkmheading(int type, u_long id, const char *name, const char *tag) 3711590Srgrimes{ 3721590Srgrimes 37313365Sgraichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 3741590Srgrimes name, *qfextension[type], id, tag); 3751590Srgrimes if (!qflag && tag[0] == '\0') { 3761590Srgrimes printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 3771590Srgrimes , "Filesystem" 37877047Spirzyk , "usage" 3791590Srgrimes , "quota" 3801590Srgrimes , "limit" 3811590Srgrimes , "grace" 3821590Srgrimes , "files" 3831590Srgrimes , "quota" 3841590Srgrimes , "limit" 3851590Srgrimes , "grace" 3861590Srgrimes ); 3871590Srgrimes } 3881590Srgrimes} 3891590Srgrimes 3901590Srgrimes/* 3911590Srgrimes * Calculate the grace period and return a printable string for it. 3921590Srgrimes */ 39395624Smarkmstatic const char * 39495624Smarkmtimeprt(time_t seconds) 3951590Srgrimes{ 3961590Srgrimes time_t hours, minutes; 3971590Srgrimes static char buf[20]; 3981590Srgrimes static time_t now; 3991590Srgrimes 4001590Srgrimes if (now == 0) 4011590Srgrimes time(&now); 4021590Srgrimes if (now > seconds) 4031590Srgrimes return ("none"); 4041590Srgrimes seconds -= now; 4051590Srgrimes minutes = (seconds + 30) / 60; 4061590Srgrimes hours = (minutes + 30) / 60; 4071590Srgrimes if (hours >= 36) { 408101544Siedowse sprintf(buf, "%lddays", ((long)hours + 12) / 24); 4091590Srgrimes return (buf); 4101590Srgrimes } 4111590Srgrimes if (minutes >= 60) { 412101544Siedowse sprintf(buf, "%2ld:%ld", (long)minutes / 60, 413101544Siedowse (long)minutes % 60); 4141590Srgrimes return (buf); 4151590Srgrimes } 416101544Siedowse sprintf(buf, "%2ld", (long)minutes); 4171590Srgrimes return (buf); 4181590Srgrimes} 4191590Srgrimes 4201590Srgrimes/* 4211590Srgrimes * Collect the requested quota information. 4221590Srgrimes */ 42316379Salexstatic struct quotause * 42495624Smarkmgetprivs(long id, int quotatype) 4251590Srgrimes{ 426101544Siedowse struct quotause *qup, *quptail = NULL; 42795624Smarkm struct fstab *fs; 4281590Srgrimes struct quotause *quphead; 42913236Sgraichen struct statfs *fst; 43013236Sgraichen int nfst, i; 4311590Srgrimes 43213236Sgraichen qup = quphead = (struct quotause *)0; 43313236Sgraichen 43497764Siedowse nfst = getmntinfo(&fst, MNT_NOWAIT); 43527888Scharnier if (nfst == 0) 43627888Scharnier errx(2, "no filesystems mounted!"); 4371590Srgrimes setfsent(); 43813236Sgraichen for (i=0; i<nfst; i++) { 43913236Sgraichen if (qup == NULL) { 44013365Sgraichen if ((qup = (struct quotause *)malloc(sizeof *qup)) 44127888Scharnier == NULL) 44227888Scharnier errx(2, "out of memory"); 4431590Srgrimes } 44432651Sbde if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 445101545Siedowse if (lflag) 446101545Siedowse continue; 44795624Smarkm if (getnfsquota(&fst[i], qup, id, quotatype) 44813365Sgraichen == 0) 4491590Srgrimes continue; 45036880Sache } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 45113236Sgraichen /* 45213236Sgraichen * XXX 45313236Sgraichen * UFS filesystems must be in /etc/fstab, and must 45413236Sgraichen * indicate that they have quotas on (?!) This is quite 45513236Sgraichen * unlike SunOS where quotas can be enabled/disabled 45613236Sgraichen * on a filesystem independent of /etc/fstab, and it 45713236Sgraichen * will still print quotas for them. 45813236Sgraichen */ 45913236Sgraichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 4601590Srgrimes continue; 46195624Smarkm if (getufsquota(fs, qup, id, quotatype) == 0) 46213236Sgraichen continue; 46313236Sgraichen } else 46413236Sgraichen continue; 46513236Sgraichen strcpy(qup->fsname, fst[i].f_mntonname); 4661590Srgrimes if (quphead == NULL) 4671590Srgrimes quphead = qup; 4681590Srgrimes else 4691590Srgrimes quptail->next = qup; 4701590Srgrimes quptail = qup; 47113236Sgraichen quptail->next = 0; 47213236Sgraichen qup = NULL; 4731590Srgrimes } 47413236Sgraichen if (qup) 47513236Sgraichen free(qup); 4761590Srgrimes endfsent(); 4771590Srgrimes return (quphead); 4781590Srgrimes} 4791590Srgrimes 4801590Srgrimes/* 4811590Srgrimes * Check to see if a particular quota is to be enabled. 4821590Srgrimes */ 48316379Salexstatic int 48495624Smarkmufshasquota(struct fstab *fs, int type, char **qfnamep) 4851590Srgrimes{ 486166485Smpp char *opt; 487166485Smpp char *cp; 488166485Smpp struct statfs sfb; 4891590Srgrimes static char initname, usrname[100], grpname[100]; 4901590Srgrimes static char buf[BUFSIZ]; 4911590Srgrimes 4921590Srgrimes if (!initname) { 493166485Smpp (void)snprintf(usrname, sizeof(usrname), "%s%s", 494166485Smpp qfextension[USRQUOTA], qfname); 495166485Smpp (void)snprintf(grpname, sizeof(grpname), "%s%s", 496166485Smpp qfextension[GRPQUOTA], qfname); 4971590Srgrimes initname = 1; 4981590Srgrimes } 4991590Srgrimes strcpy(buf, fs->fs_mntops); 5001590Srgrimes for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 50116379Salex if ((cp = index(opt, '='))) 5021590Srgrimes *cp++ = '\0'; 5031590Srgrimes if (type == USRQUOTA && strcmp(opt, usrname) == 0) 5041590Srgrimes break; 5051590Srgrimes if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 5061590Srgrimes break; 5071590Srgrimes } 5081590Srgrimes if (!opt) 5091590Srgrimes return (0); 510166485Smpp if (cp) 5111590Srgrimes *qfnamep = cp; 512166485Smpp else { 513166485Smpp (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, 514166485Smpp qfname, qfextension[type]); 515166485Smpp *qfnamep = buf; 5161590Srgrimes } 517166485Smpp if (statfs(fs->fs_file, &sfb) != 0) { 518166485Smpp warn("cannot statfs mount point %s", fs->fs_file); 519166485Smpp return (0); 520166485Smpp } 521166485Smpp if (strcmp(fs->fs_file, sfb.f_mntonname)) { 522166485Smpp warnx("%s not mounted for %s quotas", fs->fs_file, 523166485Smpp type == USRQUOTA ? "user" : "group"); 524166485Smpp return (0); 525166485Smpp } 5261590Srgrimes return (1); 5271590Srgrimes} 5281590Srgrimes 52916379Salexstatic int 53095624Smarkmgetufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype) 53113236Sgraichen{ 53213236Sgraichen char *qfpathname; 53313236Sgraichen int fd, qcmd; 53413236Sgraichen 53513236Sgraichen qcmd = QCMD(Q_GETQUOTA, quotatype); 53613236Sgraichen if (!ufshasquota(fs, quotatype, &qfpathname)) 53713236Sgraichen return (0); 53813236Sgraichen 53916379Salex if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) { 54013236Sgraichen if ((fd = open(qfpathname, O_RDONLY)) < 0) { 54158618Scharnier warn("%s", qfpathname); 54213236Sgraichen return (0); 54313236Sgraichen } 54413236Sgraichen (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 54513236Sgraichen switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 54613236Sgraichen case 0: /* EOF */ 54713236Sgraichen /* 54813236Sgraichen * Convert implicit 0 quota (EOF) 54913236Sgraichen * into an explicit one (zero'ed dqblk) 55013236Sgraichen */ 55113236Sgraichen bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk)); 55213236Sgraichen break; 55313236Sgraichen case sizeof(struct dqblk): /* OK */ 55413236Sgraichen break; 55513236Sgraichen default: /* ERROR */ 55627888Scharnier warn("read error: %s", qfpathname); 55713236Sgraichen close(fd); 55813236Sgraichen return (0); 55913236Sgraichen } 56013236Sgraichen close(fd); 56113236Sgraichen } 56213236Sgraichen return (1); 56313236Sgraichen} 56413236Sgraichen 56516379Salexstatic int 56695624Smarkmgetnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype) 56713236Sgraichen{ 56813236Sgraichen struct getquota_args gq_args; 56913236Sgraichen struct getquota_rslt gq_rslt; 57013236Sgraichen struct dqblk *dqp = &qup->dqblk; 57113236Sgraichen struct timeval tv; 57213236Sgraichen char *cp; 57313236Sgraichen 57413236Sgraichen if (fst->f_flags & MNT_LOCAL) 57513236Sgraichen return (0); 57613236Sgraichen 57713236Sgraichen /* 57813236Sgraichen * rpc.rquotad does not support group quotas 57913236Sgraichen */ 58013236Sgraichen if (quotatype != USRQUOTA) 58113236Sgraichen return (0); 58213236Sgraichen 58313236Sgraichen /* 58413236Sgraichen * must be some form of "hostname:/path" 58513236Sgraichen */ 58613236Sgraichen cp = strchr(fst->f_mntfromname, ':'); 58713236Sgraichen if (cp == NULL) { 58858618Scharnier warnx("cannot find hostname for %s", fst->f_mntfromname); 58913236Sgraichen return (0); 59013236Sgraichen } 59113236Sgraichen 59213236Sgraichen *cp = '\0'; 59313236Sgraichen if (*(cp+1) != '/') { 59413236Sgraichen *cp = ':'; 59513236Sgraichen return (0); 59613236Sgraichen } 59713236Sgraichen 59897764Siedowse /* Avoid attempting the RPC for special amd(8) filesystems. */ 59997764Siedowse if (strncmp(fst->f_mntfromname, "pid", 3) == 0 && 60097764Siedowse strchr(fst->f_mntfromname, '@') != NULL) { 60197764Siedowse *cp = ':'; 60297764Siedowse return (0); 60397764Siedowse } 60497764Siedowse 60513236Sgraichen gq_args.gqa_pathp = cp + 1; 60613236Sgraichen gq_args.gqa_uid = id; 60713236Sgraichen if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS, 608101544Siedowse RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&gq_args, 609101544Siedowse (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) != 0) { 61013236Sgraichen *cp = ':'; 61113236Sgraichen return (0); 61213236Sgraichen } 61313236Sgraichen 61413236Sgraichen switch (gq_rslt.status) { 61513236Sgraichen case Q_NOQUOTA: 61613236Sgraichen break; 61713236Sgraichen case Q_EPERM: 61827888Scharnier warnx("quota permission error, host: %s", 61913236Sgraichen fst->f_mntfromname); 62013236Sgraichen break; 62113236Sgraichen case Q_OK: 62213236Sgraichen gettimeofday(&tv, NULL); 62313236Sgraichen /* blocks*/ 62413236Sgraichen dqp->dqb_bhardlimit = 62513236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * 626118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 62713236Sgraichen dqp->dqb_bsoftlimit = 62813236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * 629118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 63013236Sgraichen dqp->dqb_curblocks = 63113236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * 632118464Sdas (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 63313236Sgraichen /* inodes */ 63413236Sgraichen dqp->dqb_ihardlimit = 63513236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit; 63613236Sgraichen dqp->dqb_isoftlimit = 63713236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit; 63813236Sgraichen dqp->dqb_curinodes = 63913236Sgraichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; 64013236Sgraichen /* grace times */ 64113236Sgraichen dqp->dqb_btime = 64213236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft; 64313236Sgraichen dqp->dqb_itime = 64413236Sgraichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft; 64513236Sgraichen *cp = ':'; 64613236Sgraichen return (1); 64713236Sgraichen default: 64858618Scharnier warnx("bad rpc result, host: %s", fst->f_mntfromname); 64913236Sgraichen break; 65013236Sgraichen } 65113236Sgraichen *cp = ':'; 65213236Sgraichen return (0); 65313236Sgraichen} 65413236Sgraichen 65516379Salexstatic int 65695624Smarkmcallaurpc(char *host, int prognum, int versnum, int procnum, 65795624Smarkm xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 65813236Sgraichen{ 65913236Sgraichen struct sockaddr_in server_addr; 66013236Sgraichen enum clnt_stat clnt_stat; 66113236Sgraichen struct hostent *hp; 66213236Sgraichen struct timeval timeout, tottimeout; 66313236Sgraichen 66413236Sgraichen CLIENT *client = NULL; 66595624Smarkm int sock = RPC_ANYSOCK; 66613236Sgraichen 66713236Sgraichen if ((hp = gethostbyname(host)) == NULL) 66813236Sgraichen return ((int) RPC_UNKNOWNHOST); 66913236Sgraichen timeout.tv_usec = 0; 67013236Sgraichen timeout.tv_sec = 6; 67158618Scharnier bcopy(hp->h_addr, &server_addr.sin_addr, 67295624Smarkm MIN(hp->h_length,(int)sizeof(server_addr.sin_addr))); 67313236Sgraichen server_addr.sin_family = AF_INET; 67413236Sgraichen server_addr.sin_port = 0; 67513236Sgraichen 67613236Sgraichen if ((client = clntudp_create(&server_addr, prognum, 67795624Smarkm versnum, timeout, &sock)) == NULL) 67813236Sgraichen return ((int) rpc_createerr.cf_stat); 67913236Sgraichen 68013236Sgraichen client->cl_auth = authunix_create_default(); 68113236Sgraichen tottimeout.tv_sec = 25; 68213236Sgraichen tottimeout.tv_usec = 0; 68313236Sgraichen clnt_stat = clnt_call(client, procnum, inproc, in, 68413236Sgraichen outproc, out, tottimeout); 68513236Sgraichen 68613236Sgraichen return ((int) clnt_stat); 68713236Sgraichen} 68813236Sgraichen 68916379Salexstatic int 69095624Smarkmalldigits(char *s) 6911590Srgrimes{ 69295624Smarkm int c; 6931590Srgrimes 6941590Srgrimes c = *s++; 6951590Srgrimes do { 6961590Srgrimes if (!isdigit(c)) 6971590Srgrimes return (0); 69816379Salex } while ((c = *s++)); 6991590Srgrimes return (1); 7001590Srgrimes} 701