]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/quota.c
xfs_scrub: use Unicode skeleton function to find confusing names
[thirdparty/xfsprogs-dev.git] / quota / quota.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include <stdbool.h>
20 #include "command.h"
21 #include <ctype.h>
22 #include <pwd.h>
23 #include <grp.h>
24 #include "init.h"
25 #include "quota.h"
26
27 static cmdinfo_t quota_cmd;
28
29 static void
30 quota_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"
43 " -n -- skip identifier-to-name translations, just report IDs\n"
44 " -N -- suppress the initial header\n"
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
52 static int
53 quota_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
68 xfsquotactl(XFS_QSYNC, dev, type, 0, NULL);
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
181 static void
182 quota(
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
200 static char *
201 getusername(
202 uid_t uid,
203 int numeric)
204 {
205 static char buffer[32];
206
207 if (!numeric) {
208 struct passwd *u = getpwuid(uid);
209 if (u)
210 return u->pw_name;
211 }
212 snprintf(buffer, sizeof(buffer), "#%u", uid);
213 return &buffer[0];
214 }
215
216 static void
217 quota_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) {
228 if (isdigits_only(name)) {
229 id = atoi(name);
230 name = getusername(id, flags & NO_LOOKUP_FLAG);
231 } else if ((u = getpwnam(name))) {
232 id = u->pw_uid;
233 name = u->pw_name;
234 } else {
235 exitcode = 1;
236 fprintf(stderr, _("%s: cannot find user %s\n"),
237 progname, name);
238 return;
239 }
240 } else {
241 id = getuid();
242 name = getusername(id, flags & NO_LOOKUP_FLAG);
243 }
244
245 quota(fp, id, name, form, type, flags);
246 }
247
248 static char *
249 getgroupname(
250 gid_t gid,
251 int numeric)
252 {
253 static char buffer[32];
254
255 if (!numeric) {
256 struct group *g = getgrgid(gid);
257 if (g)
258 return g->gr_name;
259 }
260 snprintf(buffer, sizeof(buffer), "#%u", gid);
261 return &buffer[0];
262 }
263
264 static void
265 quota_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) {
277 if (isdigits_only(name)) {
278 gid = atoi(name);
279 name = getgroupname(gid, flags & NO_LOOKUP_FLAG);
280 } else {
281 if ((g = getgrnam(name))) {
282 gid = g->gr_gid;
283 name = g->gr_name;
284 } else {
285 exitcode = 1;
286 fprintf(stderr, _("%s: cannot find group %s\n"),
287 progname, name);
288 return;
289 }
290 }
291 gids = &gid;
292 ngroups = 1;
293 } else {
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 }
306 }
307
308 for (i = 0; i < ngroups; i++, name = NULL) {
309 if (!name)
310 name = getgroupname(gids[i], flags & NO_LOOKUP_FLAG);
311 quota(fp, gids[i], name, form, type, flags);
312 }
313
314 if (dofree)
315 free(gids);
316 }
317
318 static char *
319 getprojectname(
320 prid_t prid,
321 int numeric)
322 {
323 static char buffer[32];
324
325 if (!numeric) {
326 fs_project_t *p = getprprid(prid);
327 if (p)
328 return p->pr_name;
329 }
330 snprintf(buffer, sizeof(buffer), "#%u", (unsigned int)prid);
331 return &buffer[0];
332 }
333
334 static void
335 quota_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) {
346 exitcode = 1;
347 fprintf(stderr, _("%s: must specify a project name/ID\n"),
348 progname);
349 return;
350 }
351
352 if (isdigits_only(name)) {
353 id = atoi(name);
354 name = getprojectname(id, flags & NO_LOOKUP_FLAG);
355 } else if ((p = getprnam(name))) {
356 id = p->pr_prid;
357 name = p->pr_name;
358 } else {
359 exitcode = 1;
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
368 static void
369 quota_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
389 static int
390 quota_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
398 while ((c = getopt(argc, argv, "bf:ghnNipruv")) != EOF) {
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':
413 type |= XFS_GROUP_QUOTA;
414 break;
415 case 'p':
416 type |= XFS_PROJ_QUOTA;
417 break;
418 case 'u':
419 type |= XFS_USER_QUOTA;
420 break;
421 case 'h':
422 flags |= HUMAN_FLAG;
423 break;
424 case 'n':
425 flags |= NO_LOOKUP_FLAG;
426 break;
427 case 'N':
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
441 if (!type) {
442 type = XFS_USER_QUOTA;
443 } else if (type != XFS_GROUP_QUOTA &&
444 type != XFS_PROJ_QUOTA &&
445 type != XFS_USER_QUOTA) {
446 return command_usage(&quota_cmd);
447 }
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
462 void
463 quota_init(void)
464 {
465 quota_cmd.name = "quota";
466 quota_cmd.altname = "l";
467 quota_cmd.cfunc = quota_f;
468 quota_cmd.argmin = 0;
469 quota_cmd.argmax = -1;
470 quota_cmd.args = _("[-bir] [-g|-p|-u] [-hnNv] [-f file] [id|name]...");
471 quota_cmd.oneline = _("show usage and limits");
472 quota_cmd.help = quota_help;
473 quota_cmd.flags = CMD_FLAG_FOREIGN_OK;
474
475 add_command(&quota_cmd);
476 }