]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/free.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[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
96 count = fsgeo.rtextents * fsgeo.rtextsize;
97 free = fscounts.freertx * fsgeo.rtextsize;
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{
119 fs_disk_quota_t d;
120 struct fsxattr fsx;
5aead01d
NS
121 uint type = XFS_PROJ_QUOTA;
122 char *dev = path->fs_name;
123 int fd;
124
125 if ((fd = open(path->fs_dir, O_RDONLY)) < 0) {
126 fprintf(stderr, "%s: cannot open %s: %s\n",
127 progname, path->fs_dir, strerror(errno));
128 return 0;
129 }
130
131 if ((xfsctl(path->fs_dir, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
132 perror("XFS_IOC_FSGETXATTR");
133 close(fd);
134 return 0;
135 }
136 if (!(fsx.fsx_xflags & XFS_XFLAG_PROJINHERIT)) {
137 fprintf(stderr, _("%s: project quota flag not set on %s\n"),
138 progname, path->fs_dir);
139 close(fd);
140 return 0;
141 }
142
764b1982 143 if (path->fs_prid != fsx.fsx_projid) {
5aead01d
NS
144 fprintf(stderr,
145 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
146 progname, path->fs_prid, projects_file,
764b1982 147 fsx.fsx_projid, path->fs_dir);
5aead01d
NS
148 close(fd);
149 return 0;
150 }
151
764b1982
NS
152 xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL);
153 if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) {
5aead01d
NS
154 perror("XFS_GETQUOTA");
155 close(fd);
156 return 0;
157 }
158
159 /* If no softlimit is set for any of blk/ino/rt, get actual usage */
160 if (!d.d_blk_softlimit || !d.d_ino_softlimit || !d.d_rtb_softlimit) {
161 mount_free_space_data(path, bcount, bused, bfree,
162 icount, iused, ifree, rcount, rused, rfree);
163 }
164
165 if (d.d_blk_softlimit) {
166 *bcount = d.d_blk_softlimit << 1;
167 *bfree = (d.d_blk_softlimit - d.d_bcount) << 1;
168 }
169 *bused = d.d_bcount << 1;
170 if (d.d_ino_softlimit) {
171 *icount = d.d_ino_softlimit;
172 *ifree = (d.d_ino_softlimit - d.d_icount);
173 }
174 *iused = d.d_icount;
175 if (d.d_rtb_softlimit) {
176 *rcount = d.d_rtb_softlimit << 1;
177 *rfree = (d.d_rtb_softlimit - d.d_rtbcount) << 1;
178 }
179 *rcount = d.d_rtbcount << 1;
180
181 close(fd);
182 return 1;
183}
184
185static int
186free_space(
187 FILE *fp,
188 uint form,
189 fs_path_t *path,
190 uint flags)
191{
192 __uint64_t bcount, bused, bfree;
193 __uint64_t icount, iused, ifree;
194 __uint64_t rcount, rused, rfree;
195 char a[8], s[8], u[8], p[8];
196 int count;
197
198 count = (path->fs_flags & FS_PROJECT_PATH) ?
199 projects_free_space_data(path, &bcount, &bused, &bfree,
200 &icount, &iused, &ifree,
201 &rcount, &rused, &rfree) :
202 mount_free_space_data(path, &bcount, &bused, &bfree,
203 &icount, &iused, &ifree,
204 &rcount, &rused, &rfree);
205 if (!count)
206 return 0;
207
208 if (!(flags & NO_HEADER_FLAG)) {
209 fprintf(fp, (flags & HUMAN_FLAG) ?
210 _("Filesystem ") : _("Filesystem "));
211 if (form & (XFS_BLOCK_QUOTA|XFS_RTBLOCK_QUOTA))
212 fprintf(fp, (flags & HUMAN_FLAG) ?
213 _(" Size Used Avail Use%%") :
214 _(" 1K-blocks Used Available Use%%"));
215 else if (form & XFS_INODE_QUOTA)
216 fprintf(fp, (flags & HUMAN_FLAG) ?
217 _(" Inodes Used Free Use%%") :
218 _(" Inodes IUsed IFree IUse%%"));
219 fprintf(fp, _(" Pathname\n"));
220 }
221
222 if (flags & HUMAN_FLAG) {
223 count = fprintf(fp, "%-12s", path->fs_name);
224 if (count > 13)
225 fprintf(fp, "\n%12s", " ");
226 } else {
227 count = fprintf(fp, "%-19s", path->fs_name);
228 if (count > 20)
229 fprintf(fp, "\n%19s", " ");
230 }
231
232 if (form & XFS_BLOCK_QUOTA) {
233 if (flags & HUMAN_FLAG)
234 fprintf(fp, " %6s %6s %6s %3s%%",
235 bbs_to_string(bcount, s, sizeof(s)),
236 bbs_to_string(bused, u, sizeof(u)),
237 bbs_to_string(bfree, a, sizeof(a)),
238 pct_to_string(bused, bcount, p, sizeof(p)));
239 else
240 fprintf(fp, " %10llu %10llu %10llu %3s%%",
241 (unsigned long long)bcount >> 1,
242 (unsigned long long)bused >> 1,
243 (unsigned long long)bfree >> 1,
244 pct_to_string(bused, bcount, p, sizeof(p)));
245 } else if (form & XFS_INODE_QUOTA) {
246 if (flags & HUMAN_FLAG)
247 fprintf(fp, " %6s %6s %6s %3s%%",
248 num_to_string(icount, s, sizeof(s)),
249 num_to_string(iused, u, sizeof(u)),
250 num_to_string(ifree, a, sizeof(a)),
251 pct_to_string(iused, icount, p, sizeof(p)));
252 else
253 fprintf(fp, " %10llu %10llu %10llu %3s%%",
254 (unsigned long long)icount,
255 (unsigned long long)iused,
256 (unsigned long long)ifree,
257 pct_to_string(iused, icount, p, sizeof(p)));
258 } else if (form & XFS_RTBLOCK_QUOTA) {
259 if (flags & HUMAN_FLAG)
260 fprintf(fp, " %6s %6s %6s %3s%%",
261 bbs_to_string(rcount, s, sizeof(s)),
262 bbs_to_string(rused, u, sizeof(u)),
263 bbs_to_string(rfree, a, sizeof(a)),
264 pct_to_string(rused, rcount, p, sizeof(p)));
265 else
266 fprintf(fp, " %10llu %10llu %10llu %3s%%",
267 (unsigned long long)rcount >> 1,
268 (unsigned long long)rused >> 1,
269 (unsigned long long)rfree >> 1,
270 pct_to_string(rused, rcount, p, sizeof(p)));
271 }
272 fprintf(fp, " %s\n", path->fs_dir);
273 return 1;
274}
275
276static void
277free_space_list(
278 FILE *fp,
279 uint form,
280 uint type,
281 char *dir,
282 uint flags)
283{
284 fs_cursor_t cursor;
285 fs_path_t *path;
286
287 fs_cursor_initialise(dir, type, &cursor);
288 while ((path = fs_cursor_next_entry(&cursor))) {
289 if (free_space(fp, form, path, flags))
290 flags |= NO_HEADER_FLAG;
291 }
292}
293
294static int
295free_f(
296 int argc,
297 char **argv)
298{
299 FILE *fp = NULL;
300 char *fname = NULL;
301 int c, flags = 0, form = 0, type = 0;
302
1774874a 303 while ((c = getopt(argc, argv, "bf:hNir")) != EOF) {
5aead01d
NS
304 switch (c) {
305 case 'f':
306 fname = optarg;
307 break;
308 case 'b':
309 form |= XFS_BLOCK_QUOTA;
310 break;
311 case 'i':
312 form |= XFS_INODE_QUOTA;
313 break;
314 case 'r':
315 form |= XFS_RTBLOCK_QUOTA;
316 break;
317 case 'h':
318 flags |= HUMAN_FLAG;
319 break;
1774874a 320 case 'N':
5aead01d
NS
321 flags |= NO_HEADER_FLAG;
322 break;
323 default:
324 return command_usage(&free_cmd);
325 }
326 }
327
328 if (!form)
329 form = XFS_BLOCK_QUOTA;
330
331 if (!type)
332 type = FS_MOUNT_POINT|FS_PROJECT_PATH;
333
334 if ((fp = fopen_write_secure(fname)) == NULL)
335 return 0;
336
337 if (argc == optind)
338 free_space_list(fp, form, type, NULL, flags);
339 else while (argc > optind)
340 free_space_list(fp, form, type, argv[optind++], flags);
341
342 if (fname)
343 fclose(fp);
344 return 0;
345}
346
347void
348free_init(void)
349{
350 free_cmd.name = _("df");
351 free_cmd.altname = _("free");
352 free_cmd.cfunc = free_f;
353 free_cmd.argmin = 0;
354 free_cmd.argmax = -1;
355 free_cmd.args = _("[-bir] [-hn] [-f file]");
356 free_cmd.oneline = _("show free and used counts for blocks and inodes");
357 free_cmd.help = free_help;
358
359 add_command(&free_cmd);
360}