]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/quota.c
libxcmd: don't check generic library commands
[thirdparty/xfsprogs-dev.git] / quota / quota.c
CommitLineData
5aead01d 1/*
da23017d
NS
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
5aead01d 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
5aead01d
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
5aead01d 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
5aead01d
NS
17 */
18
29647c8d 19#include <stdbool.h>
6b803e5a 20#include "command.h"
5aead01d
NS
21#include <ctype.h>
22#include <pwd.h>
23#include <grp.h>
24#include "init.h"
25#include "quota.h"
26
27static cmdinfo_t quota_cmd;
28
29static void
30quota_help(void)
31{
32 printf(_(
33"\n"
34" display usage and quota information\n"
35"\n"
36" -g -- display group quota information\n"
37" -p -- display project quota information\n"
38" -u -- display user quota information\n"
39" -b -- display number of blocks used\n"
40" -i -- display number of inodes used\n"
41" -r -- display number of realtime blocks used\n"
42" -h -- report in a human-readable format\n"
1774874a
NS
43" -n -- skip identifier-to-name translations, just report IDs\n"
44" -N -- suppress the initial header\n"
5aead01d
NS
45" -v -- increase verbosity in reporting (also dumps zero values)\n"
46" -f -- send output to a file\n"
47" The (optional) user/group/project can be specified either by name or by\n"
48" number (i.e. uid/gid/projid).\n"
49"\n"));
50}
51
52static int
53quota_mount(
54 FILE *fp,
55 __uint32_t id,
56 char *name,
57 uint form,
58 uint type,
59 fs_path_t *mount,
60 uint flags)
61{
62 fs_disk_quota_t d;
63 char *dev = mount->fs_name;
64 char c[8], h[8], s[8];
65 uint qflags;
66 int count;
67
546bedf4 68 xfsquotactl(XFS_QSYNC, dev, type, 0, NULL);
5aead01d
NS
69 if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0)
70 return 0;
71
72 if (!(flags & VERBOSE_FLAG)) {
73 count = 0;
74 if ((form & XFS_BLOCK_QUOTA) && d.d_bcount)
75 count++;
76 if ((form & XFS_INODE_QUOTA) && d.d_icount)
77 count++;
78 if ((form & XFS_RTBLOCK_QUOTA) && d.d_rtbcount)
79 count++;
80 if (!count)
81 return 0;
82 }
83
84 if (!(flags & NO_HEADER_FLAG)) {
85 fprintf(fp,
86 _("Disk quotas for %s %s (%u)\nFilesystem%s"),
87 type_to_string(type), name, id,
88 (flags & HUMAN_FLAG) ? " " : " ");
89 if (form & XFS_BLOCK_QUOTA)
90 fprintf(fp, (flags & HUMAN_FLAG) ?
91 _(" Blocks Quota Limit Warn/Time ") :
92 _(" Blocks Quota Limit Warn/Time "));
93 if (form & XFS_INODE_QUOTA)
94 fprintf(fp, (flags & HUMAN_FLAG) ?
95 _(" Files Quota Limit Warn/Time ") :
96 _(" Files Quota Limit Warn/Time "));
97 if (form & XFS_RTBLOCK_QUOTA)
98 fprintf(fp, (flags & HUMAN_FLAG) ?
99 _("Realtime Quota Limit Warn/Time ") :
100 _(" Realtime Quota Limit Warn/Time "));
101 fputs("Mounted on\n", fp);
102 }
103
104 if (flags & HUMAN_FLAG) {
105 count = fprintf(fp, "%-12s", dev);
106 if (count > 13)
107 fprintf(fp, "\n%12s", " ");
108 } else {
109 count = fprintf(fp, "%-19s", dev);
110 if (count > 20)
111 fprintf(fp, "\n%19s", " ");
112 }
113
114 if (form & XFS_BLOCK_QUOTA) {
115 qflags = (flags & HUMAN_FLAG);
116 if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
117 qflags |= LIMIT_FLAG;
118 if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
119 qflags |= QUOTA_FLAG;
120 if (flags & HUMAN_FLAG)
121 fprintf(fp, " %6s %6s %6s %02d %8s ",
122 bbs_to_string(d.d_bcount, c, sizeof(c)),
123 bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
124 bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
125 d.d_bwarns,
126 time_to_string(d.d_btimer, qflags));
127 else
128 fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
129 (unsigned long long)d.d_bcount >> 1,
130 (unsigned long long)d.d_blk_softlimit >> 1,
131 (unsigned long long)d.d_blk_hardlimit >> 1,
132 d.d_bwarns,
133 time_to_string(d.d_btimer, qflags));
134 }
135 if (form & XFS_INODE_QUOTA) {
136 qflags = (flags & HUMAN_FLAG);
137 if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
138 qflags |= LIMIT_FLAG;
139 if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
140 qflags |= QUOTA_FLAG;
141 if (flags & HUMAN_FLAG)
142 fprintf(fp, " %6s %6s %6s %02d %8s ",
143 num_to_string(d.d_icount, c, sizeof(c)),
144 num_to_string(d.d_ino_softlimit, s, sizeof(s)),
145 num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
146 d.d_iwarns,
147 time_to_string(d.d_itimer, qflags));
148 else
149 fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
150 (unsigned long long)d.d_icount,
151 (unsigned long long)d.d_ino_softlimit,
152 (unsigned long long)d.d_ino_hardlimit,
153 d.d_iwarns,
154 time_to_string(d.d_itimer, qflags));
155 }
156 if (form & XFS_RTBLOCK_QUOTA) {
157 qflags = (flags & HUMAN_FLAG);
158 if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
159 qflags |= LIMIT_FLAG;
160 if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
161 qflags |= QUOTA_FLAG;
162 if (flags & HUMAN_FLAG)
163 fprintf(fp, " %6s %6s %6s %02d %8s ",
164 bbs_to_string(d.d_rtbcount, c, sizeof(c)),
165 bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
166 bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
167 d.d_rtbwarns,
168 time_to_string(d.d_rtbtimer, qflags));
169 else
170 fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
171 (unsigned long long)d.d_rtbcount >> 1,
172 (unsigned long long)d.d_rtb_softlimit >> 1,
173 (unsigned long long)d.d_rtb_hardlimit >> 1,
174 d.d_rtbwarns,
175 time_to_string(d.d_rtbtimer, qflags));
176 }
177 fprintf(fp, "%s\n", mount->fs_dir);
178 return 1;
179}
180
181static void
182quota(
183 FILE *fp,
184 __uint32_t id,
185 char *name,
186 uint form,
187 uint type,
188 uint flags)
189{
190 fs_cursor_t cursor;
191 fs_path_t *path;
192
193 fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor);
194 while ((path = fs_cursor_next_entry(&cursor))) {
195 if (quota_mount(fp, id, name, form, type, path, flags))
196 flags |= NO_HEADER_FLAG;
197 }
198}
199
200static char *
201getusername(
1774874a
NS
202 uid_t uid,
203 int numeric)
5aead01d
NS
204{
205 static char buffer[32];
5aead01d 206
6672a605
BN
207 if (!numeric) {
208 struct passwd *u = getpwuid(uid);
209 if (u)
210 return u->pw_name;
211 }
5aead01d
NS
212 snprintf(buffer, sizeof(buffer), "#%u", uid);
213 return &buffer[0];
214}
215
216static void
217quota_user_type(
218 FILE *fp,
219 char *name,
220 uint form,
221 uint type,
222 uint flags)
223{
224 struct passwd *u;
225 uid_t id;
226
227 if (name) {
fd537fc5 228 if (isdigits_only(name)) {
5aead01d 229 id = atoi(name);
1774874a 230 name = getusername(id, flags & NO_LOOKUP_FLAG);
5aead01d
NS
231 } else if ((u = getpwnam(name))) {
232 id = u->pw_uid;
233 name = u->pw_name;
234 } else {
e3210fd8 235 exitcode = 1;
5aead01d
NS
236 fprintf(stderr, _("%s: cannot find user %s\n"),
237 progname, name);
238 return;
239 }
240 } else {
241 id = getuid();
1774874a 242 name = getusername(id, flags & NO_LOOKUP_FLAG);
5aead01d
NS
243 }
244
245 quota(fp, id, name, form, type, flags);
246}
247
248static char *
249getgroupname(
1774874a
NS
250 gid_t gid,
251 int numeric)
5aead01d
NS
252{
253 static char buffer[32];
5aead01d 254
6672a605
BN
255 if (!numeric) {
256 struct group *g = getgrgid(gid);
257 if (g)
258 return g->gr_name;
259 }
5aead01d
NS
260 snprintf(buffer, sizeof(buffer), "#%u", gid);
261 return &buffer[0];
262}
263
264static void
265quota_group_type(
266 FILE *fp,
267 char *name,
268 uint form,
269 uint type,
270 uint flags)
271{
272 struct group *g;
273 gid_t gid, *gids = NULL;
274 int i, ngroups, dofree = 0;
275
276 if (name) {
fd537fc5 277 if (isdigits_only(name)) {
5aead01d 278 gid = atoi(name);
1774874a 279 name = getgroupname(gid, flags & NO_LOOKUP_FLAG);
5aead01d
NS
280 } else {
281 if ((g = getgrnam(name))) {
282 gid = g->gr_gid;
283 name = g->gr_name;
284 } else {
e3210fd8 285 exitcode = 1;
5aead01d
NS
286 fprintf(stderr, _("%s: cannot find group %s\n"),
287 progname, name);
288 return;
289 }
290 }
291 gids = &gid;
292 ngroups = 1;
5aead01d 293 } else {
f6a8b88b
ES
294 if ( ((ngroups = sysconf(_SC_NGROUPS_MAX)) < 0) ||
295 ((gids = malloc(ngroups * sizeof(gid_t))) == NULL) ||
296 ((ngroups = getgroups(ngroups, gids)) < 0)) {
297 /* something failed. Fall back to 1 group */
298 free(gids);
299 gid = getgid();
300 gids = &gid;
301 ngroups = 1;
302 } else {
303 /* It all worked, and we allocated memory */
304 dofree = 1;
305 }
5aead01d
NS
306 }
307
308 for (i = 0; i < ngroups; i++, name = NULL) {
309 if (!name)
1774874a 310 name = getgroupname(gids[i], flags & NO_LOOKUP_FLAG);
5aead01d
NS
311 quota(fp, gids[i], name, form, type, flags);
312 }
313
314 if (dofree)
315 free(gids);
316}
317
318static char *
319getprojectname(
1774874a
NS
320 prid_t prid,
321 int numeric)
5aead01d
NS
322{
323 static char buffer[32];
5aead01d 324
6672a605
BN
325 if (!numeric) {
326 fs_project_t *p = getprprid(prid);
327 if (p)
328 return p->pr_name;
329 }
2a1888c5 330 snprintf(buffer, sizeof(buffer), "#%u", (unsigned int)prid);
5aead01d
NS
331 return &buffer[0];
332}
333
334static void
335quota_proj_type(
336 FILE *fp,
337 char *name,
338 uint form,
339 uint type,
340 uint flags)
341{
342 fs_project_t *p;
343 prid_t id;
344
345 if (!name) {
e3210fd8 346 exitcode = 1;
5aead01d
NS
347 fprintf(stderr, _("%s: must specify a project name/ID\n"),
348 progname);
349 return;
350 }
351
fd537fc5 352 if (isdigits_only(name)) {
5aead01d 353 id = atoi(name);
1774874a 354 name = getprojectname(id, flags & NO_LOOKUP_FLAG);
5aead01d
NS
355 } else if ((p = getprnam(name))) {
356 id = p->pr_prid;
357 name = p->pr_name;
358 } else {
e3210fd8 359 exitcode = 1;
5aead01d
NS
360 fprintf(stderr, _("%s: cannot find project %s\n"),
361 progname, name);
362 return;
363 }
364
365 quota(fp, id, name, form, type, flags);
366}
367
368static void
369quota_any_type(
370 FILE *fp,
371 char *name,
372 uint form,
373 uint type,
374 uint flags)
375{
376 switch (type) {
377 case XFS_USER_QUOTA:
378 quota_user_type(fp, name, form, type, flags);
379 break;
380 case XFS_GROUP_QUOTA:
381 quota_group_type(fp, name, form, type, flags);
382 break;
383 case XFS_PROJ_QUOTA:
384 quota_proj_type(fp, name, form, type, flags);
385 break;
386 }
387}
388
389static int
390quota_f(
391 int argc,
392 char **argv)
393{
394 FILE *fp = NULL;
395 char *fname = NULL;
396 int c, flags = 0, type = 0, form = 0;
397
1774874a 398 while ((c = getopt(argc, argv, "bf:ghnNipruv")) != EOF) {
5aead01d
NS
399 switch (c) {
400 case 'f':
401 fname = optarg;
402 break;
403 case 'b':
404 form |= XFS_BLOCK_QUOTA;
405 break;
406 case 'i':
407 form |= XFS_INODE_QUOTA;
408 break;
409 case 'r':
410 form |= XFS_RTBLOCK_QUOTA;
411 break;
412 case 'g':
c614d3bf 413 type |= XFS_GROUP_QUOTA;
5aead01d
NS
414 break;
415 case 'p':
c614d3bf 416 type |= XFS_PROJ_QUOTA;
5aead01d
NS
417 break;
418 case 'u':
c614d3bf 419 type |= XFS_USER_QUOTA;
5aead01d
NS
420 break;
421 case 'h':
422 flags |= HUMAN_FLAG;
423 break;
424 case 'n':
1774874a
NS
425 flags |= NO_LOOKUP_FLAG;
426 break;
427 case 'N':
5aead01d
NS
428 flags |= NO_HEADER_FLAG;
429 break;
430 case 'v':
431 flags |= VERBOSE_FLAG;
432 break;
433 default:
434 return command_usage(&quota_cmd);
435 }
436 }
437
438 if (!form)
439 form = XFS_BLOCK_QUOTA;
440
c614d3bf 441 if (!type) {
5aead01d 442 type = XFS_USER_QUOTA;
c614d3bf
ZL
443 } else if (type != XFS_GROUP_QUOTA &&
444 type != XFS_PROJ_QUOTA &&
445 type != XFS_USER_QUOTA) {
446 return command_usage(&quota_cmd);
447 }
5aead01d
NS
448
449 if ((fp = fopen_write_secure(fname)) == NULL)
450 return 0;
451
452 if (argc == optind)
453 quota_any_type(fp, NULL, form, type, flags);
454 else while (argc > optind)
455 quota_any_type(fp, argv[optind++], form, type, flags);
456
457 if (fname)
458 fclose(fp);
459 return 0;
460}
461
462void
463quota_init(void)
464{
ad765595
AM
465 quota_cmd.name = "quota";
466 quota_cmd.altname = "l";
5aead01d
NS
467 quota_cmd.cfunc = quota_f;
468 quota_cmd.argmin = 0;
469 quota_cmd.argmax = -1;
c614d3bf 470 quota_cmd.args = _("[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]...");
5aead01d
NS
471 quota_cmd.oneline = _("show usage and limits");
472 quota_cmd.help = quota_help;
29647c8d 473 quota_cmd.flags = CMD_FLAG_FOREIGN_OK;
5aead01d
NS
474
475 add_command(&quota_cmd);
476}