]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/free.c
libxfs: reset dirty buffer priority on lookup
[thirdparty/xfsprogs-dev.git] / quota / free.c
CommitLineData
5aead01d 1/*
da23017d
NS
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
5aead01d 4 *
da23017d
NS
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
5aead01d
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
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.
5aead01d 13 *
da23017d
NS
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
5aead01d
NS
17 */
18
6b803e5a 19#include "command.h"
5aead01d
NS
20#include "init.h"
21#include "quota.h"
22
23static cmdinfo_t free_cmd;
24
25static void
26free_help(void)
27{
28 printf(_(
29"\n"
30" reports the number of free disk blocks and inodes\n"
31"\n"
32" This command reports the number of total, used, and available disk blocks.\n"
33" It can optionally report the same set of numbers for inodes and realtime\n"
34" disk blocks, and will report on all known XFS filesystem mount points and\n"
35" project quota paths by default (see 'print' command for a list).\n"
36" -b -- report the block count values\n"
37" -i -- report the inode count values\n"
38" -r -- report the realtime block count values\n"
39" -h -- report in a human-readable format\n"
1774874a 40" -N -- suppress the header from the output\n"
5aead01d
NS
41"\n"));
42}
43
7cb2d41b
AE
44/*
45 * The data and realtime block counts returned (count, used, and
46 * free) are all in basic block units.
47 */
5aead01d
NS
48static int
49mount_free_space_data(
50 struct fs_path *mount,
51 __uint64_t *bcount,
52 __uint64_t *bused,
53 __uint64_t *bfree,
54 __uint64_t *icount,
55 __uint64_t *iused,
56 __uint64_t *ifree,
57 __uint64_t *rcount,
58 __uint64_t *rused,
59 __uint64_t *rfree)
60{
61 struct xfs_fsop_counts fscounts;
62 struct xfs_fsop_geom fsgeo;
63 struct statfs st;
64 __uint64_t logsize, count, free;
65 int fd;
66
67 if ((fd = open(mount->fs_dir, O_RDONLY)) < 0) {
e3210fd8 68 exitcode = 1;
5aead01d
NS
69 fprintf(stderr, "%s: cannot open %s: %s\n",
70 progname, mount->fs_dir, strerror(errno));
71 return 0;
72 }
73
74 if (platform_fstatfs(fd, &st) < 0) {
75 perror("fstatfs");
76 close(fd);
77 return 0;
78 }
79 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
80 perror("XFS_IOC_FSGEOMETRY_V1");
81 close(fd);
82 return 0;
83 }
84 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
85 perror("XFS_IOC_FSCOUNTS");
86 close(fd);
87 return 0;
88 }
89
90 logsize = fsgeo.logstart ? fsgeo.logblocks : 0;
91 count = (fsgeo.datablocks - logsize) * fsgeo.blocksize;
92 free = fscounts.freedata * fsgeo.blocksize;
93 *bcount = BTOBB(count);
94 *bfree = BTOBB(free);
95 *bused = BTOBB(count - free);
96
97 *icount = st.f_files;
98 *ifree = st.f_ffree;
99 *iused = st.f_files - st.f_ffree;
100
f5e080b0
NS
101 count = fsgeo.rtextents * fsgeo.rtextsize * fsgeo.blocksize;
102 free = fscounts.freertx * fsgeo.rtextsize * fsgeo.blocksize;
5aead01d
NS
103 *rcount = BTOBB(count);
104 *rfree = BTOBB(free);
105 *rused = BTOBB(count - free);
106
107 close(fd);
108 return 1;
109}
110
7cb2d41b
AE
111/*
112 * The data and realtime block counts returned (count, used, and
113 * free) are all in basic block units.
114 */
5aead01d
NS
115static int
116projects_free_space_data(
117 struct fs_path *path,
118 __uint64_t *bcount,
119 __uint64_t *bused,
120 __uint64_t *bfree,
121 __uint64_t *icount,
122 __uint64_t *iused,
123 __uint64_t *ifree,
124 __uint64_t *rcount,
125 __uint64_t *rused,
126 __uint64_t *rfree)
127{
c2df877f 128 fs_quota_stat_t qfs;
5aead01d
NS
129 fs_disk_quota_t d;
130 struct fsxattr fsx;
5aead01d
NS
131 uint type = XFS_PROJ_QUOTA;
132 char *dev = path->fs_name;
133 int fd;
134
c2df877f
BN
135 if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, &qfs) < 0 ||
136 !(qfs.qs_flags & XFS_QUOTA_PDQ_ACCT))
137 return 0;
138
5aead01d 139 if ((fd = open(path->fs_dir, O_RDONLY)) < 0) {
e3210fd8 140 exitcode = 1;
5aead01d
NS
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) {
e3210fd8 147 exitcode = 1;
5aead01d
NS
148 perror("XFS_IOC_FSGETXATTR");
149 close(fd);
150 return 0;
151 }
152 if (!(fsx.fsx_xflags & XFS_XFLAG_PROJINHERIT)) {
e3210fd8 153 exitcode = 1;
5aead01d
NS
154 fprintf(stderr, _("%s: project quota flag not set on %s\n"),
155 progname, path->fs_dir);
156 close(fd);
157 return 0;
158 }
159
764b1982 160 if (path->fs_prid != fsx.fsx_projid) {
e3210fd8 161 exitcode = 1;
5aead01d
NS
162 fprintf(stderr,
163 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
164 progname, path->fs_prid, projects_file,
764b1982 165 fsx.fsx_projid, path->fs_dir);
5aead01d
NS
166 close(fd);
167 return 0;
168 }
169
764b1982
NS
170 xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL);
171 if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) {
5aead01d
NS
172 perror("XFS_GETQUOTA");
173 close(fd);
174 return 0;
175 }
176
177 /* If no softlimit is set for any of blk/ino/rt, get actual usage */
178 if (!d.d_blk_softlimit || !d.d_ino_softlimit || !d.d_rtb_softlimit) {
179 mount_free_space_data(path, bcount, bused, bfree,
180 icount, iused, ifree, rcount, rused, rfree);
181 }
182
183 if (d.d_blk_softlimit) {
7cb2d41b
AE
184 *bcount = d.d_blk_softlimit;
185 *bfree = (d.d_blk_softlimit - d.d_bcount);
5aead01d 186 }
7cb2d41b 187 *bused = d.d_bcount;
1affe137 188
5aead01d
NS
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;
1affe137 194
5aead01d 195 if (d.d_rtb_softlimit) {
7cb2d41b
AE
196 *rcount = d.d_rtb_softlimit;
197 *rfree = (d.d_rtb_softlimit - d.d_rtbcount);
5aead01d 198 }
7cb2d41b 199 *rused = d.d_rtbcount;
5aead01d
NS
200
201 close(fd);
202 return 1;
203}
204
205static int
206free_space(
207 FILE *fp,
208 uint form,
209 fs_path_t *path,
210 uint flags)
211{
212 __uint64_t bcount, bused, bfree;
213 __uint64_t icount, iused, ifree;
214 __uint64_t rcount, rused, rfree;
215 char a[8], s[8], u[8], p[8];
216 int count;
217
218 count = (path->fs_flags & FS_PROJECT_PATH) ?
219 projects_free_space_data(path, &bcount, &bused, &bfree,
220 &icount, &iused, &ifree,
221 &rcount, &rused, &rfree) :
222 mount_free_space_data(path, &bcount, &bused, &bfree,
223 &icount, &iused, &ifree,
224 &rcount, &rused, &rfree);
225 if (!count)
226 return 0;
227
228 if (!(flags & NO_HEADER_FLAG)) {
229 fprintf(fp, (flags & HUMAN_FLAG) ?
230 _("Filesystem ") : _("Filesystem "));
231 if (form & (XFS_BLOCK_QUOTA|XFS_RTBLOCK_QUOTA))
232 fprintf(fp, (flags & HUMAN_FLAG) ?
233 _(" Size Used Avail Use%%") :
234 _(" 1K-blocks Used Available Use%%"));
235 else if (form & XFS_INODE_QUOTA)
236 fprintf(fp, (flags & HUMAN_FLAG) ?
237 _(" Inodes Used Free Use%%") :
238 _(" Inodes IUsed IFree IUse%%"));
239 fprintf(fp, _(" Pathname\n"));
240 }
241
242 if (flags & HUMAN_FLAG) {
243 count = fprintf(fp, "%-12s", path->fs_name);
244 if (count > 13)
245 fprintf(fp, "\n%12s", " ");
246 } else {
247 count = fprintf(fp, "%-19s", path->fs_name);
248 if (count > 20)
249 fprintf(fp, "\n%19s", " ");
250 }
251
252 if (form & XFS_BLOCK_QUOTA) {
253 if (flags & HUMAN_FLAG)
254 fprintf(fp, " %6s %6s %6s %3s%%",
255 bbs_to_string(bcount, s, sizeof(s)),
256 bbs_to_string(bused, u, sizeof(u)),
257 bbs_to_string(bfree, a, sizeof(a)),
258 pct_to_string(bused, bcount, p, sizeof(p)));
259 else
260 fprintf(fp, " %10llu %10llu %10llu %3s%%",
261 (unsigned long long)bcount >> 1,
262 (unsigned long long)bused >> 1,
263 (unsigned long long)bfree >> 1,
264 pct_to_string(bused, bcount, p, sizeof(p)));
265 } else if (form & XFS_INODE_QUOTA) {
266 if (flags & HUMAN_FLAG)
267 fprintf(fp, " %6s %6s %6s %3s%%",
268 num_to_string(icount, s, sizeof(s)),
269 num_to_string(iused, u, sizeof(u)),
270 num_to_string(ifree, a, sizeof(a)),
271 pct_to_string(iused, icount, p, sizeof(p)));
272 else
273 fprintf(fp, " %10llu %10llu %10llu %3s%%",
274 (unsigned long long)icount,
275 (unsigned long long)iused,
276 (unsigned long long)ifree,
277 pct_to_string(iused, icount, p, sizeof(p)));
278 } else if (form & XFS_RTBLOCK_QUOTA) {
279 if (flags & HUMAN_FLAG)
280 fprintf(fp, " %6s %6s %6s %3s%%",
281 bbs_to_string(rcount, s, sizeof(s)),
282 bbs_to_string(rused, u, sizeof(u)),
283 bbs_to_string(rfree, a, sizeof(a)),
284 pct_to_string(rused, rcount, p, sizeof(p)));
285 else
286 fprintf(fp, " %10llu %10llu %10llu %3s%%",
287 (unsigned long long)rcount >> 1,
288 (unsigned long long)rused >> 1,
289 (unsigned long long)rfree >> 1,
290 pct_to_string(rused, rcount, p, sizeof(p)));
291 }
292 fprintf(fp, " %s\n", path->fs_dir);
293 return 1;
294}
295
296static void
297free_space_list(
298 FILE *fp,
299 uint form,
5aead01d
NS
300 char *dir,
301 uint flags)
302{
303 fs_cursor_t cursor;
304 fs_path_t *path;
305
12a20413 306 fs_cursor_initialise(dir, 0, &cursor);
5aead01d
NS
307 while ((path = fs_cursor_next_entry(&cursor))) {
308 if (free_space(fp, form, path, flags))
309 flags |= NO_HEADER_FLAG;
310 }
311}
312
313static int
314free_f(
315 int argc,
316 char **argv)
317{
318 FILE *fp = NULL;
319 char *fname = NULL;
12a20413 320 int c, flags = 0, form = 0;
5aead01d 321
1774874a 322 while ((c = getopt(argc, argv, "bf:hNir")) != EOF) {
5aead01d
NS
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;
1774874a 339 case 'N':
5aead01d
NS
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
5aead01d
NS
350 if ((fp = fopen_write_secure(fname)) == NULL)
351 return 0;
352
353 if (argc == optind)
12a20413 354 free_space_list(fp, form, NULL, flags);
5aead01d 355 else while (argc > optind)
12a20413 356 free_space_list(fp, form, argv[optind++], flags);
5aead01d
NS
357
358 if (fname)
359 fclose(fp);
360 return 0;
361}
362
363void
364free_init(void)
365{
ad765595
AM
366 free_cmd.name = "df";
367 free_cmd.altname = "free";
5aead01d
NS
368 free_cmd.cfunc = free_f;
369 free_cmd.argmin = 0;
370 free_cmd.argmax = -1;
371 free_cmd.args = _("[-bir] [-hn] [-f file]");
372 free_cmd.oneline = _("show free and used counts for blocks and inodes");
373 free_cmd.help = free_help;
374
375 add_command(&free_cmd);
376}