]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/free.c
45ce2ceb04d59f6bf0053763f79dbe47f71cd587
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2005 Silicon Graphics, Inc.
11 #include "libfrog/logging.h"
12 #include "libfrog/fsgeom.h"
14 static cmdinfo_t free_cmd
;
21 " reports the number of free disk blocks and inodes\n"
23 " This command reports the number of total, used, and available disk blocks.\n"
24 " It can optionally report the same set of numbers for inodes and realtime\n"
25 " disk blocks, and will report on all known XFS filesystem mount points and\n"
26 " project quota paths by default (see 'print' command for a list).\n"
27 " -b -- report the block count values\n"
28 " -i -- report the inode count values\n"
29 " -r -- report the realtime block count values\n"
30 " -h -- report in a human-readable format\n"
31 " -N -- suppress the header from the output\n"
36 * The data and realtime block counts returned (count, used, and
37 * free) are all in basic block units.
40 mount_free_space_data(
41 struct fs_path
*mount
,
52 struct xfs_fsop_counts fscounts
;
53 struct xfs_fsop_geom fsgeo
;
55 uint64_t logsize
, count
, free
;
58 if ((fd
= open(mount
->fs_dir
, O_RDONLY
)) < 0) {
60 fprintf(stderr
, "%s: cannot open %s: %s\n",
61 progname
, mount
->fs_dir
, strerror(errno
));
65 if (platform_fstatfs(fd
, &st
) < 0) {
71 if (!(mount
->fs_flags
& FS_FOREIGN
)) {
72 ret
= xfrog_geometry(fd
, &fsgeo
);
74 xfrog_perror(ret
, "XFS_IOC_FSGEOMETRY");
78 if ((xfsctl(mount
->fs_dir
, fd
, XFS_IOC_FSCOUNTS
,
80 perror("XFS_IOC_FSCOUNTS");
85 logsize
= fsgeo
.logstart
? fsgeo
.logblocks
: 0;
86 count
= (fsgeo
.datablocks
- logsize
) * fsgeo
.blocksize
;
87 free
= fscounts
.freedata
* fsgeo
.blocksize
;
88 *bcount
= BTOBB(count
);
90 *bused
= BTOBB(count
- free
);
92 count
= fsgeo
.rtextents
* fsgeo
.rtextsize
* fsgeo
.blocksize
;
93 free
= fscounts
.freertx
* fsgeo
.rtextsize
* fsgeo
.blocksize
;
94 *rcount
= BTOBB(count
);
96 *rused
= BTOBB(count
- free
);
98 count
= st
.f_blocks
* st
.f_bsize
;
99 free
= st
.f_bfree
* st
.f_bsize
;
100 *bcount
= BTOBB(count
);
101 *bfree
= BTOBB(free
);
102 *bused
= BTOBB(count
- free
);
110 *icount
= st
.f_files
;
112 *iused
= st
.f_files
- st
.f_ffree
;
119 * The data and realtime block counts returned (count, used, and
120 * free) are all in basic block units.
123 projects_free_space_data(
124 struct fs_path
*path
,
138 uint type
= XFS_PROJ_QUOTA
;
139 char *dev
= path
->fs_name
;
142 if (xfsquotactl(XFS_GETQSTAT
, dev
, type
, 0, &qfs
) < 0 ||
143 !(qfs
.qs_flags
& XFS_QUOTA_PDQ_ACCT
))
146 if ((fd
= open(path
->fs_dir
, O_RDONLY
)) < 0) {
148 fprintf(stderr
, "%s: cannot open %s: %s\n",
149 progname
, path
->fs_dir
, strerror(errno
));
153 if ((xfsctl(path
->fs_dir
, fd
, FS_IOC_FSGETXATTR
, &fsx
)) < 0) {
155 perror("FS_IOC_FSGETXATTR");
159 if (!(fsx
.fsx_xflags
& FS_XFLAG_PROJINHERIT
)) {
161 fprintf(stderr
, _("%s: project quota flag not set on %s\n"),
162 progname
, path
->fs_dir
);
167 if (path
->fs_prid
!= fsx
.fsx_projid
) {
170 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
171 progname
, path
->fs_prid
, projects_file
,
172 fsx
.fsx_projid
, path
->fs_dir
);
177 xfsquotactl(XFS_QSYNC
, dev
, type
, fsx
.fsx_projid
, NULL
);
178 if (xfsquotactl(XFS_GETQUOTA
, dev
, type
, fsx
.fsx_projid
, &d
) < 0) {
179 perror("XFS_GETQUOTA");
184 /* If no softlimit is set for any of blk/ino/rt, get actual usage */
185 if (!d
.d_blk_softlimit
|| !d
.d_ino_softlimit
|| !d
.d_rtb_softlimit
) {
186 mount_free_space_data(path
, bcount
, bused
, bfree
,
187 icount
, iused
, ifree
, rcount
, rused
, rfree
);
190 if (d
.d_blk_softlimit
) {
191 *bcount
= d
.d_blk_softlimit
;
192 *bfree
= (d
.d_blk_softlimit
- d
.d_bcount
);
196 if (d
.d_ino_softlimit
) {
197 *icount
= d
.d_ino_softlimit
;
198 *ifree
= (d
.d_ino_softlimit
- d
.d_icount
);
202 if (d
.d_rtb_softlimit
) {
203 *rcount
= d
.d_rtb_softlimit
;
204 *rfree
= (d
.d_rtb_softlimit
- d
.d_rtbcount
);
206 *rused
= d
.d_rtbcount
;
219 uint64_t bcount
, bused
, bfree
;
220 uint64_t icount
, iused
, ifree
;
221 uint64_t rcount
, rused
, rfree
;
222 char a
[8], s
[8], u
[8], p
[8];
225 count
= (path
->fs_flags
& FS_PROJECT_PATH
) ?
226 projects_free_space_data(path
, &bcount
, &bused
, &bfree
,
227 &icount
, &iused
, &ifree
,
228 &rcount
, &rused
, &rfree
) :
229 mount_free_space_data(path
, &bcount
, &bused
, &bfree
,
230 &icount
, &iused
, &ifree
,
231 &rcount
, &rused
, &rfree
);
235 if (!(flags
& NO_HEADER_FLAG
)) {
236 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
237 _("Filesystem ") : _("Filesystem "));
238 if (form
& (XFS_BLOCK_QUOTA
|XFS_RTBLOCK_QUOTA
))
239 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
240 _(" Size Used Avail Use%%") :
241 _(" 1K-blocks Used Available Use%%"));
242 else if (form
& XFS_INODE_QUOTA
)
243 fprintf(fp
, (flags
& HUMAN_FLAG
) ?
244 _(" Inodes Used Free Use%%") :
245 _(" Inodes IUsed IFree IUse%%"));
246 fprintf(fp
, _(" Pathname\n"));
249 if (flags
& HUMAN_FLAG
) {
250 count
= fprintf(fp
, "%-12s", path
->fs_name
);
252 fprintf(fp
, "\n%12s", " ");
254 count
= fprintf(fp
, "%-19s", path
->fs_name
);
256 fprintf(fp
, "\n%19s", " ");
259 if (form
& XFS_BLOCK_QUOTA
) {
260 if (flags
& HUMAN_FLAG
)
261 fprintf(fp
, " %6s %6s %6s %3s%%",
262 bbs_to_string(bcount
, s
, sizeof(s
)),
263 bbs_to_string(bused
, u
, sizeof(u
)),
264 bbs_to_string(bfree
, a
, sizeof(a
)),
265 pct_to_string(bused
, bcount
, p
, sizeof(p
)));
267 fprintf(fp
, " %10llu %10llu %10llu %3s%%",
268 (unsigned long long)bcount
>> 1,
269 (unsigned long long)bused
>> 1,
270 (unsigned long long)bfree
>> 1,
271 pct_to_string(bused
, bcount
, p
, sizeof(p
)));
272 } else if (form
& XFS_INODE_QUOTA
) {
273 if (flags
& HUMAN_FLAG
)
274 fprintf(fp
, " %6s %6s %6s %3s%%",
275 num_to_string(icount
, s
, sizeof(s
)),
276 num_to_string(iused
, u
, sizeof(u
)),
277 num_to_string(ifree
, a
, sizeof(a
)),
278 pct_to_string(iused
, icount
, p
, sizeof(p
)));
280 fprintf(fp
, " %10llu %10llu %10llu %3s%%",
281 (unsigned long long)icount
,
282 (unsigned long long)iused
,
283 (unsigned long long)ifree
,
284 pct_to_string(iused
, icount
, p
, sizeof(p
)));
285 } else if (form
& XFS_RTBLOCK_QUOTA
) {
286 if (flags
& HUMAN_FLAG
)
287 fprintf(fp
, " %6s %6s %6s %3s%%",
288 bbs_to_string(rcount
, s
, sizeof(s
)),
289 bbs_to_string(rused
, u
, sizeof(u
)),
290 bbs_to_string(rfree
, a
, sizeof(a
)),
291 pct_to_string(rused
, rcount
, p
, sizeof(p
)));
293 fprintf(fp
, " %10llu %10llu %10llu %3s%%",
294 (unsigned long long)rcount
>> 1,
295 (unsigned long long)rused
>> 1,
296 (unsigned long long)rfree
>> 1,
297 pct_to_string(rused
, rcount
, p
, sizeof(p
)));
299 fprintf(fp
, " %s\n", path
->fs_dir
);
313 fs_cursor_initialise(dir
, 0, &cursor
);
314 while ((path
= fs_cursor_next_entry(&cursor
))) {
315 if (free_space(fp
, form
, path
, flags
))
316 flags
|= NO_HEADER_FLAG
;
327 int c
, flags
= 0, form
= 0;
329 while ((c
= getopt(argc
, argv
, "bf:hNir")) != EOF
) {
335 form
|= XFS_BLOCK_QUOTA
;
338 form
|= XFS_INODE_QUOTA
;
341 form
|= XFS_RTBLOCK_QUOTA
;
347 flags
|= NO_HEADER_FLAG
;
350 return command_usage(&free_cmd
);
355 form
= XFS_BLOCK_QUOTA
;
357 if ((fp
= fopen_write_secure(fname
)) == NULL
)
361 free_space_list(fp
, form
, NULL
, flags
);
362 else while (argc
> optind
)
363 free_space_list(fp
, form
, argv
[optind
++], flags
);
373 free_cmd
.name
= "df";
374 free_cmd
.altname
= "free";
375 free_cmd
.cfunc
= free_f
;
377 free_cmd
.argmax
= -1;
378 free_cmd
.args
= _("[-bir] [-hN] [-f file]");
379 free_cmd
.oneline
= _("show free and used counts for blocks and inodes");
380 free_cmd
.help
= free_help
;
381 free_cmd
.flags
= CMD_FLAG_FOREIGN_OK
;
383 add_command(&free_cmd
);