2 * Copyright (c) 1980, 1990 Regents of the University of California. All
5 * This code is derived from software contributed to Berkeley by Robert Elz at
6 * The University of Melbourne.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution. 3. All advertising
15 * materials mentioning features or use of this software must display the
16 * following acknowledgement: This product includes software developed by the
17 * University of California, Berkeley and its contributors. 4. Neither the
18 * name of the University nor the names of its contributors may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Disk quota reporting program.
40 #include <sys/types.h>
41 #include <sys/param.h>
66 #define FL_SMARTSIZE 16
67 #define FL_LOCALONLY 32
68 #define FL_QUIETREFUSE 64
69 #define FL_NOAUTOFS 128
72 #define FL_NUMNAMES 1024
73 #define FL_NFSALL 2048
74 #define FL_RAWGRACE 4096
75 #define FL_NO_MIXED_PATHS 8192
83 _("Usage: quota [-guqvswim] [-l | [-Q | -A]] [-F quotaformat]\n"),
84 _("\tquota [-qvswim] [-l | [-Q | -A]] [-F quotaformat] -u username ...\n"),
85 _("\tquota [-qvswim] [-l | [-Q | -A]] [-F quotaformat] -g groupname ...\n"),
86 _("\tquota [-qvswugQm] [-F quotaformat] -f filesystem ...\n"),
88 -u, --user display quota for user\n\
89 -g, --group display quota for group\n\
90 -q, --quiet print more terse message\n\
91 -v, --verbose print more verbose message\n\
92 -s, --human-readable display numbers in human friendly units (MB, GB...)\n\
93 --always-resolve always try to translate name to id, even if it is\n\
94 composed of only digits\n\
95 -w, --no-wrap do not wrap long lines\n\
96 -p, --raw-grace print grace time in seconds since epoch\n\
97 -l, --local-only do not query NFS filesystems\n\
98 -Q, --quiet-refuse do not print error message when NFS server does\n\
100 -i, --no-autofs do not query autofs mountpoints\n\
101 -F, --format=formatname display quota of a specific format\n\
102 -f, --filesystem-list display quota information only for given filesystems\n\
103 -A, --nfs-all display quota for all NFS mountpoints\n\
104 -m, --no-mixed-pathnames trim leading slashes from NFSv4 mountpoints\n\
105 -h, --help display this help message and exit\n\
106 -V, --version display version information and exit\n\n"));
107 fprintf(stderr, _("Bugs to: %s\n"), MY_EMAIL);
111 void heading(int type, qid_t id, char *name, char *tag)
115 if (flags & FL_SMARTSIZE)
116 spacehdr = _("space");
118 spacehdr = _("blocks");
120 printf(_("Disk quotas for %s %s (%cid %u): %s\n"), type2name(type),
121 name, *type2name(type), (uint) id, tag);
122 if (!(flags & FL_QUIET) && !tag[0]) {
123 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n", _("Filesystem"),
124 spacehdr,_("quota"), _("limit"), _("grace"),
125 _("files"), _("quota"), _("limit"), _("grace"));
129 int showquotas(int type, qid_t id, int mntcnt, char **mnt)
131 struct dquot *qlist, *q;
133 char timebuf[MAXTIMELEN];
134 char name[MAXNAMELEN];
135 struct quota_handle **handles;
136 int lines = 0, bover, iover, over;
140 id2name(id, type, name);
141 handles = create_handle_list(mntcnt, mnt, type, fmt,
142 IOI_READONLY | ((flags & FL_NO_MIXED_PATHS) ? 0 : IOI_NFS_MIXED_PATHS),
143 ((flags & FL_NOAUTOFS) ? MS_NO_AUTOFS : 0)
144 | ((flags & FL_LOCALONLY) ? MS_LOCALONLY : 0)
145 | ((flags & FL_NFSALL) ? MS_NFS_ALL : 0));
146 qlist = getprivs(id, handles, !!(flags & FL_QUIETREFUSE));
148 for (q = qlist; q; q = q->dq_next) {
150 if (!(flags & FL_VERBOSE) && !q->dq_dqb.dqb_isoftlimit && !q->dq_dqb.dqb_ihardlimit
151 && !q->dq_dqb.dqb_bsoftlimit && !q->dq_dqb.dqb_bhardlimit)
154 if (q->dq_dqb.dqb_ihardlimit && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_ihardlimit) {
155 msgi = _("File limit reached on");
158 else if (q->dq_dqb.dqb_isoftlimit
159 && q->dq_dqb.dqb_curinodes > q->dq_dqb.dqb_isoftlimit) {
160 if (q->dq_dqb.dqb_itime > now) {
161 msgi = _("In file grace period on");
165 msgi = _("Over file quota on");
170 if (q->dq_dqb.dqb_bhardlimit && toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bhardlimit) {
171 msgb = _("Block limit reached on");
174 else if (q->dq_dqb.dqb_bsoftlimit
175 && toqb(q->dq_dqb.dqb_curspace) > q->dq_dqb.dqb_bsoftlimit) {
176 if (q->dq_dqb.dqb_btime > now) {
177 msgb = _("In block grace period on");
181 msgb = _("Over block quota on");
185 over |= bover | iover;
186 if (flags & FL_QUIET) {
187 if ((msgi || msgb) && !lines++)
188 heading(type, id, name, "");
190 printf("\t%s %s\n", msgi, q->dq_h->qh_quotadev);
192 printf("\t%s %s\n", msgb, q->dq_h->qh_quotadev);
195 if ((flags & FL_VERBOSE) || q->dq_dqb.dqb_curspace || q->dq_dqb.dqb_curinodes) {
196 char numbuf[3][MAXNUMLEN];
199 heading(type, id, name, "");
200 if (strlen(q->dq_h->qh_quotadev) > 15 && !(flags & FL_NOWRAP))
201 printf("%s\n%15s", q->dq_h->qh_quotadev, "");
203 printf("%15s", q->dq_h->qh_quotadev);
204 if (!(flags & FL_RAWGRACE)) {
206 difftime2str(q->dq_dqb.dqb_btime, timebuf);
212 sprintf(timebuf, "%llu", (long long unsigned int)q->dq_dqb.dqb_btime);
214 strcpy(timebuf, "0");
216 space2str(toqb(q->dq_dqb.dqb_curspace), numbuf[0], !!(flags & FL_SMARTSIZE));
217 space2str(q->dq_dqb.dqb_bsoftlimit, numbuf[1], !!(flags & FL_SMARTSIZE));
218 space2str(q->dq_dqb.dqb_bhardlimit, numbuf[2], !!(flags & FL_SMARTSIZE));
219 printf(" %7s%c %6s %7s %7s", numbuf[0], bover ? '*' : ' ', numbuf[1],
222 if (!(flags & FL_RAWGRACE)) {
224 difftime2str(q->dq_dqb.dqb_itime, timebuf);
230 sprintf(timebuf, "%llu", (long long unsigned int)q->dq_dqb.dqb_itime);
232 strcpy(timebuf, "0");
234 number2str(q->dq_dqb.dqb_curinodes, numbuf[0], !!(flags & FL_SMARTSIZE));
235 number2str(q->dq_dqb.dqb_isoftlimit, numbuf[1], !!(flags & FL_SMARTSIZE));
236 number2str(q->dq_dqb.dqb_ihardlimit, numbuf[2], !!(flags & FL_SMARTSIZE));
237 printf(" %7s%c %6s %7s %7s\n", numbuf[0], iover ? '*' : ' ', numbuf[1],
242 if (!(flags & FL_QUIET) && !lines && qlist)
243 heading(type, id, name, _("none"));
245 dispose_handle_list(handles);
246 return over > 0 ? 1 : 0;
249 int main(int argc, char **argv)
252 gid_t gidset[NGROUPS], *gidsetp;
254 struct option long_opts[] = {
255 { "help", 0, NULL, 'h' },
256 { "version", 0, NULL, 'V' },
257 { "user", 0, NULL, 'u' },
258 { "group", 0, NULL, 'g' },
259 { "quiet", 0, NULL, 'q' },
260 { "verbose", 0, NULL, 'v' },
261 { "human-readable", 0, NULL, 's' },
262 { "always-resolve", 0, NULL, 256 },
263 { "raw-grace", 0, NULL, 'p' },
264 { "local-only", 0, NULL, 'l' },
265 { "no-autofs", 0, NULL, 'i' },
266 { "quiet-refuse", 0, NULL, 'Q' },
267 { "format", 1, NULL, 'F' },
268 { "no-wrap", 0, NULL, 'w' },
269 { "filesystem-list", 0, NULL, 'f' },
270 { "all-nfs", 0, NULL, 'A' },
271 { "no-mixed-pathnames", 0, NULL, 'm' },
276 progname = basename(argv[0]);
278 while ((ret = getopt_long(argc, argv, "guqvsVliQF:wfApm", long_opts, NULL)) != -1) {
293 if ((fmt = name2fmt(optarg)) == QF_ERROR) /* Error? */
297 flags |= FL_SMARTSIZE;
300 flags |= FL_RAWGRACE;
303 flags |= FL_NUMNAMES;
306 flags |= FL_LOCALONLY;
309 flags |= FL_QUIETREFUSE;
312 flags |= FL_NOAUTOFS;
324 flags |= FL_NO_MIXED_PATHS;
336 if (!(flags & FL_USER) && !(flags & FL_GROUP))
338 if (flags & FL_FSLIST && flags & (FL_LOCALONLY | FL_NOAUTOFS))
339 errstr(_("Warning: Ignoring -%c when filesystem list specified.\n"), flags & FL_LOCALONLY ? 'l' : 'i');
341 init_kernel_interface();
344 if (argc == 0 || flags & FL_FSLIST) {
345 if (flags & FL_FSLIST && argc == 0)
346 die(1, _("No filesystem specified.\n"));
348 ret |= showquotas(USRQUOTA, getuid(), argc, argv);
349 if (flags & FL_GROUP) {
350 ngroups = sysconf(_SC_NGROUPS_MAX);
351 if (ngroups > NGROUPS) {
352 gidsetp = malloc(ngroups * sizeof(gid_t));
354 die(1, _("Gid set allocation (%d): %s\n"), ngroups, strerror(errno));
356 gidsetp = &gidset[0];
358 ngroups = getgroups(ngroups, gidsetp);
360 die(1, _("getgroups(): %s\n"), strerror(errno));
361 for (i = 0; i < ngroups; i++)
362 ret |= showquotas(GRPQUOTA, gidsetp[i], argc, argv);
367 if ((flags & FL_USER) && (flags & FL_GROUP))
371 for (; argc > 0; argc--, argv++)
372 ret |= showquotas(USRQUOTA, user2uid(*argv, !!(flags & FL_NUMNAMES), NULL), 0, NULL);
373 else if (flags & FL_GROUP)
374 for (; argc > 0; argc--, argv++)
375 ret |= showquotas(GRPQUOTA, group2gid(*argv, !!(flags & FL_NUMNAMES), NULL), 0, NULL);