19b50d902SRodney W. Grimes /*
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1980, 1990, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by
89b50d902SRodney W. Grimes * Robert Elz at The University of Melbourne.
99b50d902SRodney W. Grimes *
109b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
119b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
129b50d902SRodney W. Grimes * are met:
139b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
159b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
169b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
179b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
199b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
209b50d902SRodney W. Grimes * without specific prior written permission.
219b50d902SRodney W. Grimes *
229b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329b50d902SRodney W. Grimes * SUCH DAMAGE.
339b50d902SRodney W. Grimes */
349b50d902SRodney W. Grimes
359b50d902SRodney W. Grimes /*
369b50d902SRodney W. Grimes * Disk quota reporting program.
379b50d902SRodney W. Grimes */
385e3934b1SWarner Losh
399b50d902SRodney W. Grimes #include <sys/param.h>
409288f266SThomas Graichen #include <sys/types.h>
419b50d902SRodney W. Grimes #include <sys/file.h>
429b50d902SRodney W. Grimes #include <sys/stat.h>
439288f266SThomas Graichen #include <sys/mount.h>
449288f266SThomas Graichen #include <sys/socket.h>
45ff288009SMark Murray
46ff288009SMark Murray #include <rpc/rpc.h>
47ff288009SMark Murray #include <rpc/pmap_prot.h>
48ff288009SMark Murray #include <rpcsvc/rquota.h>
49ff288009SMark Murray
509b50d902SRodney W. Grimes #include <ufs/ufs/quota.h>
51ff288009SMark Murray
529d63ad49SPhilippe Charnier #include <ctype.h>
539d63ad49SPhilippe Charnier #include <err.h>
549d63ad49SPhilippe Charnier #include <fstab.h>
559d63ad49SPhilippe Charnier #include <grp.h>
56478bf774SRuslan Ermilov #include <libutil.h>
57ff288009SMark Murray #include <netdb.h>
589d63ad49SPhilippe Charnier #include <pwd.h>
599b50d902SRodney W. Grimes #include <stdio.h>
602ffe6bbfSDavid Malone #include <stdint.h>
619288f266SThomas Graichen #include <stdlib.h>
629288f266SThomas Graichen #include <string.h>
632e1f5ad9SMike Pritchard #include <time.h>
6477ae30e9SAlexander Langer #include <unistd.h>
659b50d902SRodney W. Grimes
66865ff609SEd Schouten static const char *qfextension[] = INITQFNAMES;
679b50d902SRodney W. Grimes
689b50d902SRodney W. Grimes struct quotause {
699b50d902SRodney W. Grimes struct quotause *next;
709b50d902SRodney W. Grimes long flags;
719b50d902SRodney W. Grimes struct dqblk dqblk;
729b50d902SRodney W. Grimes char fsname[MAXPATHLEN + 1];
739288f266SThomas Graichen };
749b50d902SRodney W. Grimes
75829b3f6bSDag-Erling Smørgrav static char *timeprt(int64_t seconds);
76d3cb5dedSWarner Losh static struct quotause *getprivs(long id, int quotatype);
771a7ac2bdSAlfonso Gregory static void usage(void) __dead2;
78dfaa8068SMike Pritchard static int showuid(u_long uid);
79dfaa8068SMike Pritchard static int showgid(u_long gid);
80dfaa8068SMike Pritchard static int showusrname(char *name);
81dfaa8068SMike Pritchard static int showgrpname(char *name);
82dfaa8068SMike Pritchard static int showquotas(int type, u_long id, const char *name);
832e1f5ad9SMike Pritchard static void showrawquotas(int type, u_long id, struct quotause *qup);
84ff288009SMark Murray static void heading(int type, u_long id, const char *name, const char *tag);
85ff288009SMark Murray static int getufsquota(struct fstab *fs, struct quotause *qup, long id,
86ff288009SMark Murray int quotatype);
87ff288009SMark Murray static int getnfsquota(struct statfs *fst, struct quotause *qup, long id,
88ff288009SMark Murray int quotatype);
89aad5531eSSean Eric Fagan static enum clnt_stat callaurpc(char *host, int prognum, int versnum, int procnum,
9077ae30e9SAlexander Langer xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
9177ae30e9SAlexander Langer static int alldigits(char *s);
929288f266SThomas Graichen
93865ff609SEd Schouten static int hflag;
94865ff609SEd Schouten static int lflag;
95865ff609SEd Schouten static int rflag;
96865ff609SEd Schouten static int qflag;
97865ff609SEd Schouten static int vflag;
98865ff609SEd Schouten static char *filename = NULL;
999b50d902SRodney W. Grimes
10077ae30e9SAlexander Langer int
main(int argc,char * argv[])101ff288009SMark Murray main(int argc, char *argv[])
1029b50d902SRodney W. Grimes {
1039288f266SThomas Graichen int ngroups;
10437ed8e48SKirk McKusick gid_t mygid, gidset[NGROUPS];
105dfaa8068SMike Pritchard int i, ch, gflag = 0, uflag = 0, errflag = 0;
1069b50d902SRodney W. Grimes
1072e1f5ad9SMike Pritchard while ((ch = getopt(argc, argv, "f:ghlrquv")) != -1) {
1089b50d902SRodney W. Grimes switch(ch) {
1092e1f5ad9SMike Pritchard case 'f':
1102e1f5ad9SMike Pritchard filename = optarg;
1112e1f5ad9SMike Pritchard break;
1129b50d902SRodney W. Grimes case 'g':
1139b50d902SRodney W. Grimes gflag++;
1149b50d902SRodney W. Grimes break;
115478bf774SRuslan Ermilov case 'h':
116478bf774SRuslan Ermilov hflag++;
117478bf774SRuslan Ermilov break;
118e56990e4SIan Dowse case 'l':
119e56990e4SIan Dowse lflag++;
120e56990e4SIan Dowse break;
121e608ec61SIan Dowse case 'q':
122e608ec61SIan Dowse qflag++;
123e608ec61SIan Dowse break;
1242e1f5ad9SMike Pritchard case 'r':
1252e1f5ad9SMike Pritchard rflag++;
1262e1f5ad9SMike Pritchard break;
1279b50d902SRodney W. Grimes case 'u':
1289b50d902SRodney W. Grimes uflag++;
1299b50d902SRodney W. Grimes break;
1309b50d902SRodney W. Grimes case 'v':
1319b50d902SRodney W. Grimes vflag++;
1329b50d902SRodney W. Grimes break;
1339b50d902SRodney W. Grimes default:
1349b50d902SRodney W. Grimes usage();
1359b50d902SRodney W. Grimes }
1369b50d902SRodney W. Grimes }
1379b50d902SRodney W. Grimes argc -= optind;
1389b50d902SRodney W. Grimes argv += optind;
1399b50d902SRodney W. Grimes if (!uflag && !gflag)
1409b50d902SRodney W. Grimes uflag++;
1419b50d902SRodney W. Grimes if (argc == 0) {
1429b50d902SRodney W. Grimes if (uflag)
143dfaa8068SMike Pritchard errflag += showuid(getuid());
1449b50d902SRodney W. Grimes if (gflag) {
1459288f266SThomas Graichen mygid = getgid();
14637ed8e48SKirk McKusick ngroups = getgroups(NGROUPS, gidset);
1479d63ad49SPhilippe Charnier if (ngroups < 0)
1489d63ad49SPhilippe Charnier err(1, "getgroups");
149dfaa8068SMike Pritchard errflag += showgid(mygid);
1509288f266SThomas Graichen for (i = 0; i < ngroups; i++)
1519288f266SThomas Graichen if (gidset[i] != mygid)
152dfaa8068SMike Pritchard errflag += showgid(gidset[i]);
1539b50d902SRodney W. Grimes }
154dfaa8068SMike Pritchard return(errflag);
1559b50d902SRodney W. Grimes }
1569b50d902SRodney W. Grimes if (uflag && gflag)
1579b50d902SRodney W. Grimes usage();
1589b50d902SRodney W. Grimes if (uflag) {
1599b50d902SRodney W. Grimes for (; argc > 0; argc--, argv++) {
1609b50d902SRodney W. Grimes if (alldigits(*argv))
161dfaa8068SMike Pritchard errflag += showuid(atoi(*argv));
1629b50d902SRodney W. Grimes else
163dfaa8068SMike Pritchard errflag += showusrname(*argv);
1649b50d902SRodney W. Grimes }
165dfaa8068SMike Pritchard return(errflag);
1669b50d902SRodney W. Grimes }
1679b50d902SRodney W. Grimes if (gflag) {
1689b50d902SRodney W. Grimes for (; argc > 0; argc--, argv++) {
1699b50d902SRodney W. Grimes if (alldigits(*argv))
170dfaa8068SMike Pritchard errflag += showgid(atoi(*argv));
1719b50d902SRodney W. Grimes else
172dfaa8068SMike Pritchard errflag += showgrpname(*argv);
1739b50d902SRodney W. Grimes }
1749b50d902SRodney W. Grimes }
175dfaa8068SMike Pritchard return(errflag);
1769b50d902SRodney W. Grimes }
1779b50d902SRodney W. Grimes
17877ae30e9SAlexander Langer static void
usage(void)179ff288009SMark Murray usage(void)
1809b50d902SRodney W. Grimes {
1819b50d902SRodney W. Grimes
1829b50d902SRodney W. Grimes fprintf(stderr, "%s\n%s\n%s\n",
1832e1f5ad9SMike Pritchard "usage: quota [-ghlu] [-f path] [-v | -q | -r]",
1842e1f5ad9SMike Pritchard " quota [-hlu] [-f path] [-v | -q | -r] user ...",
1852e1f5ad9SMike Pritchard " quota -g [-hl] [-f path] [-v | -q | -r] group ...");
1869b50d902SRodney W. Grimes exit(1);
1879b50d902SRodney W. Grimes }
1889b50d902SRodney W. Grimes
1899b50d902SRodney W. Grimes /*
1909b50d902SRodney W. Grimes * Print out quotas for a specified user identifier.
1919b50d902SRodney W. Grimes */
192dfaa8068SMike Pritchard static int
showuid(u_long uid)193ff288009SMark Murray showuid(u_long uid)
1949b50d902SRodney W. Grimes {
1959b50d902SRodney W. Grimes struct passwd *pwd = getpwuid(uid);
196ff288009SMark Murray const char *name;
1979b50d902SRodney W. Grimes
1989b50d902SRodney W. Grimes if (pwd == NULL)
1999b50d902SRodney W. Grimes name = "(no account)";
2009b50d902SRodney W. Grimes else
2019b50d902SRodney W. Grimes name = pwd->pw_name;
202dfaa8068SMike Pritchard return(showquotas(USRQUOTA, uid, name));
2039b50d902SRodney W. Grimes }
2049b50d902SRodney W. Grimes
2059b50d902SRodney W. Grimes /*
20604389c85SGordon Bergling * Print out quotas for a specified user name.
2079b50d902SRodney W. Grimes */
208dfaa8068SMike Pritchard static int
showusrname(char * name)209ff288009SMark Murray showusrname(char *name)
2109b50d902SRodney W. Grimes {
2119b50d902SRodney W. Grimes struct passwd *pwd = getpwnam(name);
2129b50d902SRodney W. Grimes
2139b50d902SRodney W. Grimes if (pwd == NULL) {
2149d63ad49SPhilippe Charnier warnx("%s: unknown user", name);
215dfaa8068SMike Pritchard return(1);
2169b50d902SRodney W. Grimes }
217dfaa8068SMike Pritchard return(showquotas(USRQUOTA, pwd->pw_uid, name));
2189b50d902SRodney W. Grimes }
2199b50d902SRodney W. Grimes
2209b50d902SRodney W. Grimes /*
2219b50d902SRodney W. Grimes * Print out quotas for a specified group identifier.
2229b50d902SRodney W. Grimes */
223dfaa8068SMike Pritchard static int
showgid(u_long gid)224ff288009SMark Murray showgid(u_long gid)
2259b50d902SRodney W. Grimes {
2269b50d902SRodney W. Grimes struct group *grp = getgrgid(gid);
227ff288009SMark Murray const char *name;
2289b50d902SRodney W. Grimes
2299b50d902SRodney W. Grimes if (grp == NULL)
2309b50d902SRodney W. Grimes name = "(no entry)";
2319b50d902SRodney W. Grimes else
2329b50d902SRodney W. Grimes name = grp->gr_name;
233dfaa8068SMike Pritchard return(showquotas(GRPQUOTA, gid, name));
2349b50d902SRodney W. Grimes }
2359b50d902SRodney W. Grimes
2369b50d902SRodney W. Grimes /*
23704389c85SGordon Bergling * Print out quotas for a specified group name.
2389b50d902SRodney W. Grimes */
239dfaa8068SMike Pritchard static int
showgrpname(char * name)240ff288009SMark Murray showgrpname(char *name)
2419b50d902SRodney W. Grimes {
2429b50d902SRodney W. Grimes struct group *grp = getgrnam(name);
2439b50d902SRodney W. Grimes
2449b50d902SRodney W. Grimes if (grp == NULL) {
2459d63ad49SPhilippe Charnier warnx("%s: unknown group", name);
246dfaa8068SMike Pritchard return(1);
2479b50d902SRodney W. Grimes }
248dfaa8068SMike Pritchard return(showquotas(GRPQUOTA, grp->gr_gid, name));
2499b50d902SRodney W. Grimes }
2509b50d902SRodney W. Grimes
25177ae30e9SAlexander Langer static void
prthumanval(int len,u_int64_t bytes)25237ed8e48SKirk McKusick prthumanval(int len, u_int64_t bytes)
253478bf774SRuslan Ermilov {
254478bf774SRuslan Ermilov char buf[len + 1];
255478bf774SRuslan Ermilov
2562f39985fSSergey Kandaurov /*
2572f39985fSSergey Kandaurov * Limit the width to 5 bytes as that is what users expect.
2582f39985fSSergey Kandaurov */
259a3010446SMarcelo Araujo humanize_number(buf, MIN(sizeof(buf), 5), bytes, "",
2602f39985fSSergey Kandaurov HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
261478bf774SRuslan Ermilov
262478bf774SRuslan Ermilov (void)printf(" %*s", len, buf);
263478bf774SRuslan Ermilov }
264478bf774SRuslan Ermilov
265dfaa8068SMike Pritchard static int
showquotas(int type,u_long id,const char * name)266ff288009SMark Murray showquotas(int type, u_long id, const char *name)
2679b50d902SRodney W. Grimes {
268ff288009SMark Murray struct quotause *qup;
2699288f266SThomas Graichen struct quotause *quplist;
270ff288009SMark Murray const char *msgi, *msgb;
271ff288009SMark Murray const char *nam;
272829b3f6bSDag-Erling Smørgrav char *bgrace = NULL, *igrace = NULL;
273dfaa8068SMike Pritchard int lines = 0, overquota = 0;
2749b50d902SRodney W. Grimes static time_t now;
2759b50d902SRodney W. Grimes
2769b50d902SRodney W. Grimes if (now == 0)
2779b50d902SRodney W. Grimes time(&now);
2789b50d902SRodney W. Grimes quplist = getprivs(id, type);
2799b50d902SRodney W. Grimes for (qup = quplist; qup; qup = qup->next) {
280829b3f6bSDag-Erling Smørgrav msgi = NULL;
2819b50d902SRodney W. Grimes if (qup->dqblk.dqb_ihardlimit &&
282dfaa8068SMike Pritchard qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) {
283dfaa8068SMike Pritchard overquota++;
2849b50d902SRodney W. Grimes msgi = "File limit reached on";
285dfaa8068SMike Pritchard }
2869b50d902SRodney W. Grimes else if (qup->dqblk.dqb_isoftlimit &&
287ff288009SMark Murray qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) {
288dfaa8068SMike Pritchard overquota++;
2899b50d902SRodney W. Grimes if (qup->dqblk.dqb_itime > now)
2909b50d902SRodney W. Grimes msgi = "In file grace period on";
2919b50d902SRodney W. Grimes else
2929b50d902SRodney W. Grimes msgi = "Over file quota on";
293ff288009SMark Murray }
294829b3f6bSDag-Erling Smørgrav msgb = NULL;
2959b50d902SRodney W. Grimes if (qup->dqblk.dqb_bhardlimit &&
296dfaa8068SMike Pritchard qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) {
297dfaa8068SMike Pritchard overquota++;
2989b50d902SRodney W. Grimes msgb = "Block limit reached on";
299dfaa8068SMike Pritchard }
3009b50d902SRodney W. Grimes else if (qup->dqblk.dqb_bsoftlimit &&
301ff288009SMark Murray qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) {
302dfaa8068SMike Pritchard overquota++;
3039b50d902SRodney W. Grimes if (qup->dqblk.dqb_btime > now)
3049b50d902SRodney W. Grimes msgb = "In block grace period on";
3059b50d902SRodney W. Grimes else
3069b50d902SRodney W. Grimes msgb = "Over block quota on";
307ff288009SMark Murray }
3082e1f5ad9SMike Pritchard if (rflag) {
3092e1f5ad9SMike Pritchard showrawquotas(type, id, qup);
3102e1f5ad9SMike Pritchard continue;
3112e1f5ad9SMike Pritchard }
3122e1f5ad9SMike Pritchard if (!vflag &&
3132e1f5ad9SMike Pritchard qup->dqblk.dqb_isoftlimit == 0 &&
3142e1f5ad9SMike Pritchard qup->dqblk.dqb_ihardlimit == 0 &&
3152e1f5ad9SMike Pritchard qup->dqblk.dqb_bsoftlimit == 0 &&
3162e1f5ad9SMike Pritchard qup->dqblk.dqb_bhardlimit == 0)
3172e1f5ad9SMike Pritchard continue;
3189b50d902SRodney W. Grimes if (qflag) {
319829b3f6bSDag-Erling Smørgrav if ((msgi != NULL || msgb != NULL) &&
3209b50d902SRodney W. Grimes lines++ == 0)
3219b50d902SRodney W. Grimes heading(type, id, name, "");
322829b3f6bSDag-Erling Smørgrav if (msgi != NULL)
3239b50d902SRodney W. Grimes printf("\t%s %s\n", msgi, qup->fsname);
324829b3f6bSDag-Erling Smørgrav if (msgb != NULL)
3259b50d902SRodney W. Grimes printf("\t%s %s\n", msgb, qup->fsname);
3269b50d902SRodney W. Grimes continue;
3279b50d902SRodney W. Grimes }
32837ed8e48SKirk McKusick if (!vflag &&
32937ed8e48SKirk McKusick qup->dqblk.dqb_curblocks == 0 &&
33037ed8e48SKirk McKusick qup->dqblk.dqb_curinodes == 0)
33137ed8e48SKirk McKusick continue;
3329b50d902SRodney W. Grimes if (lines++ == 0)
3339b50d902SRodney W. Grimes heading(type, id, name, "");
3349288f266SThomas Graichen nam = qup->fsname;
3359288f266SThomas Graichen if (strlen(qup->fsname) > 15) {
3369288f266SThomas Graichen printf("%s\n", qup->fsname);
3379288f266SThomas Graichen nam = "";
3389288f266SThomas Graichen }
33937ed8e48SKirk McKusick printf("%-15s", nam);
340478bf774SRuslan Ermilov if (hflag) {
34137ed8e48SKirk McKusick prthumanval(7, dbtob(qup->dqblk.dqb_curblocks));
342829b3f6bSDag-Erling Smørgrav printf("%c", (msgb == NULL) ? ' ' : '*');
34337ed8e48SKirk McKusick prthumanval(7, dbtob(qup->dqblk.dqb_bsoftlimit));
34437ed8e48SKirk McKusick prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit));
345478bf774SRuslan Ermilov } else {
34637ed8e48SKirk McKusick printf(" %7ju%c %7ju %7ju",
3472f39985fSSergey Kandaurov (uintmax_t)dbtob(qup->dqblk.dqb_curblocks)
3482f39985fSSergey Kandaurov / 1024,
349829b3f6bSDag-Erling Smørgrav (msgb == NULL) ? ' ' : '*',
3502f39985fSSergey Kandaurov (uintmax_t)dbtob(qup->dqblk.dqb_bsoftlimit)
3512f39985fSSergey Kandaurov / 1024,
3522f39985fSSergey Kandaurov (uintmax_t)dbtob(qup->dqblk.dqb_bhardlimit)
3532f39985fSSergey Kandaurov / 1024);
354478bf774SRuslan Ermilov }
355f5374712SMike Pritchard if (msgb != NULL)
356829b3f6bSDag-Erling Smørgrav bgrace = timeprt(qup->dqblk.dqb_btime);
357f5374712SMike Pritchard if (msgi != NULL)
358829b3f6bSDag-Erling Smørgrav igrace = timeprt(qup->dqblk.dqb_itime);
35937ed8e48SKirk McKusick printf("%8s %6ju%c %6ju %6ju%8s\n"
360829b3f6bSDag-Erling Smørgrav , (msgb == NULL) ? "" : bgrace
36137ed8e48SKirk McKusick , (uintmax_t)qup->dqblk.dqb_curinodes
362829b3f6bSDag-Erling Smørgrav , (msgi == NULL) ? ' ' : '*'
36337ed8e48SKirk McKusick , (uintmax_t)qup->dqblk.dqb_isoftlimit
36437ed8e48SKirk McKusick , (uintmax_t)qup->dqblk.dqb_ihardlimit
365829b3f6bSDag-Erling Smørgrav , (msgi == NULL) ? "" : igrace
3669b50d902SRodney W. Grimes );
367829b3f6bSDag-Erling Smørgrav if (msgb != NULL)
368f5374712SMike Pritchard free(bgrace);
369829b3f6bSDag-Erling Smørgrav if (msgi != NULL)
370f5374712SMike Pritchard free(igrace);
3719b50d902SRodney W. Grimes }
3722e1f5ad9SMike Pritchard if (!qflag && !rflag && lines == 0)
3739b50d902SRodney W. Grimes heading(type, id, name, "none");
374dfaa8068SMike Pritchard return (overquota);
3759b50d902SRodney W. Grimes }
3769b50d902SRodney W. Grimes
37777ae30e9SAlexander Langer static void
showrawquotas(int type,u_long id,struct quotause * qup)37861328d7aSXin LI showrawquotas(int type, u_long id, struct quotause *qup)
3792e1f5ad9SMike Pritchard {
380829b3f6bSDag-Erling Smørgrav time_t t;
38137ed8e48SKirk McKusick
3822e1f5ad9SMike Pritchard printf("Raw %s quota information for id %lu on %s\n",
3832e1f5ad9SMike Pritchard type == USRQUOTA ? "user" : "group", id, qup->fsname);
38437ed8e48SKirk McKusick printf("block hard limit: %ju\n",
38537ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_bhardlimit);
38637ed8e48SKirk McKusick printf("block soft limit: %ju\n",
38737ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_bsoftlimit);
38837ed8e48SKirk McKusick printf("current block count: %ju\n",
38937ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_curblocks);
39037ed8e48SKirk McKusick printf("i-node hard limit: %ju\n",
39137ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_ihardlimit);
39237ed8e48SKirk McKusick printf("i-node soft limit: %ju\n",
39337ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_isoftlimit);
39437ed8e48SKirk McKusick printf("current i-node count: %ju\n",
39537ed8e48SKirk McKusick (uintmax_t)qup->dqblk.dqb_curinodes);
39637ed8e48SKirk McKusick printf("block grace time: %jd",
39737ed8e48SKirk McKusick (intmax_t)qup->dqblk.dqb_btime);
398049aa2e8SOlivier Houchard if (qup->dqblk.dqb_btime != 0) {
399829b3f6bSDag-Erling Smørgrav t = qup->dqblk.dqb_btime;
400829b3f6bSDag-Erling Smørgrav printf(" %s", ctime(&t));
40137ed8e48SKirk McKusick } else {
4022e1f5ad9SMike Pritchard printf("\n");
40337ed8e48SKirk McKusick }
4042ffe6bbfSDavid Malone printf("i-node grace time: %jd", (intmax_t)qup->dqblk.dqb_itime);
405049aa2e8SOlivier Houchard if (qup->dqblk.dqb_itime != 0) {
406829b3f6bSDag-Erling Smørgrav t = qup->dqblk.dqb_itime;
407829b3f6bSDag-Erling Smørgrav printf(" %s", ctime(&t));
40837ed8e48SKirk McKusick } else {
4092e1f5ad9SMike Pritchard printf("\n");
4102e1f5ad9SMike Pritchard }
41137ed8e48SKirk McKusick }
4122e1f5ad9SMike Pritchard
4132e1f5ad9SMike Pritchard
4142e1f5ad9SMike Pritchard static void
heading(int type,u_long id,const char * name,const char * tag)415ff288009SMark Murray heading(int type, u_long id, const char *name, const char *tag)
4169b50d902SRodney W. Grimes {
4179b50d902SRodney W. Grimes
4181d00bf00SThomas Graichen printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type],
4199b50d902SRodney W. Grimes name, *qfextension[type], id, tag);
4209b50d902SRodney W. Grimes if (!qflag && tag[0] == '\0') {
42137ed8e48SKirk McKusick printf("%-15s %7s %8s %7s %7s %6s %7s %6s%8s\n"
4229b50d902SRodney W. Grimes , "Filesystem"
42344501248SJim Pirzyk , "usage"
4249b50d902SRodney W. Grimes , "quota"
4259b50d902SRodney W. Grimes , "limit"
4269b50d902SRodney W. Grimes , "grace"
4279b50d902SRodney W. Grimes , "files"
4289b50d902SRodney W. Grimes , "quota"
4299b50d902SRodney W. Grimes , "limit"
4309b50d902SRodney W. Grimes , "grace"
4319b50d902SRodney W. Grimes );
4329b50d902SRodney W. Grimes }
4339b50d902SRodney W. Grimes }
4349b50d902SRodney W. Grimes
4359b50d902SRodney W. Grimes /*
4369b50d902SRodney W. Grimes * Calculate the grace period and return a printable string for it.
4379b50d902SRodney W. Grimes */
438f5374712SMike Pritchard static char *
timeprt(int64_t seconds)439829b3f6bSDag-Erling Smørgrav timeprt(int64_t seconds)
4409b50d902SRodney W. Grimes {
4419b50d902SRodney W. Grimes time_t hours, minutes;
442f5374712SMike Pritchard char *buf;
4439b50d902SRodney W. Grimes static time_t now;
4449b50d902SRodney W. Grimes
4459b50d902SRodney W. Grimes if (now == 0)
4469b50d902SRodney W. Grimes time(&now);
447f5374712SMike Pritchard if (now > seconds) {
448829b3f6bSDag-Erling Smørgrav if ((buf = strdup("none")) == NULL)
449829b3f6bSDag-Erling Smørgrav errx(1, "strdup() failed in timeprt()");
450829b3f6bSDag-Erling Smørgrav return (buf);
451f5374712SMike Pritchard }
4529b50d902SRodney W. Grimes seconds -= now;
4539b50d902SRodney W. Grimes minutes = (seconds + 30) / 60;
4549b50d902SRodney W. Grimes hours = (minutes + 30) / 60;
4559b50d902SRodney W. Grimes if (hours >= 36) {
456f5374712SMike Pritchard if (asprintf(&buf, "%lddays", ((long)hours + 12) / 24) < 0)
457829b3f6bSDag-Erling Smørgrav errx(1, "asprintf() failed in timeprt(1)");
4589b50d902SRodney W. Grimes return (buf);
4599b50d902SRodney W. Grimes }
4609b50d902SRodney W. Grimes if (minutes >= 60) {
461f5374712SMike Pritchard if (asprintf(&buf, "%2ld:%ld", (long)minutes / 60,
462f5374712SMike Pritchard (long)minutes % 60) < 0)
463829b3f6bSDag-Erling Smørgrav errx(1, "asprintf() failed in timeprt(2)");
4649b50d902SRodney W. Grimes return (buf);
4659b50d902SRodney W. Grimes }
466f5374712SMike Pritchard if (asprintf(&buf, "%2ld", (long)minutes) < 0)
467829b3f6bSDag-Erling Smørgrav errx(1, "asprintf() failed in timeprt(3)");
4689b50d902SRodney W. Grimes return (buf);
4699b50d902SRodney W. Grimes }
4709b50d902SRodney W. Grimes
4719b50d902SRodney W. Grimes /*
4729b50d902SRodney W. Grimes * Collect the requested quota information.
4739b50d902SRodney W. Grimes */
47477ae30e9SAlexander Langer static struct quotause *
getprivs(long id,int quotatype)475ff288009SMark Murray getprivs(long id, int quotatype)
4769b50d902SRodney W. Grimes {
477e608ec61SIan Dowse struct quotause *qup, *quptail = NULL;
478ff288009SMark Murray struct fstab *fs;
4799b50d902SRodney W. Grimes struct quotause *quphead;
4809288f266SThomas Graichen struct statfs *fst;
4819288f266SThomas Graichen int nfst, i;
4822e1f5ad9SMike Pritchard struct statfs sfb;
4839b50d902SRodney W. Grimes
4849288f266SThomas Graichen qup = quphead = (struct quotause *)0;
4859288f266SThomas Graichen
4862e1f5ad9SMike Pritchard if (filename != NULL && statfs(filename, &sfb) != 0)
4872e1f5ad9SMike Pritchard err(1, "cannot statfs %s", filename);
488ab5ff6a6SIan Dowse nfst = getmntinfo(&fst, MNT_NOWAIT);
4899d63ad49SPhilippe Charnier if (nfst == 0)
4909d63ad49SPhilippe Charnier errx(2, "no filesystems mounted!");
4919b50d902SRodney W. Grimes setfsent();
4929288f266SThomas Graichen for (i = 0; i < nfst; i++) {
4939288f266SThomas Graichen if (qup == NULL) {
4941d00bf00SThomas Graichen if ((qup = (struct quotause *)malloc(sizeof *qup))
4959d63ad49SPhilippe Charnier == NULL)
4969d63ad49SPhilippe Charnier errx(2, "out of memory");
4979b50d902SRodney W. Grimes }
4982e1f5ad9SMike Pritchard /*
4992e1f5ad9SMike Pritchard * See if the user requested a specific file system
5002e1f5ad9SMike Pritchard * or specified a file inside a mounted file system.
5012e1f5ad9SMike Pritchard */
5022e1f5ad9SMike Pritchard if (filename != NULL &&
5032e1f5ad9SMike Pritchard strcmp(sfb.f_mntonname, fst[i].f_mntonname) != 0)
5042e1f5ad9SMike Pritchard continue;
505d63b9ba4SBruce Evans if (strcmp(fst[i].f_fstypename, "nfs") == 0) {
506e56990e4SIan Dowse if (lflag)
507e56990e4SIan Dowse continue;
5082e1f5ad9SMike Pritchard if (getnfsquota(&fst[i], qup, id, quotatype) == 0)
5099288f266SThomas Graichen continue;
510abf0f067SAndrey A. Chernov } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) {
5119b50d902SRodney W. Grimes /*
5129288f266SThomas Graichen * XXX
5139288f266SThomas Graichen * UFS filesystems must be in /etc/fstab, and must
5149288f266SThomas Graichen * indicate that they have quotas on (?!) This is quite
5159288f266SThomas Graichen * unlike SunOS where quotas can be enabled/disabled
5169288f266SThomas Graichen * on a filesystem independent of /etc/fstab, and it
5179288f266SThomas Graichen * will still print quotas for them.
5189b50d902SRodney W. Grimes */
5199288f266SThomas Graichen if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL)
5209b50d902SRodney W. Grimes continue;
521ff288009SMark Murray if (getufsquota(fs, qup, id, quotatype) == 0)
5229288f266SThomas Graichen continue;
5239288f266SThomas Graichen } else
5249288f266SThomas Graichen continue;
5259288f266SThomas Graichen strcpy(qup->fsname, fst[i].f_mntonname);
5269b50d902SRodney W. Grimes if (quphead == NULL)
5279b50d902SRodney W. Grimes quphead = qup;
5289b50d902SRodney W. Grimes else
5299b50d902SRodney W. Grimes quptail->next = qup;
5309b50d902SRodney W. Grimes quptail = qup;
5319288f266SThomas Graichen quptail->next = 0;
5329288f266SThomas Graichen qup = NULL;
5339b50d902SRodney W. Grimes }
5349288f266SThomas Graichen if (qup)
5359288f266SThomas Graichen free(qup);
5369b50d902SRodney W. Grimes endfsent();
5379b50d902SRodney W. Grimes return (quphead);
5389b50d902SRodney W. Grimes }
5399b50d902SRodney W. Grimes
5409b50d902SRodney W. Grimes /*
54137ed8e48SKirk McKusick * Check to see if a particular quota is available.
5429b50d902SRodney W. Grimes */
54377ae30e9SAlexander Langer static int
getufsquota(struct fstab * fs,struct quotause * qup,long id,int quotatype)544ff288009SMark Murray getufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype)
5459288f266SThomas Graichen {
54637ed8e48SKirk McKusick struct quotafile *qf;
5479288f266SThomas Graichen
54837ed8e48SKirk McKusick if ((qf = quota_open(fs, quotatype, O_RDONLY)) == NULL)
5499288f266SThomas Graichen return (0);
55037ed8e48SKirk McKusick if (quota_read(qf, &qup->dqblk, id) != 0)
5519288f266SThomas Graichen return (0);
55237ed8e48SKirk McKusick quota_close(qf);
5539288f266SThomas Graichen return (1);
5549288f266SThomas Graichen }
5559288f266SThomas Graichen
55677ae30e9SAlexander Langer static int
getnfsquota(struct statfs * fst,struct quotause * qup,long id,int quotatype)557ff288009SMark Murray getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype)
5589288f266SThomas Graichen {
559aad5531eSSean Eric Fagan struct ext_getquota_args gq_args;
560aad5531eSSean Eric Fagan struct getquota_args old_gq_args;
5619288f266SThomas Graichen struct getquota_rslt gq_rslt;
5629288f266SThomas Graichen struct dqblk *dqp = &qup->dqblk;
5639288f266SThomas Graichen struct timeval tv;
564754f368cSHiroki Sato char *cp, host[NI_MAXHOST];
565aad5531eSSean Eric Fagan enum clnt_stat call_stat;
5669288f266SThomas Graichen
5679288f266SThomas Graichen if (fst->f_flags & MNT_LOCAL)
5689288f266SThomas Graichen return (0);
5699288f266SThomas Graichen
5709288f266SThomas Graichen /*
5719288f266SThomas Graichen * must be some form of "hostname:/path"
5729288f266SThomas Graichen */
573754f368cSHiroki Sato cp = fst->f_mntfromname;
574754f368cSHiroki Sato do {
575754f368cSHiroki Sato cp = strrchr(cp, ':');
576754f368cSHiroki Sato } while (cp != NULL && *(cp + 1) != '/');
5779288f266SThomas Graichen if (cp == NULL) {
578b189011dSPhilippe Charnier warnx("cannot find hostname for %s", fst->f_mntfromname);
5799288f266SThomas Graichen return (0);
5809288f266SThomas Graichen }
581754f368cSHiroki Sato memset(host, 0, sizeof(host));
582754f368cSHiroki Sato memcpy(host, fst->f_mntfromname, cp - fst->f_mntfromname);
583754f368cSHiroki Sato host[sizeof(host) - 1] = '\0';
5849288f266SThomas Graichen
585ab5ff6a6SIan Dowse /* Avoid attempting the RPC for special amd(8) filesystems. */
586ab5ff6a6SIan Dowse if (strncmp(fst->f_mntfromname, "pid", 3) == 0 &&
587754f368cSHiroki Sato strchr(fst->f_mntfromname, '@') != NULL)
588ab5ff6a6SIan Dowse return (0);
589ab5ff6a6SIan Dowse
5909288f266SThomas Graichen gq_args.gqa_pathp = cp + 1;
591aad5531eSSean Eric Fagan gq_args.gqa_id = id;
592aad5531eSSean Eric Fagan gq_args.gqa_type = quotatype;
593aad5531eSSean Eric Fagan
594aad5531eSSean Eric Fagan call_stat = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS,
595aad5531eSSean Eric Fagan RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args, (char *)&gq_args,
596aad5531eSSean Eric Fagan (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
597740a5434SHiroki Sato if (call_stat == RPC_PROGVERSMISMATCH || call_stat == RPC_PROGNOTREGISTERED) {
598aad5531eSSean Eric Fagan if (quotatype == USRQUOTA) {
599aad5531eSSean Eric Fagan old_gq_args.gqa_pathp = cp + 1;
600aad5531eSSean Eric Fagan old_gq_args.gqa_uid = id;
601aad5531eSSean Eric Fagan call_stat = callaurpc(host, RQUOTAPROG, RQUOTAVERS,
602aad5531eSSean Eric Fagan RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&old_gq_args,
603aad5531eSSean Eric Fagan (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
604aad5531eSSean Eric Fagan } else {
605aad5531eSSean Eric Fagan /* Old rpc quota does not support group type */
6069288f266SThomas Graichen return (0);
607aad5531eSSean Eric Fagan }
608aad5531eSSean Eric Fagan }
609aad5531eSSean Eric Fagan if (call_stat != 0)
610aad5531eSSean Eric Fagan return (call_stat);
6119288f266SThomas Graichen
6129288f266SThomas Graichen switch (gq_rslt.status) {
6139288f266SThomas Graichen case Q_NOQUOTA:
6149288f266SThomas Graichen break;
6159288f266SThomas Graichen case Q_EPERM:
6169d63ad49SPhilippe Charnier warnx("quota permission error, host: %s",
6179288f266SThomas Graichen fst->f_mntfromname);
6189288f266SThomas Graichen break;
6199288f266SThomas Graichen case Q_OK:
6209288f266SThomas Graichen gettimeofday(&tv, NULL);
6219288f266SThomas Graichen /* blocks*/
6229288f266SThomas Graichen dqp->dqb_bhardlimit =
623404d2feeSConrad Meyer ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit *
624404d2feeSConrad Meyer gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6259288f266SThomas Graichen dqp->dqb_bsoftlimit =
626404d2feeSConrad Meyer ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit *
627404d2feeSConrad Meyer gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6289288f266SThomas Graichen dqp->dqb_curblocks =
629404d2feeSConrad Meyer ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks *
630404d2feeSConrad Meyer gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6319288f266SThomas Graichen /* inodes */
6329288f266SThomas Graichen dqp->dqb_ihardlimit =
6339288f266SThomas Graichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit;
6349288f266SThomas Graichen dqp->dqb_isoftlimit =
6359288f266SThomas Graichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit;
6369288f266SThomas Graichen dqp->dqb_curinodes =
6379288f266SThomas Graichen gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles;
6389288f266SThomas Graichen /* grace times */
6399288f266SThomas Graichen dqp->dqb_btime =
6409288f266SThomas Graichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft;
6419288f266SThomas Graichen dqp->dqb_itime =
6429288f266SThomas Graichen tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft;
6439288f266SThomas Graichen return (1);
6449288f266SThomas Graichen default:
645b189011dSPhilippe Charnier warnx("bad rpc result, host: %s", fst->f_mntfromname);
6469288f266SThomas Graichen break;
6479288f266SThomas Graichen }
648754f368cSHiroki Sato
6499288f266SThomas Graichen return (0);
6509288f266SThomas Graichen }
6519288f266SThomas Graichen
652aad5531eSSean Eric Fagan static enum clnt_stat
callaurpc(char * host,int prognum,int versnum,int procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out)653ff288009SMark Murray callaurpc(char *host, int prognum, int versnum, int procnum,
654ff288009SMark Murray xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
6559288f266SThomas Graichen {
6569288f266SThomas Graichen enum clnt_stat clnt_stat;
6579288f266SThomas Graichen struct timeval timeout, tottimeout;
6589288f266SThomas Graichen
6599288f266SThomas Graichen CLIENT *client = NULL;
6609288f266SThomas Graichen
661754f368cSHiroki Sato client = clnt_create(host, prognum, versnum, "udp");
662754f368cSHiroki Sato if (client == NULL)
663754f368cSHiroki Sato return ((int)rpc_createerr.cf_stat);
6649288f266SThomas Graichen timeout.tv_usec = 0;
6659288f266SThomas Graichen timeout.tv_sec = 6;
666754f368cSHiroki Sato CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
6679288f266SThomas Graichen
6689288f266SThomas Graichen client->cl_auth = authunix_create_default();
6699288f266SThomas Graichen tottimeout.tv_sec = 25;
6709288f266SThomas Graichen tottimeout.tv_usec = 0;
6719288f266SThomas Graichen clnt_stat = clnt_call(client, procnum, inproc, in,
6729288f266SThomas Graichen outproc, out, tottimeout);
673aad5531eSSean Eric Fagan return (clnt_stat);
6749288f266SThomas Graichen }
6759288f266SThomas Graichen
67677ae30e9SAlexander Langer static int
alldigits(char * s)677ff288009SMark Murray alldigits(char *s)
6789b50d902SRodney W. Grimes {
679ff288009SMark Murray int c;
6809b50d902SRodney W. Grimes
6819b50d902SRodney W. Grimes c = *s++;
6829b50d902SRodney W. Grimes do {
6839b50d902SRodney W. Grimes if (!isdigit(c))
6849b50d902SRodney W. Grimes return (0);
68577ae30e9SAlexander Langer } while ((c = *s++));
6869b50d902SRodney W. Grimes return (1);
6879b50d902SRodney W. Grimes }
688