]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/free.c
build system: Make --enable-gettext actually enable gettext
[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
19#include <xfs/command.h>
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
44static int
45mount_free_space_data(
46 struct fs_path *mount,
47 __uint64_t *bcount,
48 __uint64_t *bused,
49 __uint64_t *bfree,
50 __uint64_t *icount,
51 __uint64_t *iused,
52 __uint64_t *ifree,
53 __uint64_t *rcount,
54 __uint64_t *rused,
55 __uint64_t *rfree)
56{
57 struct xfs_fsop_counts fscounts;
58 struct xfs_fsop_geom fsgeo;
59 struct statfs st;
60 __uint64_t logsize, count, free;
61 int fd;
62
63 if ((fd = open(mount->fs_dir, O_RDONLY)) < 0) {
64 fprintf(stderr, "%s: cannot open %s: %s\n",
65 progname, mount->fs_dir, strerror(errno));
66 return 0;
67 }
68
69 if (platform_fstatfs(fd, &st) < 0) {
70 perror("fstatfs");
71 close(fd);
72 return 0;
73 }
74 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
75 perror("XFS_IOC_FSGEOMETRY_V1");
76 close(fd);
77 return 0;
78 }
79 if ((xfsctl(mount->fs_dir, fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
80 perror("XFS_IOC_FSCOUNTS");
81 close(fd);
82 return 0;
83 }
84
85 logsize = fsgeo.logstart ? fsgeo.logblocks : 0;
86 count = (fsgeo.datablocks - logsize) * fsgeo.blocksize;
87 free = fscounts.freedata * fsgeo.blocksize;
88 *bcount = BTOBB(count);
89 *bfree = BTOBB(free);
90 *bused = BTOBB(count - free);
91
92 *icount = st.f_files;
93 *ifree = st.f_ffree;
94 *iused = st.f_files - st.f_ffree;
95
f5e080b0
NS
96 count = fsgeo.rtextents * fsgeo.rtextsize * fsgeo.blocksize;
97 free = fscounts.freertx * fsgeo.rtextsize * fsgeo.blocksize;
5aead01d
NS
98 *rcount = BTOBB(count);
99 *rfree = BTOBB(free);
100 *rused = BTOBB(count - free);
101
102 close(fd);
103 return 1;
104}
105
106static int
107projects_free_space_data(
108 struct fs_path *path,
109 __uint64_t *bcount,
110 __uint64_t *bused,
111 __uint64_t *bfree,
112 __uint64_t *icount,
113 __uint64_t *iused,
114 __uint64_t *ifree,
115 __uint64_t *rcount,
116 __uint64_t *rused,
117 __uint64_t *rfree)
118{
c2df877f 119 fs_quota_stat_t qfs;
5aead01d
NS
120 fs_disk_quota_t d;
121 struct fsxattr fsx;
5aead01d
NS
122 uint type = XFS_PROJ_QUOTA;
123 char *dev = path->fs_name;
124 int fd;
125
c2df877f
BN
126 if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, &qfs) < 0 ||
127 !(qfs.qs_flags & XFS_QUOTA_PDQ_ACCT))
128 return 0;
129
5aead01d
NS
130 if ((fd = open(path->fs_dir, O_RDONLY)) < 0) {
131 fprintf(stderr, "%s: cannot open %s: %s\n",
132 progname, path->fs_dir, strerror(errno));
133 return 0;
134 }
135
136 if ((xfsctl(path->fs_dir, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
137 perror("XFS_IOC_FSGETXATTR");
138 close(fd);
139 return 0;
140 }
141 if (!(fsx.fsx_xflags & XFS_XFLAG_PROJINHERIT)) {
142 fprintf(stderr, _("%s: project quota flag not set on %s\n"),
143 progname, path->fs_dir);
144 close(fd);
145 return 0;
146 }
147
764b1982 148 if (path->fs_prid != fsx.fsx_projid) {
5aead01d
NS
149 fprintf(stderr,
150 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
151 progname, path->fs_prid, projects_file,
764b1982 152 fsx.fsx_projid, path->fs_dir);
5aead01d
NS
153 close(fd);
154 return 0;
155 }
156
764b1982
NS
157 xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL);
158 if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) {
5aead01d
NS
159 perror("XFS_GETQUOTA");
160 close(fd);
161 return 0;
162 }
163
164 /* If no softlimit is set for any of blk/ino/rt, get actual usage */
165 if (!d.d_blk_softlimit || !d.d_ino_softlimit || !d.d_rtb_softlimit) {
166 mount_free_space_data(path, bcount, bused, bfree,
167 icount, iused, ifree, rcount, rused, rfree);
168 }
169
170 if (d.d_blk_softlimit) {
171 *bcount = d.d_blk_softlimit << 1;
172 *bfree = (d.d_blk_softlimit - d.d_bcount) << 1;
173 }
174 *bused = d.d_bcount << 1;
175 if (d.d_ino_softlimit) {
176 *icount = d.d_ino_softlimit;
177 *ifree = (d.d_ino_softlimit - d.d_icount);
178 }
179 *iused = d.d_icount;
180 if (d.d_rtb_softlimit) {
181 *rcount = d.d_rtb_softlimit << 1;
182 *rfree = (d.d_rtb_softlimit - d.d_rtbcount) << 1;
183 }
184 *rcount = d.d_rtbcount << 1;
185
186 close(fd);
187 return 1;
188}
189
190static int
191free_space(
192 FILE *fp,
193 uint form,
194 fs_path_t *path,
195 uint flags)
196{
197 __uint64_t bcount, bused, bfree;
198 __uint64_t icount, iused, ifree;
199 __uint64_t rcount, rused, rfree;
200 char a[8], s[8], u[8], p[8];
201 int count;
202
203 count = (path->fs_flags & FS_PROJECT_PATH) ?
204 projects_free_space_data(path, &bcount, &bused, &bfree,
205 &icount, &iused, &ifree,
206 &rcount, &rused, &rfree) :
207 mount_free_space_data(path, &bcount, &bused, &bfree,
208 &icount, &iused, &ifree,
209 &rcount, &rused, &rfree);
210 if (!count)
211 return 0;
212
213 if (!(flags & NO_HEADER_FLAG)) {
214 fprintf(fp, (flags & HUMAN_FLAG) ?
215 _("Filesystem ") : _("Filesystem "));
216 if (form & (XFS_BLOCK_QUOTA|XFS_RTBLOCK_QUOTA))
217 fprintf(fp, (flags & HUMAN_FLAG) ?
218 _(" Size Used Avail Use%%") :
219 _(" 1K-blocks Used Available Use%%"));
220 else if (form & XFS_INODE_QUOTA)
221 fprintf(fp, (flags & HUMAN_FLAG) ?
222 _(" Inodes Used Free Use%%") :
223 _(" Inodes IUsed IFree IUse%%"));
224 fprintf(fp, _(" Pathname\n"));
225 }
226
227 if (flags & HUMAN_FLAG) {
228 count = fprintf(fp, "%-12s", path->fs_name);
229 if (count > 13)
230 fprintf(fp, "\n%12s", " ");
231 } else {
232 count = fprintf(fp, "%-19s", path->fs_name);
233 if (count > 20)
234 fprintf(fp, "\n%19s", " ");
235 }
236
237 if (form & XFS_BLOCK_QUOTA) {
238 if (flags & HUMAN_FLAG)
239 fprintf(fp, " %6s %6s %6s %3s%%",
240 bbs_to_string(bcount, s, sizeof(s)),
241 bbs_to_string(bused, u, sizeof(u)),
242 bbs_to_string(bfree, a, sizeof(a)),
243 pct_to_string(bused, bcount, p, sizeof(p)));
244 else
245 fprintf(fp, " %10llu %10llu %10llu %3s%%",
246 (unsigned long long)bcount >> 1,
247 (unsigned long long)bused >> 1,
248 (unsigned long long)bfree >> 1,
249 pct_to_string(bused, bcount, p, sizeof(p)));
250 } else if (form & XFS_INODE_QUOTA) {
251 if (flags & HUMAN_FLAG)
252 fprintf(fp, " %6s %6s %6s %3s%%",
253 num_to_string(icount, s, sizeof(s)),
254 num_to_string(iused, u, sizeof(u)),
255 num_to_string(ifree, a, sizeof(a)),
256 pct_to_string(iused, icount, p, sizeof(p)));
257 else
258 fprintf(fp, " %10llu %10llu %10llu %3s%%",
259 (unsigned long long)icount,
260 (unsigned long long)iused,
261 (unsigned long long)ifree,
262 pct_to_string(iused, icount, p, sizeof(p)));
263 } else if (form & XFS_RTBLOCK_QUOTA) {
264 if (flags & HUMAN_FLAG)
265 fprintf(fp, " %6s %6s %6s %3s%%",
266 bbs_to_string(rcount, s, sizeof(s)),
267 bbs_to_string(rused, u, sizeof(u)),
268 bbs_to_string(rfree, a, sizeof(a)),
269 pct_to_string(rused, rcount, p, sizeof(p)));
270 else
271 fprintf(fp, " %10llu %10llu %10llu %3s%%",
272 (unsigned long long)rcount >> 1,
273 (unsigned long long)rused >> 1,
274 (unsigned long long)rfree >> 1,
275 pct_to_string(rused, rcount, p, sizeof(p)));
276 }
277 fprintf(fp, " %s\n", path->fs_dir);
278 return 1;
279}
280
281static void
282free_space_list(
283 FILE *fp,
284 uint form,
285 uint type,
286 char *dir,
287 uint flags)
288{
289 fs_cursor_t cursor;
290 fs_path_t *path;
291
292 fs_cursor_initialise(dir, type, &cursor);
293 while ((path = fs_cursor_next_entry(&cursor))) {
294 if (free_space(fp, form, path, flags))
295 flags |= NO_HEADER_FLAG;
296 }
297}
298
299static int
300free_f(
301 int argc,
302 char **argv)
303{
304 FILE *fp = NULL;
305 char *fname = NULL;
306 int c, flags = 0, form = 0, type = 0;
307
1774874a 308 while ((c = getopt(argc, argv, "bf:hNir")) != EOF) {
5aead01d
NS
309 switch (c) {
310 case 'f':
311 fname = optarg;
312 break;
313 case 'b':
314 form |= XFS_BLOCK_QUOTA;
315 break;
316 case 'i':
317 form |= XFS_INODE_QUOTA;
318 break;
319 case 'r':
320 form |= XFS_RTBLOCK_QUOTA;
321 break;
322 case 'h':
323 flags |= HUMAN_FLAG;
324 break;
1774874a 325 case 'N':
5aead01d
NS
326 flags |= NO_HEADER_FLAG;
327 break;
328 default:
329 return command_usage(&free_cmd);
330 }
331 }
332
333 if (!form)
334 form = XFS_BLOCK_QUOTA;
335
336 if (!type)
337 type = FS_MOUNT_POINT|FS_PROJECT_PATH;
338
339 if ((fp = fopen_write_secure(fname)) == NULL)
340 return 0;
341
342 if (argc == optind)
343 free_space_list(fp, form, type, NULL, flags);
344 else while (argc > optind)
345 free_space_list(fp, form, type, argv[optind++], flags);
346
347 if (fname)
348 fclose(fp);
349 return 0;
350}
351
352void
353free_init(void)
354{
355 free_cmd.name = _("df");
356 free_cmd.altname = _("free");
357 free_cmd.cfunc = free_f;
358 free_cmd.argmin = 0;
359 free_cmd.argmax = -1;
360 free_cmd.args = _("[-bir] [-hn] [-f file]");
361 free_cmd.oneline = _("show free and used counts for blocks and inodes");
362 free_cmd.help = free_help;
363
364 add_command(&free_cmd);
365}