]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/quota.c
xfs: fix maxicount division by zero error
[thirdparty/xfsprogs-dev.git] / quota / quota.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include <stdbool.h>
8 #include "command.h"
9 #include <ctype.h>
10 #include <pwd.h>
11 #include <grp.h>
12 #include "init.h"
13 #include "quota.h"
14
15 static cmdinfo_t quota_cmd;
16
17 static void
18 quota_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"
31 " -n -- skip identifier-to-name translations, just report IDs\n"
32 " -N -- suppress the initial header\n"
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
40 static int
41 quota_mount(
42 FILE *fp,
43 uint32_t id,
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
56 xfsquotactl(XFS_QSYNC, dev, type, 0, NULL);
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
169 static void
170 quota(
171 FILE *fp,
172 uint32_t id,
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
188 static char *
189 getusername(
190 uid_t uid,
191 int numeric)
192 {
193 static char buffer[32];
194
195 if (!numeric) {
196 struct passwd *u = getpwuid(uid);
197 if (u)
198 return u->pw_name;
199 }
200 snprintf(buffer, sizeof(buffer), "#%u", uid);
201 return &buffer[0];
202 }
203
204 static void
205 quota_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) {
216 if (isdigits_only(name)) {
217 id = atoi(name);
218 name = getusername(id, flags & NO_LOOKUP_FLAG);
219 } else if ((u = getpwnam(name))) {
220 id = u->pw_uid;
221 name = u->pw_name;
222 } else {
223 exitcode = 1;
224 fprintf(stderr, _("%s: cannot find user %s\n"),
225 progname, name);
226 return;
227 }
228 } else {
229 id = getuid();
230 name = getusername(id, flags & NO_LOOKUP_FLAG);
231 }
232
233 quota(fp, id, name, form, type, flags);
234 }
235
236 static char *
237 getgroupname(
238 gid_t gid,
239 int numeric)
240 {
241 static char buffer[32];
242
243 if (!numeric) {
244 struct group *g = getgrgid(gid);
245 if (g)
246 return g->gr_name;
247 }
248 snprintf(buffer, sizeof(buffer), "#%u", gid);
249 return &buffer[0];
250 }
251
252 static void
253 quota_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) {
265 if (isdigits_only(name)) {
266 gid = atoi(name);
267 name = getgroupname(gid, flags & NO_LOOKUP_FLAG);
268 } else {
269 if ((g = getgrnam(name))) {
270 gid = g->gr_gid;
271 name = g->gr_name;
272 } else {
273 exitcode = 1;
274 fprintf(stderr, _("%s: cannot find group %s\n"),
275 progname, name);
276 return;
277 }
278 }
279 gids = &gid;
280 ngroups = 1;
281 } else {
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 }
294 }
295
296 for (i = 0; i < ngroups; i++, name = NULL) {
297 if (!name)
298 name = getgroupname(gids[i], flags & NO_LOOKUP_FLAG);
299 quota(fp, gids[i], name, form, type, flags);
300 }
301
302 if (dofree)
303 free(gids);
304 }
305
306 static char *
307 getprojectname(
308 prid_t prid,
309 int numeric)
310 {
311 static char buffer[32];
312
313 if (!numeric) {
314 fs_project_t *p = getprprid(prid);
315 if (p)
316 return p->pr_name;
317 }
318 snprintf(buffer, sizeof(buffer), "#%u", (unsigned int)prid);
319 return &buffer[0];
320 }
321
322 static void
323 quota_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) {
334 exitcode = 1;
335 fprintf(stderr, _("%s: must specify a project name/ID\n"),
336 progname);
337 return;
338 }
339
340 if (isdigits_only(name)) {
341 id = atoi(name);
342 name = getprojectname(id, flags & NO_LOOKUP_FLAG);
343 } else if ((p = getprnam(name))) {
344 id = p->pr_prid;
345 name = p->pr_name;
346 } else {
347 exitcode = 1;
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
356 static void
357 quota_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
377 static int
378 quota_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
386 while ((c = getopt(argc, argv, "bf:ghnNipruv")) != EOF) {
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':
401 type |= XFS_GROUP_QUOTA;
402 break;
403 case 'p':
404 type |= XFS_PROJ_QUOTA;
405 break;
406 case 'u':
407 type |= XFS_USER_QUOTA;
408 break;
409 case 'h':
410 flags |= HUMAN_FLAG;
411 break;
412 case 'n':
413 flags |= NO_LOOKUP_FLAG;
414 break;
415 case 'N':
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
429 if (!type) {
430 type = XFS_USER_QUOTA;
431 } else if (type != XFS_GROUP_QUOTA &&
432 type != XFS_PROJ_QUOTA &&
433 type != XFS_USER_QUOTA) {
434 return command_usage(&quota_cmd);
435 }
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
450 void
451 quota_init(void)
452 {
453 quota_cmd.name = "quota";
454 quota_cmd.altname = "l";
455 quota_cmd.cfunc = quota_f;
456 quota_cmd.argmin = 0;
457 quota_cmd.argmax = -1;
458 quota_cmd.args = _("[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]...");
459 quota_cmd.oneline = _("show usage and limits");
460 quota_cmd.help = quota_help;
461 quota_cmd.flags = CMD_FLAG_FOREIGN_OK;
462
463 add_command(&quota_cmd);
464 }