Initial commit to Gerrit
[profile/ivi/quota.git] / quota.c
1 /*
2  * Copyright (c) 1980, 1990 Regents of the University of California. All
3  * rights reserved.
4  * 
5  * This code is derived from software contributed to Berkeley by Robert Elz at
6  * The University of Melbourne.
7  * 
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.
21  * 
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
32  * SUCH DAMAGE.
33  */
34
35 #include "config.h"
36
37 /*
38  * Disk quota reporting program.
39  */
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <getopt.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <time.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <unistd.h>
51 #ifdef RPC
52 #include <rpc/rpc.h>
53 #include "rquota.h"
54 #endif
55
56 #include "quota.h"
57 #include "quotaops.h"
58 #include "quotasys.h"
59 #include "pot.h"
60 #include "common.h"
61
62 #define FL_QUIET 1
63 #define FL_VERBOSE 2
64 #define FL_USER 4
65 #define FL_GROUP 8
66 #define FL_SMARTSIZE 16
67 #define FL_LOCALONLY 32
68 #define FL_QUIETREFUSE 64
69 #define FL_NOAUTOFS 128
70 #define FL_NOWRAP 256
71 #define FL_FSLIST 512
72 #define FL_NUMNAMES 1024
73 #define FL_NFSALL 2048
74 #define FL_RAWGRACE 4096
75 #define FL_NO_MIXED_PATHS 8192
76
77 int flags, fmt = -1;
78 char *progname;
79
80 void usage(void)
81 {
82         errstr( "%s%s%s%s%s",
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"),
87                 _("\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\
99                           not respond\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);
108         exit(1);
109 }
110
111 void heading(int type, qid_t id, char *name, char *tag)
112 {
113         char *spacehdr;
114
115         if (flags & FL_SMARTSIZE)
116                 spacehdr = _("space");
117         else
118                 spacehdr = _("blocks");
119
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"));
126         }
127 }
128
129 int showquotas(int type, qid_t id, int mntcnt, char **mnt)
130 {
131         struct dquot *qlist, *q;
132         char *msgi, *msgb;
133         char timebuf[MAXTIMELEN];
134         char name[MAXNAMELEN];
135         struct quota_handle **handles;
136         int lines = 0, bover, iover, over;
137         time_t now;
138
139         time(&now);
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));
147         over = 0;
148         for (q = qlist; q; q = q->dq_next) {
149                 bover = iover = 0;
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)
152                         continue;
153                 msgi = NULL;
154                 if (q->dq_dqb.dqb_ihardlimit && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_ihardlimit) {
155                         msgi = _("File limit reached on");
156                         iover = 1;
157                 }
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");
162                                 iover = 2;
163                         }
164                         else {
165                                 msgi = _("Over file quota on");
166                                 iover = 3;
167                         }
168                 }
169                 msgb = NULL;
170                 if (q->dq_dqb.dqb_bhardlimit && toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bhardlimit) {
171                                 msgb = _("Block limit reached on");
172                                 bover = 1;
173                 }
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");
178                                 bover = 2;
179                         }
180                         else {
181                                 msgb = _("Over block quota on");
182                                 bover = 3;
183                         }
184                 }
185                 over |= bover | iover;
186                 if (flags & FL_QUIET) {
187                         if ((msgi || msgb) && !lines++)
188                                 heading(type, id, name, "");
189                         if (msgi)
190                                 printf("\t%s %s\n", msgi, q->dq_h->qh_quotadev);
191                         if (msgb)
192                                 printf("\t%s %s\n", msgb, q->dq_h->qh_quotadev);
193                         continue;
194                 }
195                 if ((flags & FL_VERBOSE) || q->dq_dqb.dqb_curspace || q->dq_dqb.dqb_curinodes) {
196                         char numbuf[3][MAXNUMLEN];
197
198                         if (!lines++)
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, "");
202                         else
203                                 printf("%15s", q->dq_h->qh_quotadev);
204                         if (!(flags & FL_RAWGRACE)) {
205                                 if (bover)
206                                         difftime2str(q->dq_dqb.dqb_btime, timebuf);
207                                 else
208                                         timebuf[0] = 0;
209                         }
210                         else {
211                                 if (bover)
212                                         sprintf(timebuf, "%llu", (long long unsigned int)q->dq_dqb.dqb_btime);
213                                 else
214                                         strcpy(timebuf, "0");
215                         }
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],
220                                numbuf[2], timebuf);
221
222                         if (!(flags & FL_RAWGRACE)) {
223                                 if (iover)
224                                         difftime2str(q->dq_dqb.dqb_itime, timebuf);
225                                 else
226                                         timebuf[0] = 0;
227                         }
228                         else {
229                                 if (iover)
230                                         sprintf(timebuf, "%llu", (long long unsigned int)q->dq_dqb.dqb_itime);
231                                 else
232                                         strcpy(timebuf, "0");
233                         }
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],
238                                numbuf[2], timebuf);
239                         continue;
240                 }
241         }
242         if (!(flags & FL_QUIET) && !lines && qlist)
243                 heading(type, id, name, _("none"));
244         freeprivs(qlist);
245         dispose_handle_list(handles);
246         return over > 0 ? 1 : 0;
247 }
248
249 int main(int argc, char **argv)
250 {
251         int ngroups;
252         gid_t gidset[NGROUPS], *gidsetp;
253         int i, ret;
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' },
272                 { NULL, 0, NULL, 0 }
273         };
274
275         gettexton();
276         progname = basename(argv[0]);
277
278         while ((ret = getopt_long(argc, argv, "guqvsVliQF:wfApm", long_opts, NULL)) != -1) {
279                 switch (ret) {
280                   case 'g':
281                           flags |= FL_GROUP;
282                           break;
283                   case 'u':
284                           flags |= FL_USER;
285                           break;
286                   case 'q':
287                           flags |= FL_QUIET;
288                           break;
289                   case 'v':
290                           flags |= FL_VERBOSE;
291                           break;
292                   case 'F':
293                           if ((fmt = name2fmt(optarg)) == QF_ERROR)     /* Error? */
294                                   exit(1);
295                           break;
296                   case 's':
297                           flags |= FL_SMARTSIZE;
298                           break;
299                   case 'p':
300                           flags |= FL_RAWGRACE;
301                           break;
302                   case 256:
303                           flags |= FL_NUMNAMES;
304                           break;
305                   case 'l':
306                           flags |= FL_LOCALONLY;
307                           break;
308                   case 'Q':
309                           flags |= FL_QUIETREFUSE;
310                           break;
311                   case 'i':
312                           flags |= FL_NOAUTOFS;
313                           break;
314                   case 'w':
315                           flags |= FL_NOWRAP;
316                           break;
317                   case 'f':
318                           flags |= FL_FSLIST;
319                           break;
320                   case 'A':
321                           flags |= FL_NFSALL;
322                           break;
323                   case 'm':
324                           flags |= FL_NO_MIXED_PATHS;
325                           break;
326                   case 'V':
327                           version();
328                           exit(0);
329                   default:
330                           usage();
331                 }
332         }
333         argc -= optind;
334         argv += optind;
335
336         if (!(flags & FL_USER) && !(flags & FL_GROUP))
337                 flags |= FL_USER;
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');
340
341         init_kernel_interface();
342
343         ret = 0;
344         if (argc == 0 || flags & FL_FSLIST) {
345                 if (flags & FL_FSLIST && argc == 0)
346                         die(1, _("No filesystem specified.\n"));
347                 if (flags & FL_USER)
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));
353                                 if (!gidsetp)
354                                         die(1, _("Gid set allocation (%d): %s\n"), ngroups, strerror(errno));
355                         } else {
356                                 gidsetp = &gidset[0];
357                         }
358                         ngroups = getgroups(ngroups, gidsetp);
359                         if (ngroups < 0)
360                                 die(1, _("getgroups(): %s\n"), strerror(errno));
361                         for (i = 0; i < ngroups; i++)
362                                 ret |= showquotas(GRPQUOTA, gidsetp[i], argc, argv);
363                 }
364                 exit(ret);
365         }
366
367         if ((flags & FL_USER) && (flags & FL_GROUP))
368                 usage();
369
370         if (flags & FL_USER)
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);
376         return ret;
377 }