]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/stat.c
xfs: convert to new timestamp accessors
[thirdparty/xfsprogs-dev.git] / io / stat.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 * Copyright (C) 2015, 2017 Red Hat, Inc.
6 * Portions of statx support written by David Howells (dhowells@redhat.com)
7 */
8
9 #include "command.h"
10 #include "input.h"
11 #include "init.h"
12 #include "io.h"
13 #include "statx.h"
14 #include "libxfs.h"
15 #include "libfrog/logging.h"
16 #include "libfrog/fsgeom.h"
17
18 #include <fcntl.h>
19
20 static cmdinfo_t stat_cmd;
21 static cmdinfo_t statfs_cmd;
22 static cmdinfo_t statx_cmd;
23
24 off64_t
25 filesize(void)
26 {
27 struct stat st;
28
29 if (fstat(file->fd, &st) < 0) {
30 perror("fstat");
31 return -1;
32 }
33 return st.st_size;
34 }
35
36 static char *
37 filetype(mode_t mode)
38 {
39 switch (mode & S_IFMT) {
40 case S_IFSOCK:
41 return _("socket");
42 case S_IFDIR:
43 return _("directory");
44 case S_IFCHR:
45 return _("char device");
46 case S_IFBLK:
47 return _("block device");
48 case S_IFREG:
49 return _("regular file");
50 case S_IFLNK:
51 return _("symbolic link");
52 case S_IFIFO:
53 return _("fifo");
54 }
55 return NULL;
56 }
57
58 static int
59 dump_raw_stat(struct stat *st)
60 {
61 printf("stat.blksize = %lu\n", (unsigned long)st->st_blksize);
62 printf("stat.nlink = %lu\n", (unsigned long)st->st_nlink);
63 printf("stat.uid = %u\n", st->st_uid);
64 printf("stat.gid = %u\n", st->st_gid);
65 printf("stat.mode: 0%o\n", st->st_mode);
66 printf("stat.ino = %llu\n", (unsigned long long)st->st_ino);
67 printf("stat.size = %lld\n", (long long)st->st_size);
68 printf("stat.blocks = %lld\n", (long long)st->st_blocks);
69 printf("stat.atime.tv_sec = %ld\n", st->st_atim.tv_sec);
70 printf("stat.atime.tv_nsec = %ld\n", st->st_atim.tv_nsec);
71 printf("stat.ctime.tv_sec = %ld\n", st->st_ctim.tv_sec);
72 printf("stat.ctime.tv_nsec = %ld\n", st->st_ctim.tv_nsec);
73 printf("stat.mtime.tv_sec = %ld\n", st->st_mtim.tv_sec);
74 printf("stat.mtime.tv_nsec = %ld\n", st->st_mtim.tv_nsec);
75 printf("stat.rdev_major = %u\n", major(st->st_rdev));
76 printf("stat.rdev_minor = %u\n", minor(st->st_rdev));
77 printf("stat.dev_major = %u\n", major(st->st_dev));
78 printf("stat.dev_minor = %u\n", minor(st->st_dev));
79 return 0;
80 }
81
82 static void
83 print_file_info(void)
84 {
85 printf(_("fd.path = \"%s\"\n"), file->name);
86 printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"),
87 file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
88 file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
89 file->flags & IO_READONLY ? _("read-only") : _("read-write"),
90 file->flags & IO_REALTIME ? _(",real-time") : "",
91 file->flags & IO_APPEND ? _(",append-only") : "",
92 file->flags & IO_NONBLOCK ? _(",non-block") : "",
93 file->flags & IO_TMPFILE ? _(",tmpfile") : "");
94 }
95
96 static void
97 print_xfs_info(int verbose)
98 {
99 struct dioattr dio;
100 struct fsxattr fsx, fsxa;
101
102 if ((xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0 ||
103 (xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTRA, &fsxa)) < 0) {
104 perror("FS_IOC_FSGETXATTR");
105 } else {
106 printf(_("fsxattr.xflags = 0x%x "), fsx.fsx_xflags);
107 printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1);
108 printf(_("fsxattr.projid = %u\n"), fsx.fsx_projid);
109 printf(_("fsxattr.extsize = %u\n"), fsx.fsx_extsize);
110 printf(_("fsxattr.cowextsize = %u\n"), fsx.fsx_cowextsize);
111 printf(_("fsxattr.nextents = %u\n"), fsx.fsx_nextents);
112 printf(_("fsxattr.naextents = %u\n"), fsxa.fsx_nextents);
113 }
114 if ((xfsctl(file->name, file->fd, XFS_IOC_DIOINFO, &dio)) < 0) {
115 perror("XFS_IOC_DIOINFO");
116 } else {
117 printf(_("dioattr.mem = 0x%x\n"), dio.d_mem);
118 printf(_("dioattr.miniosz = %u\n"), dio.d_miniosz);
119 printf(_("dioattr.maxiosz = %u\n"), dio.d_maxiosz);
120 }
121 }
122
123 int
124 stat_f(
125 int argc,
126 char **argv)
127 {
128 struct stat st;
129 int c, verbose = 0, raw = 0;
130
131 while ((c = getopt(argc, argv, "rv")) != EOF) {
132 switch (c) {
133 case 'r':
134 raw = 1;
135 break;
136 case 'v':
137 verbose = 1;
138 break;
139 default:
140 exitcode = 1;
141 return command_usage(&stat_cmd);
142 }
143 }
144
145 if (fstat(file->fd, &st) < 0) {
146 perror("fstat");
147 exitcode = 1;
148 return 0;
149 }
150
151 if (raw)
152 return dump_raw_stat(&st);
153
154 print_file_info();
155
156 printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
157 printf(_("stat.type = %s\n"), filetype(st.st_mode));
158 printf(_("stat.size = %lld\n"), (long long)st.st_size);
159 printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
160 if (verbose) {
161 printf(_("stat.atime = %s"), ctime(&st.st_atime));
162 printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
163 printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
164 }
165
166 if (file->flags & IO_FOREIGN)
167 return 0;
168
169 print_xfs_info(verbose);
170
171 return 0;
172 }
173
174 static void
175 statfs_help(void)
176 {
177 printf(_(
178 "\n"
179 " Display file system status.\n"
180 "\n"
181 " Options:\n"
182 " -c -- Print fs summary count data.\n"
183 " -g -- Print fs geometry data.\n"
184 " -s -- Print statfs data.\n"
185 "\n"));
186 }
187
188 #define REPORT_STATFS (1 << 0)
189 #define REPORT_GEOMETRY (1 << 1)
190 #define REPORT_FSCOUNTS (1 << 2)
191
192 static int
193 statfs_f(
194 int argc,
195 char **argv)
196 {
197 struct xfs_fsop_counts fscounts;
198 struct xfs_fsop_geom fsgeo;
199 struct statfs st;
200 unsigned int flags = 0;
201 int c;
202 int ret;
203
204 while ((c = getopt(argc, argv, "cgs")) != EOF) {
205 switch (c) {
206 case 'c':
207 flags |= REPORT_FSCOUNTS;
208 break;
209 case 'g':
210 flags |= REPORT_GEOMETRY;
211 break;
212 case 's':
213 flags |= REPORT_STATFS;
214 break;
215 default:
216 exitcode = 1;
217 return command_usage(&statfs_cmd);
218 }
219 }
220
221 if (!flags)
222 flags = REPORT_STATFS | REPORT_GEOMETRY | REPORT_FSCOUNTS;
223
224 printf(_("fd.path = \"%s\"\n"), file->name);
225 if (flags & REPORT_STATFS) {
226 ret = platform_fstatfs(file->fd, &st);
227 if (ret < 0) {
228 perror("fstatfs");
229 exitcode = 1;
230 } else {
231 printf(_("statfs.f_bsize = %lld\n"),
232 (long long) st.f_bsize);
233 printf(_("statfs.f_blocks = %lld\n"),
234 (long long) st.f_blocks);
235 printf(_("statfs.f_bavail = %lld\n"),
236 (long long) st.f_bavail);
237 printf(_("statfs.f_files = %lld\n"),
238 (long long) st.f_files);
239 printf(_("statfs.f_ffree = %lld\n"),
240 (long long) st.f_ffree);
241 #ifdef HAVE_STATFS_FLAGS
242 printf(_("statfs.f_flags = 0x%llx\n"),
243 (long long) st.f_flags);
244 #endif
245 }
246 }
247
248 if (file->flags & IO_FOREIGN)
249 return 0;
250
251 if (flags & REPORT_GEOMETRY) {
252 ret = -xfrog_geometry(file->fd, &fsgeo);
253 if (ret) {
254 xfrog_perror(ret, "XFS_IOC_FSGEOMETRY");
255 exitcode = 1;
256 } else {
257 printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
258 printf(_("geom.agcount = %u\n"), fsgeo.agcount);
259 printf(_("geom.agblocks = %u\n"), fsgeo.agblocks);
260 printf(_("geom.datablocks = %llu\n"),
261 (unsigned long long) fsgeo.datablocks);
262 printf(_("geom.rtblocks = %llu\n"),
263 (unsigned long long) fsgeo.rtblocks);
264 printf(_("geom.rtextents = %llu\n"),
265 (unsigned long long) fsgeo.rtextents);
266 printf(_("geom.rtextsize = %u\n"), fsgeo.rtextsize);
267 printf(_("geom.sunit = %u\n"), fsgeo.sunit);
268 printf(_("geom.swidth = %u\n"), fsgeo.swidth);
269 }
270 }
271
272 if (flags & REPORT_FSCOUNTS) {
273 ret = ioctl(file->fd, XFS_IOC_FSCOUNTS, &fscounts);
274 if (ret < 0) {
275 perror("XFS_IOC_FSCOUNTS");
276 exitcode = 1;
277 } else {
278 printf(_("counts.freedata = %llu\n"),
279 (unsigned long long) fscounts.freedata);
280 printf(_("counts.freertx = %llu\n"),
281 (unsigned long long) fscounts.freertx);
282 printf(_("counts.freeino = %llu\n"),
283 (unsigned long long) fscounts.freeino);
284 printf(_("counts.allocino = %llu\n"),
285 (unsigned long long) fscounts.allocino);
286 }
287 }
288
289 return 0;
290 }
291
292 static ssize_t
293 _statx(
294 int dfd,
295 const char *filename,
296 unsigned int flags,
297 unsigned int mask,
298 struct statx *buffer)
299 {
300 #ifdef __NR_statx
301 return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
302 #else
303 errno = ENOSYS;
304 return -1;
305 #endif
306 }
307
308 static void
309 statx_help(void)
310 {
311 printf(_(
312 "\n"
313 " Display extended file status.\n"
314 "\n"
315 " Options:\n"
316 " -v -- More verbose output\n"
317 " -r -- Print raw statx structure fields\n"
318 " -m mask -- Specify the field mask for the statx call\n"
319 " (can also be 'basic' or 'all'; default STATX_ALL)\n"
320 " -D -- Don't sync attributes with the server\n"
321 " -F -- Force the attributes to be sync'd with the server\n"
322 "\n"));
323 }
324
325 /* statx helper */
326 static int
327 dump_raw_statx(struct statx *stx)
328 {
329 printf("stat.mask = 0x%x\n", stx->stx_mask);
330 printf("stat.blksize = %u\n", stx->stx_blksize);
331 printf("stat.attributes = 0x%llx\n", (unsigned long long)stx->stx_attributes);
332 printf("stat.nlink = %u\n", stx->stx_nlink);
333 printf("stat.uid = %u\n", stx->stx_uid);
334 printf("stat.gid = %u\n", stx->stx_gid);
335 printf("stat.mode: 0%o\n", stx->stx_mode);
336 printf("stat.ino = %llu\n", (unsigned long long)stx->stx_ino);
337 printf("stat.size = %llu\n", (unsigned long long)stx->stx_size);
338 printf("stat.blocks = %llu\n", (unsigned long long)stx->stx_blocks);
339 printf("stat.attributes_mask = 0x%llx\n", (unsigned long long)stx->stx_attributes_mask);
340 printf("stat.atime.tv_sec = %lld\n", (long long)stx->stx_atime.tv_sec);
341 printf("stat.atime.tv_nsec = %d\n", stx->stx_atime.tv_nsec);
342 printf("stat.btime.tv_sec = %lld\n", (long long)stx->stx_btime.tv_sec);
343 printf("stat.btime.tv_nsec = %d\n", stx->stx_btime.tv_nsec);
344 printf("stat.ctime.tv_sec = %lld\n", (long long)stx->stx_ctime.tv_sec);
345 printf("stat.ctime.tv_nsec = %d\n", stx->stx_ctime.tv_nsec);
346 printf("stat.mtime.tv_sec = %lld\n", (long long)stx->stx_mtime.tv_sec);
347 printf("stat.mtime.tv_nsec = %d\n", stx->stx_mtime.tv_nsec);
348 printf("stat.rdev_major = %u\n", stx->stx_rdev_major);
349 printf("stat.rdev_minor = %u\n", stx->stx_rdev_minor);
350 printf("stat.dev_major = %u\n", stx->stx_dev_major);
351 printf("stat.dev_minor = %u\n", stx->stx_dev_minor);
352 return 0;
353 }
354
355 /*
356 * options:
357 * - input flags - query type
358 * - output style for flags (and all else?) (chars vs. hex?)
359 * - output - mask out incidental flag or not?
360 */
361 static int
362 statx_f(
363 int argc,
364 char **argv)
365 {
366 int c, verbose = 0, raw = 0;
367 char *p;
368 struct statx stx;
369 int atflag = 0;
370 unsigned int mask = STATX_ALL;
371
372 while ((c = getopt(argc, argv, "m:rvFD")) != EOF) {
373 switch (c) {
374 case 'm':
375 if (strcmp(optarg, "basic") == 0)
376 mask = STATX_BASIC_STATS;
377 else if (strcmp(optarg, "all") == 0)
378 mask = STATX_ALL;
379 else {
380 mask = strtoul(optarg, &p, 0);
381 if (!p || p == optarg) {
382 printf(
383 _("non-numeric mask -- %s\n"), optarg);
384 exitcode = 1;
385 return 0;
386 }
387 }
388 break;
389 case 'r':
390 raw = 1;
391 break;
392 case 'v':
393 verbose = 1;
394 break;
395 case 'F':
396 atflag &= ~AT_STATX_SYNC_TYPE;
397 atflag |= AT_STATX_FORCE_SYNC;
398 break;
399 case 'D':
400 atflag &= ~AT_STATX_SYNC_TYPE;
401 atflag |= AT_STATX_DONT_SYNC;
402 break;
403 default:
404 exitcode = 1;
405 return command_usage(&statx_cmd);
406 }
407 }
408
409 if (raw && verbose)
410 return command_usage(&statx_cmd);
411
412 memset(&stx, 0xbf, sizeof(stx));
413 if (_statx(file->fd, "", atflag | AT_EMPTY_PATH, mask, &stx) < 0) {
414 perror("statx");
415 exitcode = 1;
416 return 0;
417 }
418 exitcode = 0;
419
420 if (raw)
421 return dump_raw_statx(&stx);
422
423 print_file_info();
424
425 printf(_("stat.ino = %lld\n"), (long long)stx.stx_ino);
426 printf(_("stat.type = %s\n"), filetype(stx.stx_mode));
427 printf(_("stat.size = %lld\n"), (long long)stx.stx_size);
428 printf(_("stat.blocks = %lld\n"), (long long)stx.stx_blocks);
429 if (verbose) {
430 printf(_("stat.atime = %s"), ctime((time_t *)&stx.stx_atime.tv_sec));
431 printf(_("stat.mtime = %s"), ctime((time_t *)&stx.stx_mtime.tv_sec));
432 printf(_("stat.ctime = %s"), ctime((time_t *)&stx.stx_ctime.tv_sec));
433 if (stx.stx_mask & STATX_BTIME)
434 printf(_("stat.btime = %s"),
435 ctime((time_t *)&stx.stx_btime.tv_sec));
436 }
437
438 if (file->flags & IO_FOREIGN)
439 return 0;
440
441 print_xfs_info(verbose);
442
443 return 0;
444 }
445
446 void
447 stat_init(void)
448 {
449 stat_cmd.name = "stat";
450 stat_cmd.cfunc = stat_f;
451 stat_cmd.argmin = 0;
452 stat_cmd.argmax = 1;
453 stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
454 stat_cmd.args = _("[-v|-r]");
455 stat_cmd.oneline = _("statistics on the currently open file");
456
457 statx_cmd.name = "statx";
458 statx_cmd.cfunc = statx_f;
459 statx_cmd.argmin = 0;
460 statx_cmd.argmax = -1;
461 statx_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
462 statx_cmd.args = _("[-v|-r][-m basic | -m all | -m <mask>][-FD]");
463 statx_cmd.oneline = _("extended statistics on the currently open file");
464 statx_cmd.help = statx_help;
465
466 statfs_cmd.name = "statfs";
467 statfs_cmd.cfunc = statfs_f;
468 statfs_cmd.argmin = 0;
469 statfs_cmd.argmax = -1;
470 statfs_cmd.args = _("[-c] [-g] [-s]");
471 statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
472 statfs_cmd.oneline =
473 _("statistics on the filesystem of the currently open file");
474 statfs_cmd.help = statfs_help;
475
476 add_command(&stat_cmd);
477 add_command(&statx_cmd);
478 add_command(&statfs_cmd);
479 }