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