]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/free.c
df42954bc056bef1b3e3c8cbf16c7dd93cb41934
[thirdparty/xfsprogs-dev.git] / quota / free.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <xfs/command.h>
34 #include "init.h"
35 #include "quota.h"
36
37 static cmdinfo_t free_cmd;
38
39 static void
40 free_help(void)
41 {
42 printf(_(
43 "\n"
44 " reports the number of free disk blocks and inodes\n"
45 "\n"
46 " This command reports the number of total, used, and available disk blocks.\n"
47 " It can optionally report the same set of numbers for inodes and realtime\n"
48 " disk blocks, and will report on all known XFS filesystem mount points and\n"
49 " project quota paths by default (see 'print' command for a list).\n"
50 " -b -- report the block count values\n"
51 " -i -- report the inode count values\n"
52 " -r -- report the realtime block count values\n"
53 " -h -- report in a human-readable format\n"
54 " -n -- suppress the header from the output\n"
55 "\n"));
56 }
57
58 static int
59 mount_free_space_data(
60 struct fs_path *mount,
61 __uint64_t *bcount,
62 __uint64_t *bused,
63 __uint64_t *bfree,
64 __uint64_t *icount,
65 __uint64_t *iused,
66 __uint64_t *ifree,
67 __uint64_t *rcount,
68 __uint64_t *rused,
69 __uint64_t *rfree)
70 {
71 struct xfs_fsop_counts fscounts;
72 struct xfs_fsop_geom fsgeo;
73 struct statfs st;
74 __uint64_t logsize, count, free;
75 int fd;
76
77 if ((fd = open(mount->fs_dir, O_RDONLY)) < 0) {
78 fprintf(stderr, "%s: cannot open %s: %s\n",
79 progname, mount->fs_dir, strerror(errno));
80 return 0;
81 }
82
83 if (platform_fstatfs(fd, &st) < 0) {
84 perror("fstatfs");
85 close(fd);
86 return 0;
87 }
88 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
89 perror("XFS_IOC_FSGEOMETRY_V1");
90 close(fd);
91 return 0;
92 }
93 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
94 perror("XFS_IOC_FSCOUNTS");
95 close(fd);
96 return 0;
97 }
98
99 logsize = fsgeo.logstart ? fsgeo.logblocks : 0;
100 count = (fsgeo.datablocks - logsize) * fsgeo.blocksize;
101 free = fscounts.freedata * fsgeo.blocksize;
102 *bcount = BTOBB(count);
103 *bfree = BTOBB(free);
104 *bused = BTOBB(count - free);
105
106 *icount = st.f_files;
107 *ifree = st.f_ffree;
108 *iused = st.f_files - st.f_ffree;
109
110 count = fsgeo.rtextents * fsgeo.rtextsize;
111 free = fscounts.freertx * fsgeo.rtextsize;
112 *rcount = BTOBB(count);
113 *rfree = BTOBB(free);
114 *rused = BTOBB(count - free);
115
116 close(fd);
117 return 1;
118 }
119
120 static int
121 projects_free_space_data(
122 struct fs_path *path,
123 __uint64_t *bcount,
124 __uint64_t *bused,
125 __uint64_t *bfree,
126 __uint64_t *icount,
127 __uint64_t *iused,
128 __uint64_t *ifree,
129 __uint64_t *rcount,
130 __uint64_t *rused,
131 __uint64_t *rfree)
132 {
133 fs_disk_quota_t d;
134 struct fsxattr fsx;
135 __uint32_t projid;
136 uint type = XFS_PROJ_QUOTA;
137 char *dev = path->fs_name;
138 int fd;
139
140 if ((fd = open(path->fs_dir, O_RDONLY)) < 0) {
141 fprintf(stderr, "%s: cannot open %s: %s\n",
142 progname, path->fs_dir, strerror(errno));
143 return 0;
144 }
145
146 if ((xfsctl(path->fs_dir, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
147 perror("XFS_IOC_FSGETXATTR");
148 close(fd);
149 return 0;
150 }
151 if (!(fsx.fsx_xflags & XFS_XFLAG_PROJINHERIT)) {
152 fprintf(stderr, _("%s: project quota flag not set on %s\n"),
153 progname, path->fs_dir);
154 close(fd);
155 return 0;
156 }
157
158 if ((xfsctl(path->fs_dir, fd, XFS_IOC_GETPROJID, &projid)) < 0) {
159 perror("XFS_IOC_GETPROJID");
160 close(fd);
161 return 0;
162 }
163 if (path->fs_prid != projid) {
164 fprintf(stderr,
165 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
166 progname, path->fs_prid, projects_file,
167 projid, path->fs_dir);
168 close(fd);
169 return 0;
170 }
171
172 if (xfsquotactl(XFS_GETQUOTA, dev, type, projid, (void *)&d) < 0) {
173 perror("XFS_GETQUOTA");
174 close(fd);
175 return 0;
176 }
177
178 /* If no softlimit is set for any of blk/ino/rt, get actual usage */
179 if (!d.d_blk_softlimit || !d.d_ino_softlimit || !d.d_rtb_softlimit) {
180 mount_free_space_data(path, bcount, bused, bfree,
181 icount, iused, ifree, rcount, rused, rfree);
182 }
183
184 if (d.d_blk_softlimit) {
185 *bcount = d.d_blk_softlimit << 1;
186 *bfree = (d.d_blk_softlimit - d.d_bcount) << 1;
187 }
188 *bused = d.d_bcount << 1;
189 if (d.d_ino_softlimit) {
190 *icount = d.d_ino_softlimit;
191 *ifree = (d.d_ino_softlimit - d.d_icount);
192 }
193 *iused = d.d_icount;
194 if (d.d_rtb_softlimit) {
195 *rcount = d.d_rtb_softlimit << 1;
196 *rfree = (d.d_rtb_softlimit - d.d_rtbcount) << 1;
197 }
198 *rcount = d.d_rtbcount << 1;
199
200 close(fd);
201 return 1;
202 }
203
204 static int
205 free_space(
206 FILE *fp,
207 uint form,
208 fs_path_t *path,
209 uint flags)
210 {
211 __uint64_t bcount, bused, bfree;
212 __uint64_t icount, iused, ifree;
213 __uint64_t rcount, rused, rfree;
214 char a[8], s[8], u[8], p[8];
215 int count;
216
217 count = (path->fs_flags & FS_PROJECT_PATH) ?
218 projects_free_space_data(path, &bcount, &bused, &bfree,
219 &icount, &iused, &ifree,
220 &rcount, &rused, &rfree) :
221 mount_free_space_data(path, &bcount, &bused, &bfree,
222 &icount, &iused, &ifree,
223 &rcount, &rused, &rfree);
224 if (!count)
225 return 0;
226
227 if (!(flags & NO_HEADER_FLAG)) {
228 fprintf(fp, (flags & HUMAN_FLAG) ?
229 _("Filesystem ") : _("Filesystem "));
230 if (form & (XFS_BLOCK_QUOTA|XFS_RTBLOCK_QUOTA))
231 fprintf(fp, (flags & HUMAN_FLAG) ?
232 _(" Size Used Avail Use%%") :
233 _(" 1K-blocks Used Available Use%%"));
234 else if (form & XFS_INODE_QUOTA)
235 fprintf(fp, (flags & HUMAN_FLAG) ?
236 _(" Inodes Used Free Use%%") :
237 _(" Inodes IUsed IFree IUse%%"));
238 fprintf(fp, _(" Pathname\n"));
239 }
240
241 if (flags & HUMAN_FLAG) {
242 count = fprintf(fp, "%-12s", path->fs_name);
243 if (count > 13)
244 fprintf(fp, "\n%12s", " ");
245 } else {
246 count = fprintf(fp, "%-19s", path->fs_name);
247 if (count > 20)
248 fprintf(fp, "\n%19s", " ");
249 }
250
251 if (form & XFS_BLOCK_QUOTA) {
252 if (flags & HUMAN_FLAG)
253 fprintf(fp, " %6s %6s %6s %3s%%",
254 bbs_to_string(bcount, s, sizeof(s)),
255 bbs_to_string(bused, u, sizeof(u)),
256 bbs_to_string(bfree, a, sizeof(a)),
257 pct_to_string(bused, bcount, p, sizeof(p)));
258 else
259 fprintf(fp, " %10llu %10llu %10llu %3s%%",
260 (unsigned long long)bcount >> 1,
261 (unsigned long long)bused >> 1,
262 (unsigned long long)bfree >> 1,
263 pct_to_string(bused, bcount, p, sizeof(p)));
264 } else if (form & XFS_INODE_QUOTA) {
265 if (flags & HUMAN_FLAG)
266 fprintf(fp, " %6s %6s %6s %3s%%",
267 num_to_string(icount, s, sizeof(s)),
268 num_to_string(iused, u, sizeof(u)),
269 num_to_string(ifree, a, sizeof(a)),
270 pct_to_string(iused, icount, p, sizeof(p)));
271 else
272 fprintf(fp, " %10llu %10llu %10llu %3s%%",
273 (unsigned long long)icount,
274 (unsigned long long)iused,
275 (unsigned long long)ifree,
276 pct_to_string(iused, icount, p, sizeof(p)));
277 } else if (form & XFS_RTBLOCK_QUOTA) {
278 if (flags & HUMAN_FLAG)
279 fprintf(fp, " %6s %6s %6s %3s%%",
280 bbs_to_string(rcount, s, sizeof(s)),
281 bbs_to_string(rused, u, sizeof(u)),
282 bbs_to_string(rfree, a, sizeof(a)),
283 pct_to_string(rused, rcount, p, sizeof(p)));
284 else
285 fprintf(fp, " %10llu %10llu %10llu %3s%%",
286 (unsigned long long)rcount >> 1,
287 (unsigned long long)rused >> 1,
288 (unsigned long long)rfree >> 1,
289 pct_to_string(rused, rcount, p, sizeof(p)));
290 }
291 fprintf(fp, " %s\n", path->fs_dir);
292 return 1;
293 }
294
295 static void
296 free_space_list(
297 FILE *fp,
298 uint form,
299 uint type,
300 char *dir,
301 uint flags)
302 {
303 fs_cursor_t cursor;
304 fs_path_t *path;
305
306 fs_cursor_initialise(dir, type, &cursor);
307 while ((path = fs_cursor_next_entry(&cursor))) {
308 if (free_space(fp, form, path, flags))
309 flags |= NO_HEADER_FLAG;
310 }
311 }
312
313 static int
314 free_f(
315 int argc,
316 char **argv)
317 {
318 FILE *fp = NULL;
319 char *fname = NULL;
320 int c, flags = 0, form = 0, type = 0;
321
322 while ((c = getopt(argc, argv, "bf:hnir")) != EOF) {
323 switch (c) {
324 case 'f':
325 fname = optarg;
326 break;
327 case 'b':
328 form |= XFS_BLOCK_QUOTA;
329 break;
330 case 'i':
331 form |= XFS_INODE_QUOTA;
332 break;
333 case 'r':
334 form |= XFS_RTBLOCK_QUOTA;
335 break;
336 case 'h':
337 flags |= HUMAN_FLAG;
338 break;
339 case 'n':
340 flags |= NO_HEADER_FLAG;
341 break;
342 default:
343 return command_usage(&free_cmd);
344 }
345 }
346
347 if (!form)
348 form = XFS_BLOCK_QUOTA;
349
350 if (!type)
351 type = FS_MOUNT_POINT|FS_PROJECT_PATH;
352
353 if ((fp = fopen_write_secure(fname)) == NULL)
354 return 0;
355
356 if (argc == optind)
357 free_space_list(fp, form, type, NULL, flags);
358 else while (argc > optind)
359 free_space_list(fp, form, type, argv[optind++], flags);
360
361 if (fname)
362 fclose(fp);
363 return 0;
364 }
365
366 void
367 free_init(void)
368 {
369 free_cmd.name = _("df");
370 free_cmd.altname = _("free");
371 free_cmd.cfunc = free_f;
372 free_cmd.argmin = 0;
373 free_cmd.argmax = -1;
374 free_cmd.args = _("[-bir] [-hn] [-f file]");
375 free_cmd.oneline = _("show free and used counts for blocks and inodes");
376 free_cmd.help = free_help;
377
378 add_command(&free_cmd);
379 }