]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/quota.c
469c51fe93807a6c774a3fb3e89c3c9b7a9ff929
[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 struct passwd *u;
206
207 if (!numeric && (u = getpwuid(uid)))
208 return u->pw_name;
209 snprintf(buffer, sizeof(buffer), "#%u", uid);
210 return &buffer[0];
211 }
212
213 static void
214 quota_user_type(
215 FILE *fp,
216 char *name,
217 uint form,
218 uint type,
219 uint flags)
220 {
221 struct passwd *u;
222 uid_t id;
223
224 if (name) {
225 if (isdigit(name[0])) {
226 id = atoi(name);
227 name = getusername(id, flags & NO_LOOKUP_FLAG);
228 } else if ((u = getpwnam(name))) {
229 id = u->pw_uid;
230 name = u->pw_name;
231 } else {
232 fprintf(stderr, _("%s: cannot find user %s\n"),
233 progname, name);
234 return;
235 }
236 } else {
237 id = getuid();
238 name = getusername(id, flags & NO_LOOKUP_FLAG);
239 }
240
241 quota(fp, id, name, form, type, flags);
242 }
243
244 static char *
245 getgroupname(
246 gid_t gid,
247 int numeric)
248 {
249 static char buffer[32];
250 struct group *g;
251
252 if (!numeric && (g = getgrgid(gid)))
253 return g->gr_name;
254 snprintf(buffer, sizeof(buffer), "#%u", gid);
255 return &buffer[0];
256 }
257
258 static void
259 quota_group_type(
260 FILE *fp,
261 char *name,
262 uint form,
263 uint type,
264 uint flags)
265 {
266 struct group *g;
267 gid_t gid, *gids = NULL;
268 int i, ngroups, dofree = 0;
269
270 if (name) {
271 if (isdigit(name[0])) {
272 gid = atoi(name);
273 name = getgroupname(gid, flags & NO_LOOKUP_FLAG);
274 } else {
275 if ((g = getgrnam(name))) {
276 gid = g->gr_gid;
277 name = g->gr_name;
278 } else {
279 fprintf(stderr, _("%s: cannot find group %s\n"),
280 progname, name);
281 return;
282 }
283 }
284 gids = &gid;
285 ngroups = 1;
286 } else if ( ((ngroups = sysconf(_SC_NGROUPS_MAX)) < 0) ||
287 ((gids = malloc(ngroups * sizeof(gid_t))) == NULL) ||
288 ((ngroups = getgroups(ngroups, gids)) < 0)) {
289 dofree = (gids != NULL);
290 gid = getgid();
291 gids = &gid;
292 ngroups = 1;
293 } else {
294 dofree = (gids != NULL);
295 }
296
297 for (i = 0; i < ngroups; i++, name = NULL) {
298 if (!name)
299 name = getgroupname(gids[i], flags & NO_LOOKUP_FLAG);
300 quota(fp, gids[i], name, form, type, flags);
301 }
302
303 if (dofree)
304 free(gids);
305 }
306
307 static char *
308 getprojectname(
309 prid_t prid,
310 int numeric)
311 {
312 static char buffer[32];
313 fs_project_t *p;
314
315 if ((p = getprprid(prid)))
316 return p->pr_name;
317 snprintf(buffer, sizeof(buffer), "#%u", prid);
318 return &buffer[0];
319 }
320
321 static void
322 quota_proj_type(
323 FILE *fp,
324 char *name,
325 uint form,
326 uint type,
327 uint flags)
328 {
329 fs_project_t *p;
330 prid_t id;
331
332 if (!name) {
333 fprintf(stderr, _("%s: must specify a project name/ID\n"),
334 progname);
335 return;
336 }
337
338 if (isdigit(name[0])) {
339 id = atoi(name);
340 name = getprojectname(id, flags & NO_LOOKUP_FLAG);
341 } else if ((p = getprnam(name))) {
342 id = p->pr_prid;
343 name = p->pr_name;
344 } else {
345 fprintf(stderr, _("%s: cannot find project %s\n"),
346 progname, name);
347 return;
348 }
349
350 quota(fp, id, name, form, type, flags);
351 }
352
353 static void
354 quota_any_type(
355 FILE *fp,
356 char *name,
357 uint form,
358 uint type,
359 uint flags)
360 {
361 switch (type) {
362 case XFS_USER_QUOTA:
363 quota_user_type(fp, name, form, type, flags);
364 break;
365 case XFS_GROUP_QUOTA:
366 quota_group_type(fp, name, form, type, flags);
367 break;
368 case XFS_PROJ_QUOTA:
369 quota_proj_type(fp, name, form, type, flags);
370 break;
371 }
372 }
373
374 static int
375 quota_f(
376 int argc,
377 char **argv)
378 {
379 FILE *fp = NULL;
380 char *fname = NULL;
381 int c, flags = 0, type = 0, form = 0;
382
383 while ((c = getopt(argc, argv, "bf:ghnNipruv")) != EOF) {
384 switch (c) {
385 case 'f':
386 fname = optarg;
387 break;
388 case 'b':
389 form |= XFS_BLOCK_QUOTA;
390 break;
391 case 'i':
392 form |= XFS_INODE_QUOTA;
393 break;
394 case 'r':
395 form |= XFS_RTBLOCK_QUOTA;
396 break;
397 case 'g':
398 type = XFS_GROUP_QUOTA;
399 break;
400 case 'p':
401 type = XFS_PROJ_QUOTA;
402 break;
403 case 'u':
404 type = XFS_USER_QUOTA;
405 break;
406 case 'h':
407 flags |= HUMAN_FLAG;
408 break;
409 case 'n':
410 flags |= NO_LOOKUP_FLAG;
411 break;
412 case 'N':
413 flags |= NO_HEADER_FLAG;
414 break;
415 case 'v':
416 flags |= VERBOSE_FLAG;
417 break;
418 default:
419 return command_usage(&quota_cmd);
420 }
421 }
422
423 if (!form)
424 form = XFS_BLOCK_QUOTA;
425
426 if (!type)
427 type = XFS_USER_QUOTA;
428
429 if ((fp = fopen_write_secure(fname)) == NULL)
430 return 0;
431
432 if (argc == optind)
433 quota_any_type(fp, NULL, form, type, flags);
434 else while (argc > optind)
435 quota_any_type(fp, argv[optind++], form, type, flags);
436
437 if (fname)
438 fclose(fp);
439 return 0;
440 }
441
442 void
443 quota_init(void)
444 {
445 quota_cmd.name = _("quota");
446 quota_cmd.altname = _("l");
447 quota_cmd.cfunc = quota_f;
448 quota_cmd.argmin = 0;
449 quota_cmd.argmax = -1;
450 quota_cmd.args = _("[-bir] [-gpu] [-hnv] [-f file] [id|name]...");
451 quota_cmd.oneline = _("show usage and limits");
452 quota_cmd.help = quota_help;
453
454 add_command(&quota_cmd);
455 }