]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/free.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[thirdparty/xfsprogs-dev.git] / quota / free.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include <xfs/command.h>
20 #include "init.h"
21 #include "quota.h"
22
23 static cmdinfo_t free_cmd;
24
25 static void
26 free_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"
40 " -N -- suppress the header from the output\n"
41 "\n"));
42 }
43
44 static int
45 mount_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
106 static int
107 projects_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;
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
143 if (path->fs_prid != fsx.fsx_projid) {
144 fprintf(stderr,
145 _("%s: project ID %u (%s) doesn't match ID %u (%s)\n"),
146 progname, path->fs_prid, projects_file,
147 fsx.fsx_projid, path->fs_dir);
148 close(fd);
149 return 0;
150 }
151
152 xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL);
153 if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) {
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
185 static int
186 free_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
276 static void
277 free_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
294 static int
295 free_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
303 while ((c = getopt(argc, argv, "bf:hNir")) != EOF) {
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;
320 case 'N':
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
347 void
348 free_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 }