quota.c revision 207736
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 207736 2010-05-07 00:41:12Z mckusick $"); 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> 74169345Sdwmalone#include <stdint.h> 7513236Sgraichen#include <stdlib.h> 7613236Sgraichen#include <string.h> 77166646Smpp#include <time.h> 7816379Salex#include <unistd.h> 791590Srgrimes 8095624Smarkmconst char *qfname = QUOTAFILENAME; 8195624Smarkmconst char *qfextension[] = INITQFNAMES; 8213236Sgraichen 831590Srgrimesstruct quotause { 841590Srgrimes struct quotause *next; 851590Srgrimes long flags; 861590Srgrimes struct dqblk dqblk; 871590Srgrimes char fsname[MAXPATHLEN + 1]; 8813236Sgraichen}; 891590Srgrimes 90207736Smckusickstatic char *timeprt(int64_t seconds); 9192921Simpstatic struct quotause *getprivs(long id, int quotatype); 9295624Smarkmstatic void usage(void); 93166388Smppstatic int showuid(u_long uid); 94166388Smppstatic int showgid(u_long gid); 95166388Smppstatic int showusrname(char *name); 96166388Smppstatic int showgrpname(char *name); 97166388Smppstatic int showquotas(int type, u_long id, const char *name); 98166646Smppstatic void showrawquotas(int type, u_long id, struct quotause *qup); 9995624Smarkmstatic void heading(int type, u_long id, const char *name, const char *tag); 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 108163599Sruint hflag; 109101545Siedowseint lflag; 110166646Smppint rflag; 1111590Srgrimesint qflag; 1121590Srgrimesint vflag; 113166646Smppchar *filename = NULL; 1141590Srgrimes 11516379Salexint 11695624Smarkmmain(int argc, char *argv[]) 1171590Srgrimes{ 11813236Sgraichen int ngroups; 119207736Smckusick gid_t mygid, gidset[NGROUPS]; 120166388Smpp int i, ch, gflag = 0, uflag = 0, errflag = 0; 1211590Srgrimes 122166646Smpp while ((ch = getopt(argc, argv, "f:ghlrquv")) != -1) { 1231590Srgrimes switch(ch) { 124166646Smpp case 'f': 125166646Smpp filename = optarg; 126166646Smpp break; 1271590Srgrimes case 'g': 1281590Srgrimes gflag++; 1291590Srgrimes break; 130163599Sru case 'h': 131163599Sru hflag++; 132163599Sru break; 133101545Siedowse case 'l': 134101545Siedowse lflag++; 135101545Siedowse break; 136101544Siedowse case 'q': 137101544Siedowse qflag++; 138101544Siedowse break; 139166646Smpp case 'r': 140166646Smpp rflag++; 141166646Smpp break; 1421590Srgrimes case 'u': 1431590Srgrimes uflag++; 1441590Srgrimes break; 1451590Srgrimes case 'v': 1461590Srgrimes vflag++; 1471590Srgrimes break; 1481590Srgrimes default: 1491590Srgrimes usage(); 1501590Srgrimes } 1511590Srgrimes } 1521590Srgrimes argc -= optind; 1531590Srgrimes argv += optind; 1541590Srgrimes if (!uflag && !gflag) 1551590Srgrimes uflag++; 1561590Srgrimes if (argc == 0) { 1571590Srgrimes if (uflag) 158166388Smpp errflag += showuid(getuid()); 1591590Srgrimes if (gflag) { 16013236Sgraichen mygid = getgid(); 161207736Smckusick ngroups = getgroups(NGROUPS, gidset); 16227888Scharnier if (ngroups < 0) 16327888Scharnier err(1, "getgroups"); 164166388Smpp errflag += showgid(mygid); 16513236Sgraichen for (i = 0; i < ngroups; i++) 16613236Sgraichen if (gidset[i] != mygid) 167166388Smpp errflag += showgid(gidset[i]); 1681590Srgrimes } 169166388Smpp return(errflag); 1701590Srgrimes } 1711590Srgrimes if (uflag && gflag) 1721590Srgrimes usage(); 1731590Srgrimes if (uflag) { 1741590Srgrimes for (; argc > 0; argc--, argv++) { 1751590Srgrimes if (alldigits(*argv)) 176166388Smpp errflag += showuid(atoi(*argv)); 1771590Srgrimes else 178166388Smpp errflag += showusrname(*argv); 1791590Srgrimes } 180166388Smpp return(errflag); 1811590Srgrimes } 1821590Srgrimes if (gflag) { 1831590Srgrimes for (; argc > 0; argc--, argv++) { 1841590Srgrimes if (alldigits(*argv)) 185166388Smpp errflag += showgid(atoi(*argv)); 1861590Srgrimes else 187166388Smpp errflag += showgrpname(*argv); 1881590Srgrimes } 1891590Srgrimes } 190166388Smpp return(errflag); 1911590Srgrimes} 1921590Srgrimes 19316379Salexstatic void 19495624Smarkmusage(void) 1951590Srgrimes{ 1961590Srgrimes 1971590Srgrimes fprintf(stderr, "%s\n%s\n%s\n", 198166646Smpp "usage: quota [-ghlu] [-f path] [-v | -q | -r]", 199166646Smpp " quota [-hlu] [-f path] [-v | -q | -r] user ...", 200166646Smpp " quota -g [-hl] [-f path] [-v | -q | -r] group ..."); 2011590Srgrimes exit(1); 2021590Srgrimes} 2031590Srgrimes 2041590Srgrimes/* 2051590Srgrimes * Print out quotas for a specified user identifier. 2061590Srgrimes */ 207166388Smppstatic int 20895624Smarkmshowuid(u_long uid) 2091590Srgrimes{ 2101590Srgrimes struct passwd *pwd = getpwuid(uid); 21195624Smarkm const char *name; 2121590Srgrimes 2131590Srgrimes if (pwd == NULL) 2141590Srgrimes name = "(no account)"; 2151590Srgrimes else 2161590Srgrimes name = pwd->pw_name; 217166388Smpp return(showquotas(USRQUOTA, uid, name)); 2181590Srgrimes} 2191590Srgrimes 2201590Srgrimes/* 2211590Srgrimes * Print out quotas for a specifed user name. 2221590Srgrimes */ 223166388Smppstatic int 22495624Smarkmshowusrname(char *name) 2251590Srgrimes{ 2261590Srgrimes struct passwd *pwd = getpwnam(name); 2271590Srgrimes 2281590Srgrimes if (pwd == NULL) { 22927888Scharnier warnx("%s: unknown user", name); 230166388Smpp return(1); 2311590Srgrimes } 232166388Smpp return(showquotas(USRQUOTA, pwd->pw_uid, name)); 2331590Srgrimes} 2341590Srgrimes 2351590Srgrimes/* 2361590Srgrimes * Print out quotas for a specified group identifier. 2371590Srgrimes */ 238166388Smppstatic int 23995624Smarkmshowgid(u_long gid) 2401590Srgrimes{ 2411590Srgrimes struct group *grp = getgrgid(gid); 24295624Smarkm const char *name; 2431590Srgrimes 2441590Srgrimes if (grp == NULL) 2451590Srgrimes name = "(no entry)"; 2461590Srgrimes else 2471590Srgrimes name = grp->gr_name; 248166388Smpp return(showquotas(GRPQUOTA, gid, name)); 2491590Srgrimes} 2501590Srgrimes 2511590Srgrimes/* 2521590Srgrimes * Print out quotas for a specifed group name. 2531590Srgrimes */ 254166388Smppstatic int 25595624Smarkmshowgrpname(char *name) 2561590Srgrimes{ 2571590Srgrimes struct group *grp = getgrnam(name); 2581590Srgrimes 2591590Srgrimes if (grp == NULL) { 26027888Scharnier warnx("%s: unknown group", name); 261166388Smpp return(1); 2621590Srgrimes } 263166388Smpp return(showquotas(GRPQUOTA, grp->gr_gid, name)); 2641590Srgrimes} 2651590Srgrimes 26616379Salexstatic void 267207736Smckusickprthumanval(int len, u_int64_t bytes) 268163599Sru{ 269163599Sru char buf[len + 1]; 270163599Sru 271163599Sru humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, 272163599Sru HN_B | HN_NOSPACE | HN_DECIMAL); 273163599Sru 274163599Sru (void)printf(" %*s", len, buf); 275163599Sru} 276163599Sru 277166388Smppstatic int 27895624Smarkmshowquotas(int type, u_long id, const char *name) 2791590Srgrimes{ 28095624Smarkm struct quotause *qup; 28113236Sgraichen struct quotause *quplist; 28295624Smarkm const char *msgi, *msgb; 28395624Smarkm const char *nam; 284181267Sdelphij char *bgrace = NULL, *igrace = NULL; 285166388Smpp int lines = 0, overquota = 0; 2861590Srgrimes static time_t now; 2871590Srgrimes 2881590Srgrimes if (now == 0) 2891590Srgrimes time(&now); 2901590Srgrimes quplist = getprivs(id, type); 2911590Srgrimes for (qup = quplist; qup; qup = qup->next) { 292207736Smckusick msgi = NULL; 2931590Srgrimes if (qup->dqblk.dqb_ihardlimit && 294166388Smpp qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) { 295166388Smpp overquota++; 2961590Srgrimes msgi = "File limit reached on"; 297166388Smpp } 2981590Srgrimes else if (qup->dqblk.dqb_isoftlimit && 29995624Smarkm qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 300166388Smpp overquota++; 3011590Srgrimes if (qup->dqblk.dqb_itime > now) 3021590Srgrimes msgi = "In file grace period on"; 3031590Srgrimes else 3041590Srgrimes msgi = "Over file quota on"; 30595624Smarkm } 306207736Smckusick msgb = NULL; 3071590Srgrimes if (qup->dqblk.dqb_bhardlimit && 308166388Smpp qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) { 309166388Smpp overquota++; 3101590Srgrimes msgb = "Block limit reached on"; 311166388Smpp } 3121590Srgrimes else if (qup->dqblk.dqb_bsoftlimit && 31395624Smarkm qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 314166388Smpp overquota++; 3151590Srgrimes if (qup->dqblk.dqb_btime > now) 3161590Srgrimes msgb = "In block grace period on"; 3171590Srgrimes else 3181590Srgrimes msgb = "Over block quota on"; 31995624Smarkm } 320166646Smpp if (rflag) { 321166646Smpp showrawquotas(type, id, qup); 322166646Smpp continue; 323166646Smpp } 324166646Smpp if (!vflag && 325166646Smpp qup->dqblk.dqb_isoftlimit == 0 && 326166646Smpp qup->dqblk.dqb_ihardlimit == 0 && 327166646Smpp qup->dqblk.dqb_bsoftlimit == 0 && 328166646Smpp qup->dqblk.dqb_bhardlimit == 0) 329166646Smpp continue; 3301590Srgrimes if (qflag) { 331207736Smckusick if ((msgi != NULL || msgb != NULL) && 3321590Srgrimes lines++ == 0) 3331590Srgrimes heading(type, id, name, ""); 334207736Smckusick if (msgi != NULL) 3351590Srgrimes printf("\t%s %s\n", msgi, qup->fsname); 336207736Smckusick if (msgb != NULL) 3371590Srgrimes printf("\t%s %s\n", msgb, qup->fsname); 3381590Srgrimes continue; 3391590Srgrimes } 340207736Smckusick if (!vflag && 341207736Smckusick qup->dqblk.dqb_curblocks == 0 && 342207736Smckusick qup->dqblk.dqb_curinodes == 0) 3431590Srgrimes continue; 344207736Smckusick if (lines++ == 0) 345207736Smckusick heading(type, id, name, ""); 346207736Smckusick nam = qup->fsname; 347207736Smckusick if (strlen(qup->fsname) > 15) { 348207736Smckusick printf("%s\n", qup->fsname); 349207736Smckusick nam = ""; 350207736Smckusick } 351207736Smckusick printf("%-15s", nam); 352207736Smckusick if (hflag) { 353207736Smckusick prthumanval(7, dbtob(qup->dqblk.dqb_curblocks)); 354207736Smckusick printf("%c", (msgb == NULL) ? ' ' : '*'); 355207736Smckusick prthumanval(7, dbtob(qup->dqblk.dqb_bsoftlimit)); 356207736Smckusick prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit)); 357207736Smckusick } else { 358207736Smckusick printf(" %7ju%c %7ju %7ju", 359207736Smckusick dbtob(1024) * (uintmax_t)qup->dqblk.dqb_curblocks, 360207736Smckusick (msgb == NULL) ? ' ' : '*', 361207736Smckusick dbtob(1024) * (uintmax_t)qup->dqblk.dqb_bsoftlimit, 362207736Smckusick dbtob(1024) * (uintmax_t)qup->dqblk.dqb_bhardlimit); 3631590Srgrimes } 364207736Smckusick if (msgb != NULL) 365207736Smckusick bgrace = timeprt(qup->dqblk.dqb_btime); 366207736Smckusick if (msgi != NULL) 367207736Smckusick igrace = timeprt(qup->dqblk.dqb_itime); 368207736Smckusick printf("%8s %6ju%c %6ju %6ju%8s\n" 369207736Smckusick , (msgb == NULL) ? "" : bgrace 370207736Smckusick , (uintmax_t)qup->dqblk.dqb_curinodes 371207736Smckusick , (msgi == NULL) ? ' ' : '*' 372207736Smckusick , (uintmax_t)qup->dqblk.dqb_isoftlimit 373207736Smckusick , (uintmax_t)qup->dqblk.dqb_ihardlimit 374207736Smckusick , (msgi == NULL) ? "" : igrace 375207736Smckusick ); 376207736Smckusick if (msgb != NULL) 377207736Smckusick free(bgrace); 378207736Smckusick if (msgi != NULL) 379207736Smckusick free(igrace); 3801590Srgrimes } 381166646Smpp if (!qflag && !rflag && lines == 0) 3821590Srgrimes heading(type, id, name, "none"); 383207736Smckusick return (overquota); 3841590Srgrimes} 3851590Srgrimes 38616379Salexstatic void 387181267Sdelphijshowrawquotas(int type, u_long id, struct quotause *qup) 388166646Smpp{ 389207736Smckusick time_t t; 390207736Smckusick 391166646Smpp printf("Raw %s quota information for id %lu on %s\n", 392166646Smpp type == USRQUOTA ? "user" : "group", id, qup->fsname); 393207736Smckusick printf("block hard limit: %ju\n", 394207736Smckusick (uintmax_t)qup->dqblk.dqb_bhardlimit); 395207736Smckusick printf("block soft limit: %ju\n", 396207736Smckusick (uintmax_t)qup->dqblk.dqb_bsoftlimit); 397207736Smckusick printf("current block count: %ju\n", 398207736Smckusick (uintmax_t)qup->dqblk.dqb_curblocks); 399207736Smckusick printf("i-node hard limit: %ju\n", 400207736Smckusick (uintmax_t)qup->dqblk.dqb_ihardlimit); 401207736Smckusick printf("i-node soft limit: %ju\n", 402207736Smckusick (uintmax_t)qup->dqblk.dqb_isoftlimit); 403207736Smckusick printf("current i-node count: %ju\n", 404207736Smckusick (uintmax_t)qup->dqblk.dqb_curinodes); 405207736Smckusick printf("block grace time: %jd", 406207736Smckusick (intmax_t)qup->dqblk.dqb_btime); 407181262Scognet if (qup->dqblk.dqb_btime != 0) { 408207736Smckusick t = qup->dqblk.dqb_btime; 409207736Smckusick printf(" %s", ctime(&t)); 410207736Smckusick } else { 411166646Smpp printf("\n"); 412207736Smckusick } 413169345Sdwmalone printf("i-node grace time: %jd", (intmax_t)qup->dqblk.dqb_itime); 414181262Scognet if (qup->dqblk.dqb_itime != 0) { 415207736Smckusick t = qup->dqblk.dqb_itime; 416207736Smckusick printf(" %s", ctime(&t)); 417207736Smckusick } else { 418166646Smpp printf("\n"); 419207736Smckusick } 420166646Smpp} 421166646Smpp 422166646Smpp 423166646Smppstatic void 42495624Smarkmheading(int type, u_long id, const char *name, const char *tag) 4251590Srgrimes{ 4261590Srgrimes 42713365Sgraichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 4281590Srgrimes name, *qfextension[type], id, tag); 4291590Srgrimes if (!qflag && tag[0] == '\0') { 430207736Smckusick printf("%-15s %7s %8s %7s %7s %6s %7s %6s%8s\n" 4311590Srgrimes , "Filesystem" 43277047Spirzyk , "usage" 4331590Srgrimes , "quota" 4341590Srgrimes , "limit" 4351590Srgrimes , "grace" 4361590Srgrimes , "files" 4371590Srgrimes , "quota" 4381590Srgrimes , "limit" 4391590Srgrimes , "grace" 4401590Srgrimes ); 4411590Srgrimes } 4421590Srgrimes} 4431590Srgrimes 4441590Srgrimes/* 4451590Srgrimes * Calculate the grace period and return a printable string for it. 4461590Srgrimes */ 447166495Smppstatic char * 448207736Smckusicktimeprt(int64_t seconds) 4491590Srgrimes{ 4501590Srgrimes time_t hours, minutes; 451207736Smckusick char *buf; 4521590Srgrimes static time_t now; 4531590Srgrimes 4541590Srgrimes if (now == 0) 4551590Srgrimes time(&now); 456166495Smpp if (now > seconds) { 457207736Smckusick if ((buf = strdup("none")) == NULL) 458207736Smckusick errx(1, "strdup() failed in timeprt()"); 459207736Smckusick return (buf); 460166495Smpp } 4611590Srgrimes seconds -= now; 4621590Srgrimes minutes = (seconds + 30) / 60; 4631590Srgrimes hours = (minutes + 30) / 60; 4641590Srgrimes if (hours >= 36) { 465166495Smpp if (asprintf(&buf, "%lddays", ((long)hours + 12) / 24) < 0) 466207736Smckusick errx(1, "asprintf() failed in timeprt(1)"); 4671590Srgrimes return (buf); 4681590Srgrimes } 4691590Srgrimes if (minutes >= 60) { 470166495Smpp if (asprintf(&buf, "%2ld:%ld", (long)minutes / 60, 471166495Smpp (long)minutes % 60) < 0) 472207736Smckusick errx(1, "asprintf() failed in timeprt(2)"); 4731590Srgrimes return (buf); 4741590Srgrimes } 475166495Smpp if (asprintf(&buf, "%2ld", (long)minutes) < 0) 476207736Smckusick errx(1, "asprintf() failed in timeprt(3)"); 4771590Srgrimes return (buf); 4781590Srgrimes} 4791590Srgrimes 4801590Srgrimes/* 4811590Srgrimes * Collect the requested quota information. 4821590Srgrimes */ 48316379Salexstatic struct quotause * 48495624Smarkmgetprivs(long id, int quotatype) 4851590Srgrimes{ 486101544Siedowse struct quotause *qup, *quptail = NULL; 48795624Smarkm struct fstab *fs; 4881590Srgrimes struct quotause *quphead; 48913236Sgraichen struct statfs *fst; 49013236Sgraichen int nfst, i; 491166646Smpp struct statfs sfb; 4921590Srgrimes 49313236Sgraichen qup = quphead = (struct quotause *)0; 49413236Sgraichen 495166646Smpp if (filename != NULL && statfs(filename, &sfb) != 0) 496166646Smpp err(1, "cannot statfs %s", filename); 49797764Siedowse nfst = getmntinfo(&fst, MNT_NOWAIT); 49827888Scharnier if (nfst == 0) 49927888Scharnier errx(2, "no filesystems mounted!"); 5001590Srgrimes setfsent(); 501207736Smckusick for (i = 0; i < nfst; i++) { 50213236Sgraichen if (qup == NULL) { 50313365Sgraichen if ((qup = (struct quotause *)malloc(sizeof *qup)) 50427888Scharnier == NULL) 50527888Scharnier errx(2, "out of memory"); 5061590Srgrimes } 507166646Smpp /* 508166646Smpp * See if the user requested a specific file system 509166646Smpp * or specified a file inside a mounted file system. 510166646Smpp */ 511166646Smpp if (filename != NULL && 512166646Smpp strcmp(sfb.f_mntonname, fst[i].f_mntonname) != 0) 513166646Smpp continue; 51432651Sbde if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 515101545Siedowse if (lflag) 516101545Siedowse continue; 517166646Smpp if (getnfsquota(&fst[i], qup, id, quotatype) == 0) 5181590Srgrimes continue; 51936880Sache } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 52013236Sgraichen /* 52113236Sgraichen * XXX 52213236Sgraichen * UFS filesystems must be in /etc/fstab, and must 52313236Sgraichen * indicate that they have quotas on (?!) This is quite 52413236Sgraichen * unlike SunOS where quotas can be enabled/disabled 52513236Sgraichen * on a filesystem independent of /etc/fstab, and it 52613236Sgraichen * will still print quotas for them. 52713236Sgraichen */ 52813236Sgraichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 5291590Srgrimes continue; 53095624Smarkm if (getufsquota(fs, qup, id, quotatype) == 0) 53113236Sgraichen continue; 53213236Sgraichen } else 53313236Sgraichen continue; 53413236Sgraichen strcpy(qup->fsname, fst[i].f_mntonname); 5351590Srgrimes if (quphead == NULL) 5361590Srgrimes quphead = qup; 5371590Srgrimes else 5381590Srgrimes quptail->next = qup; 5391590Srgrimes quptail = qup; 54013236Sgraichen quptail->next = 0; 54113236Sgraichen qup = NULL; 5421590Srgrimes } 54313236Sgraichen if (qup) 54413236Sgraichen free(qup); 5451590Srgrimes endfsent(); 5461590Srgrimes return (quphead); 5471590Srgrimes} 5481590Srgrimes 5491590Srgrimes/* 550207736Smckusick * Check to see if a particular quota is available. 5511590Srgrimes */ 55216379Salexstatic int 553207736Smckusickgetufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype) 5541590Srgrimes{ 555207736Smckusick struct quotafile *qf; 5561590Srgrimes 557207736Smckusick if ((qf = quota_open(fs, quotatype, O_RDONLY)) == NULL) 5581590Srgrimes return (0); 559207736Smckusick if (quota_read(qf, &qup->dqblk, id) != 0) 560166485Smpp return (0); 561207736Smckusick quota_close(qf); 5621590Srgrimes return (1); 5631590Srgrimes} 5641590Srgrimes 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