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