]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/open.c
xfs_io: fix inode command with "-n" for bogus inode
[thirdparty/xfsprogs-dev.git] / io / open.c
CommitLineData
e246ba5f 1/*
da23017d
NS
2 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 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
e246ba5f 7 * published by the Free Software Foundation.
dfc130f3 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.
dfc130f3 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
e246ba5f 17 */
dfc130f3 18
6b803e5a
CH
19#include "command.h"
20#include "input.h"
e246ba5f 21#include "init.h"
48c46ee3 22#include "io.h"
ef25c9e4 23#include "libxfs.h"
e246ba5f 24
da2b3c09
CH
25#ifndef __O_TMPFILE
26#if defined __alpha__
27#define __O_TMPFILE 0100000000
28#elif defined(__hppa__)
29#define __O_TMPFILE 040000000
30#elif defined(__sparc__)
31#define __O_TMPFILE 0x2000000
32#else
33#define __O_TMPFILE 020000000
34#endif
35#endif /* __O_TMPFILE */
36
37#ifndef O_TMPFILE
38#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
39#endif
40
e246ba5f
NS
41static cmdinfo_t open_cmd;
42static cmdinfo_t stat_cmd;
48c46ee3 43static cmdinfo_t close_cmd;
e246ba5f 44static cmdinfo_t statfs_cmd;
5ecb3de2
NS
45static cmdinfo_t chproj_cmd;
46static cmdinfo_t lsproj_cmd;
9b5ee343 47static cmdinfo_t extsize_cmd;
ef25c9e4 48static cmdinfo_t inode_cmd;
3d93ccb7 49static prid_t prid;
0e51fd13 50static long extsize;
48c46ee3
NS
51
52off64_t
53filesize(void)
54{
55 struct stat64 st;
56
57 if (fstat64(file->fd, &st) < 0) {
58 perror("fstat64");
59 return -1;
60 }
61 return st.st_size;
62}
63
64static char *
65filetype(mode_t mode)
66{
67 switch (mode & S_IFMT) {
68 case S_IFSOCK:
69 return _("socket");
70 case S_IFDIR:
71 return _("directory");
72 case S_IFCHR:
73 return _("char device");
74 case S_IFBLK:
75 return _("block device");
76 case S_IFREG:
77 return _("regular file");
78 case S_IFLNK:
79 return _("symbolic link");
80 case S_IFIFO:
81 return _("fifo");
82 }
83 return NULL;
84}
85
48c46ee3
NS
86static int
87stat_f(
88 int argc,
89 char **argv)
90{
d347f827
NS
91 struct dioattr dio;
92 struct fsxattr fsx, fsxa;
48c46ee3
NS
93 struct stat64 st;
94 int verbose = (argc == 2 && !strcmp(argv[1], "-v"));
95
96 printf(_("fd.path = \"%s\"\n"), file->name);
da2b3c09 97 printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"),
48c46ee3
NS
98 file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
99 file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
100 file->flags & IO_READONLY ? _("read-only") : _("read-write"),
101 file->flags & IO_REALTIME ? _(",real-time") : "",
57f46ec0 102 file->flags & IO_APPEND ? _(",append-only") : "",
da2b3c09
CH
103 file->flags & IO_NONBLOCK ? _(",non-block") : "",
104 file->flags & IO_TMPFILE ? _(",tmpfile") : "");
48c46ee3
NS
105 if (fstat64(file->fd, &st) < 0) {
106 perror("fstat64");
107 } else {
108 printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
109 printf(_("stat.type = %s\n"), filetype(st.st_mode));
110 printf(_("stat.size = %lld\n"), (long long)st.st_size);
111 printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
112 if (verbose) {
113 printf(_("stat.atime = %s"), ctime(&st.st_atime));
114 printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
115 printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
116 }
117 }
118 if (file->flags & IO_FOREIGN)
119 return 0;
83f4b5ac 120 if ((xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0 ||
d347f827 121 (xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTRA, &fsxa)) < 0) {
83f4b5ac 122 perror("FS_IOC_FSGETXATTR");
48c46ee3 123 } else {
d347f827 124 printf(_("fsxattr.xflags = 0x%x "), fsx.fsx_xflags);
2ac030ae 125 printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1);
d347f827
NS
126 printf(_("fsxattr.projid = %u\n"), fsx.fsx_projid);
127 printf(_("fsxattr.extsize = %u\n"), fsx.fsx_extsize);
128 printf(_("fsxattr.nextents = %u\n"), fsx.fsx_nextents);
129 printf(_("fsxattr.naextents = %u\n"), fsxa.fsx_nextents);
130 }
131 if ((xfsctl(file->name, file->fd, XFS_IOC_DIOINFO, &dio)) < 0) {
132 perror("XFS_IOC_DIOINFO");
133 } else {
134 printf(_("dioattr.mem = 0x%x\n"), dio.d_mem);
135 printf(_("dioattr.miniosz = %u\n"), dio.d_miniosz);
136 printf(_("dioattr.maxiosz = %u\n"), dio.d_maxiosz);
48c46ee3
NS
137 }
138 return 0;
139}
e246ba5f
NS
140
141int
142openfile(
93d9f139 143 char *path,
638473d8 144 xfs_fsop_geom_t *geom,
48c46ee3
NS
145 int flags,
146 mode_t mode)
e246ba5f
NS
147{
148 int fd;
149 int oflags;
e246ba5f 150
48c46ee3
NS
151 oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
152 if (flags & IO_APPEND)
e246ba5f 153 oflags |= O_APPEND;
48c46ee3 154 if (flags & IO_CREAT)
e246ba5f 155 oflags |= O_CREAT;
48c46ee3 156 if (flags & IO_DIRECT)
e246ba5f 157 oflags |= O_DIRECT;
48c46ee3 158 if (flags & IO_OSYNC)
e246ba5f 159 oflags |= O_SYNC;
48c46ee3 160 if (flags & IO_TRUNC)
e246ba5f 161 oflags |= O_TRUNC;
57f46ec0
NS
162 if (flags & IO_NONBLOCK)
163 oflags |= O_NONBLOCK;
da2b3c09
CH
164 if (flags & IO_TMPFILE)
165 oflags |= O_TMPFILE;
e246ba5f 166
48c46ee3 167 fd = open(path, oflags, mode);
e246ba5f 168 if (fd < 0) {
da2b3c09
CH
169 if (errno == EISDIR &&
170 ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) {
258b00ea
TS
171 /* make it as if we asked for O_RDONLY & try again */
172 oflags &= ~O_RDWR;
173 oflags |= O_RDONLY;
174 flags |= IO_READONLY;
175 fd = open(path, oflags, mode);
176 if (fd < 0) {
177 perror(path);
178 return -1;
179 }
180 } else {
181 perror(path);
182 return -1;
183 }
e246ba5f 184 }
48c46ee3 185
1bc7dfb2 186 if (!geom || !platform_test_xfs_fd(fd))
db0bb90c
NS
187 return fd;
188
638473d8
NS
189 if (xfsctl(path, fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
190 perror("XFS_IOC_FSGEOMETRY");
191 close(fd);
192 return -1;
193 }
194
48c46ee3 195 if (!(flags & IO_READONLY) && (flags & IO_REALTIME)) {
e246ba5f
NS
196 struct fsxattr attr;
197
83f4b5ac
DC
198 if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &attr) < 0) {
199 perror("FS_IOC_FSGETXATTR");
e246ba5f
NS
200 close(fd);
201 return -1;
202 }
83f4b5ac
DC
203 if (!(attr.fsx_xflags & FS_XFLAG_REALTIME)) {
204 attr.fsx_xflags |= FS_XFLAG_REALTIME;
205 if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &attr) < 0) {
206 perror("FS_IOC_FSSETXATTR");
e246ba5f
NS
207 close(fd);
208 return -1;
209 }
210 }
211 }
212 return fd;
213}
214
48c46ee3
NS
215int
216addfile(
217 char *name,
218 int fd,
219 xfs_fsop_geom_t *geometry,
220 int flags)
e246ba5f 221{
48c46ee3
NS
222 char *filename;
223
224 filename = strdup(name);
225 if (!filename) {
226 perror("strdup");
227 close(fd);
228 return -1;
229 }
230
231 /* Extend the table of currently open files */
232 filetable = (fileio_t *)realloc(filetable, /* growing */
233 ++filecount * sizeof(fileio_t));
234 if (!filetable) {
235 perror("realloc");
236 filecount = 0;
237 free(filename);
238 close(fd);
239 return -1;
240 }
241
242 /* Finally, make this the new active open file */
243 file = &filetable[filecount - 1];
244 file->fd = fd;
245 file->flags = flags;
246 file->name = filename;
247 file->geom = *geometry;
e246ba5f
NS
248 return 0;
249}
250
251static void
252open_help(void)
253{
254 printf(_(
255"\n"
48c46ee3 256" opens a new file in the requested mode\n"
e246ba5f
NS
257"\n"
258" Example:\n"
48c46ee3 259" 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
e246ba5f
NS
260"\n"
261" Opens a file for subsequent use by all of the other xfs_io commands.\n"
262" With no arguments, open uses the stat command to show the current file.\n"
263" -a -- open with the O_APPEND flag (append-only mode)\n"
e246ba5f 264" -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
48c46ee3
NS
265" -f -- open with O_CREAT (create the file if it doesn't exist)\n"
266" -m -- permissions to use in case a new file is created (default 0600)\n"
57f46ec0 267" -n -- open with O_NONBLOCK\n"
e246ba5f
NS
268" -r -- open with O_RDONLY, the default is O_RDWR\n"
269" -s -- open with O_SYNC\n"
270" -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
57f46ec0 271" -R -- mark the file as a realtime XFS file immediately after opening it\n"
da2b3c09 272" -T -- open with O_TMPFILE (create a file not visible in the namespace)\n"
48c46ee3
NS
273" Note1: usually read/write direct IO requests must be blocksize aligned;\n"
274" some kernels, however, allow sectorsize alignment for direct IO.\n"
275" Note2: the bmap for non-regular files can be obtained provided the file\n"
2c794e6e 276" was opened correctly (in particular, must be opened read-only).\n"
e246ba5f
NS
277"\n"));
278}
279
280static int
281open_f(
282 int argc,
283 char **argv)
284{
48c46ee3
NS
285 int c, fd, flags = 0;
286 char *sp;
287 mode_t mode = 0600;
f72d20ad 288 xfs_fsop_geom_t geometry = { 0 };
e246ba5f 289
48c46ee3
NS
290 if (argc == 1) {
291 if (file)
292 return stat_f(argc, argv);
293 fprintf(stderr, _("no files are open, try 'help open'\n"));
294 return 0;
295 }
e246ba5f 296
da2b3c09 297 while ((c = getopt(argc, argv, "FRTacdfm:nrstx")) != EOF) {
e246ba5f 298 switch (c) {
f72d20ad 299 case 'F':
d1b88183 300 /* Ignored / deprecated now, handled automatically */
f72d20ad 301 break;
e246ba5f 302 case 'a':
48c46ee3 303 flags |= IO_APPEND;
e246ba5f
NS
304 break;
305 case 'c':
48c46ee3
NS
306 case 'f':
307 flags |= IO_CREAT;
e246ba5f
NS
308 break;
309 case 'd':
48c46ee3
NS
310 flags |= IO_DIRECT;
311 break;
312 case 'm':
313 mode = strtoul(optarg, &sp, 0);
314 if (!sp || sp == optarg) {
315 printf(_("non-numeric mode -- %s\n"), optarg);
316 return 0;
317 }
e246ba5f 318 break;
57f46ec0
NS
319 case 'n':
320 flags |= IO_NONBLOCK;
321 break;
e246ba5f 322 case 'r':
48c46ee3 323 flags |= IO_READONLY;
e246ba5f
NS
324 break;
325 case 's':
48c46ee3 326 flags |= IO_OSYNC;
e246ba5f
NS
327 break;
328 case 't':
48c46ee3 329 flags |= IO_TRUNC;
e246ba5f 330 break;
57f46ec0
NS
331 case 'R':
332 case 'x': /* backwards compatibility */
48c46ee3 333 flags |= IO_REALTIME;
e246ba5f 334 break;
da2b3c09
CH
335 case 'T':
336 flags |= IO_TMPFILE;
337 break;
e246ba5f 338 default:
48c46ee3 339 return command_usage(&open_cmd);
e246ba5f
NS
340 }
341 }
342
343 if (optind != argc - 1)
48c46ee3 344 return command_usage(&open_cmd);
e246ba5f 345
ade06f83
ES
346 if ((flags & (IO_READONLY|IO_TMPFILE)) == (IO_READONLY|IO_TMPFILE)) {
347 fprintf(stderr, _("-T and -r options are incompatible\n"));
348 return -1;
349 }
350
d1b88183 351 fd = openfile(argv[optind], &geometry, flags, mode);
e246ba5f
NS
352 if (fd < 0)
353 return 0;
354
d1b88183
ES
355 if (!platform_test_xfs_fd(fd))
356 flags |= IO_FOREIGN;
357
48c46ee3 358 addfile(argv[optind], fd, &geometry, flags);
e246ba5f
NS
359 return 0;
360}
361
48c46ee3
NS
362static int
363close_f(
364 int argc,
365 char **argv)
e246ba5f 366{
48c46ee3
NS
367 size_t length;
368 unsigned int offset;
e246ba5f 369
48c46ee3
NS
370 if (close(file->fd) < 0) {
371 perror("close");
372 return 0;
e246ba5f 373 }
48c46ee3
NS
374 free(file->name);
375
376 /* Shuffle the file table entries down over the removed entry */
377 offset = file - &filetable[0];
378 length = filecount * sizeof(fileio_t);
379 length -= (offset + 1) * sizeof(fileio_t);
380 if (length)
381 memmove(file, file + 1, length);
382
383 /* Resize the memory allocated for the table, possibly freeing */
384 if (--filecount) {
385 filetable = (fileio_t *)realloc(filetable, /* shrinking */
386 filecount * sizeof(fileio_t));
387 if (offset == filecount)
388 offset--;
389 file = filetable + offset;
390 } else {
391 free(filetable);
392 file = filetable = NULL;
2c794e6e 393 }
48c46ee3
NS
394 filelist_f();
395 return 0;
2c794e6e
NS
396}
397
3d93ccb7
NS
398static void
399lsproj_help(void)
400{
401 printf(_(
402"\n"
403" displays the project identifier associated with the current path\n"
404"\n"
405" Options:\n"
406" -R -- recursively descend (useful when current path is a directory)\n"
407" -D -- recursively descend, but only list projects on directories\n"
408"\n"));
409}
410
411static int
412lsproj_callback(
413 const char *path,
414 const struct stat *stat,
415 int status,
416 struct FTW *data)
417{
418 prid_t projid;
419 int fd;
420
421 if (recurse_dir && !S_ISDIR(stat->st_mode))
422 return 0;
423
424 if ((fd = open(path, O_RDONLY)) == -1) {
425 fprintf(stderr, _("%s: cannot open %s: %s\n"),
426 progname, path, strerror(errno));
427 } else {
428 if (getprojid(path, fd, &projid) == 0)
2a1888c5 429 printf("[%u] %s\n", (unsigned int)projid, path);
3d93ccb7
NS
430 close(fd);
431 }
432 return 0;
433}
434
5ecb3de2
NS
435static int
436lsproj_f(
437 int argc,
438 char **argv)
439{
3d93ccb7
NS
440 prid_t projid;
441 int c;
5ecb3de2 442
0e51fd13 443 recurse_all = recurse_dir = 0;
3d93ccb7
NS
444 while ((c = getopt(argc, argv, "DR")) != EOF) {
445 switch (c) {
446 case 'D':
447 recurse_all = 0;
448 recurse_dir = 1;
449 break;
450 case 'R':
451 recurse_all = 1;
452 recurse_dir = 0;
453 break;
454 default:
455 return command_usage(&lsproj_cmd);
456 }
457 }
458
459 if (argc != optind)
460 return command_usage(&lsproj_cmd);
461
462 if (recurse_all || recurse_dir)
463 nftw(file->name, lsproj_callback,
464 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
465 else if (getprojid(file->name, file->fd, &projid) < 0)
466 perror("getprojid");
467 else
2a1888c5 468 printf(_("projid = %u\n"), (unsigned int)projid);
3d93ccb7
NS
469 return 0;
470}
471
472static void
473chproj_help(void)
474{
475 printf(_(
476"\n"
477" modifies the project identifier associated with the current path\n"
478"\n"
479" -R -- recursively descend (useful when current path is a directory)\n"
480" -D -- recursively descend, only modifying projects on directories\n"
481"\n"));
482}
483
484static int
485chproj_callback(
486 const char *path,
487 const struct stat *stat,
488 int status,
489 struct FTW *data)
490{
491 int fd;
492
493 if (recurse_dir && !S_ISDIR(stat->st_mode))
5ecb3de2 494 return 0;
3d93ccb7
NS
495
496 if ((fd = open(path, O_RDONLY)) == -1) {
497 fprintf(stderr, _("%s: cannot open %s: %s\n"),
498 progname, path, strerror(errno));
499 } else {
500 if (setprojid(path, fd, prid) < 0)
501 perror("setprojid");
502 close(fd);
5ecb3de2 503 }
5ecb3de2
NS
504 return 0;
505}
506
507static int
508chproj_f(
509 int argc,
510 char **argv)
511{
3d93ccb7 512 int c;
5ecb3de2 513
0e51fd13 514 recurse_all = recurse_dir = 0;
3d93ccb7
NS
515 while ((c = getopt(argc, argv, "DR")) != EOF) {
516 switch (c) {
517 case 'D':
518 recurse_all = 0;
519 recurse_dir = 1;
520 break;
521 case 'R':
522 recurse_all = 1;
523 recurse_dir = 0;
524 break;
525 default:
526 return command_usage(&chproj_cmd);
527 }
528 }
529
530 if (argc != optind + 1)
531 return command_usage(&chproj_cmd);
532
533 prid = prid_from_string(argv[optind]);
534 if (prid == -1) {
535 printf(_("invalid project ID -- %s\n"), argv[optind]);
5ecb3de2
NS
536 return 0;
537 }
3d93ccb7
NS
538
539 if (recurse_all || recurse_dir)
540 nftw(file->name, chproj_callback,
541 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
542 else if (setprojid(file->name, file->fd, prid) < 0)
543 perror("setprojid");
5ecb3de2
NS
544 return 0;
545}
546
0e51fd13
NS
547static void
548extsize_help(void)
549{
550 printf(_(
551"\n"
ff1f79a7 552" report or modify preferred extent size (in bytes) for the current path\n"
0e51fd13
NS
553"\n"
554" -R -- recursively descend (useful when current path is a directory)\n"
555" -D -- recursively descend, only modifying extsize on directories\n"
556"\n"));
557}
558
559static int
560get_extsize(const char *path, int fd)
561{
562 struct fsxattr fsx;
563
83f4b5ac
DC
564 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
565 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
0e51fd13
NS
566 progname, path, strerror(errno));
567 return 0;
568 }
569 printf("[%u] %s\n", fsx.fsx_extsize, path);
570 return 0;
571}
572
573static int
574set_extsize(const char *path, int fd, long extsz)
575{
576 struct fsxattr fsx;
577 struct stat64 stat;
578
579 if (fstat64(fd, &stat) < 0) {
580 perror("fstat64");
581 return 0;
582 }
83f4b5ac
DC
583 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
584 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
0e51fd13
NS
585 progname, path, strerror(errno));
586 return 0;
587 }
588
589 if (S_ISREG(stat.st_mode)) {
83f4b5ac 590 fsx.fsx_xflags |= FS_XFLAG_EXTSIZE;
0e51fd13 591 } else if (S_ISDIR(stat.st_mode)) {
83f4b5ac 592 fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT;
0e51fd13
NS
593 } else {
594 printf(_("invalid target file type - file %s\n"), path);
595 return 0;
596 }
597 fsx.fsx_extsize = extsz;
598
83f4b5ac
DC
599 if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) {
600 printf("%s: FS_IOC_FSSETXATTR %s: %s\n",
0e51fd13
NS
601 progname, path, strerror(errno));
602 return 0;
603 }
604
605 return 0;
606}
607
608static int
609get_extsize_callback(
610 const char *path,
611 const struct stat *stat,
612 int status,
613 struct FTW *data)
614{
615 int fd;
616
617 if (recurse_dir && !S_ISDIR(stat->st_mode))
618 return 0;
619
620 if ((fd = open(path, O_RDONLY)) == -1) {
621 fprintf(stderr, _("%s: cannot open %s: %s\n"),
622 progname, path, strerror(errno));
623 } else {
624 get_extsize(path, fd);
625 close(fd);
626 }
627 return 0;
628}
629
630static int
631set_extsize_callback(
632 const char *path,
633 const struct stat *stat,
634 int status,
635 struct FTW *data)
636{
637 int fd;
638
639 if (recurse_dir && !S_ISDIR(stat->st_mode))
640 return 0;
641
642 if ((fd = open(path, O_RDONLY)) == -1) {
643 fprintf(stderr, _("%s: cannot open %s: %s\n"),
644 progname, path, strerror(errno));
645 } else {
646 set_extsize(path, fd, extsize);
647 close(fd);
648 }
649 return 0;
650}
651
652static int
653extsize_f(
654 int argc,
655 char **argv)
656{
657 size_t blocksize, sectsize;
658 int c;
659
660 recurse_all = recurse_dir = 0;
661 init_cvtnum(&blocksize, &sectsize);
662 while ((c = getopt(argc, argv, "DR")) != EOF) {
663 switch (c) {
664 case 'D':
665 recurse_all = 0;
666 recurse_dir = 1;
667 break;
668 case 'R':
669 recurse_all = 1;
670 recurse_dir = 0;
671 break;
672 default:
673 return command_usage(&extsize_cmd);
674 }
675 }
676
677 if (optind < argc) {
678 extsize = (long)cvtnum(blocksize, sectsize, argv[optind]);
679 if (extsize < 0) {
680 printf(_("non-numeric extsize argument -- %s\n"),
681 argv[optind]);
682 return 0;
683 }
684 } else {
685 extsize = -1;
686 }
687
688 if (recurse_all || recurse_dir)
689 nftw(file->name, (extsize >= 0) ?
690 set_extsize_callback : get_extsize_callback,
691 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
692 else if (extsize >= 0)
693 set_extsize(file->name, file->fd, extsize);
694 else
695 get_extsize(file->name, file->fd);
696 return 0;
697}
698
e246ba5f
NS
699static int
700statfs_f(
701 int argc,
702 char **argv)
703{
5ecb3de2 704 struct xfs_fsop_counts fscounts;
c0211f67 705 struct xfs_fsop_geom fsgeo;
e246ba5f 706 struct statfs st;
e246ba5f 707
48c46ee3
NS
708 printf(_("fd.path = \"%s\"\n"), file->name);
709 if (platform_fstatfs(file->fd, &st) < 0) {
e246ba5f
NS
710 perror("fstatfs");
711 } else {
712 printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize);
713 printf(_("statfs.f_blocks = %lld\n"), (long long) st.f_blocks);
2c794e6e
NS
714#if defined(__sgi__)
715 printf(_("statfs.f_frsize = %lld\n"), (long long) st.f_frsize);
c0211f67 716#else
e246ba5f 717 printf(_("statfs.f_bavail = %lld\n"), (long long) st.f_bavail);
93d9f139 718#endif
2c794e6e
NS
719 printf(_("statfs.f_files = %lld\n"), (long long) st.f_files);
720 printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree);
e246ba5f 721 }
48c46ee3 722 if (file->flags & IO_FOREIGN)
f72d20ad 723 return 0;
48c46ee3
NS
724 if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
725 perror("XFS_IOC_FSGEOMETRY_V1");
e246ba5f
NS
726 } else {
727 printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
728 printf(_("geom.agcount = %u\n"), fsgeo.agcount);
729 printf(_("geom.agblocks = %u\n"), fsgeo.agblocks);
730 printf(_("geom.datablocks = %llu\n"),
731 (unsigned long long) fsgeo.datablocks);
732 printf(_("geom.rtblocks = %llu\n"),
733 (unsigned long long) fsgeo.rtblocks);
734 printf(_("geom.rtextents = %llu\n"),
735 (unsigned long long) fsgeo.rtextents);
736 printf(_("geom.rtextsize = %u\n"), fsgeo.rtextsize);
737 printf(_("geom.sunit = %u\n"), fsgeo.sunit);
738 printf(_("geom.swidth = %u\n"), fsgeo.swidth);
739 }
5ecb3de2
NS
740 if ((xfsctl(file->name, file->fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
741 perror("XFS_IOC_FSCOUNTS");
742 } else {
743 printf(_("counts.freedata = %llu\n"),
744 (unsigned long long) fscounts.freedata);
745 printf(_("counts.freertx = %llu\n"),
746 (unsigned long long) fscounts.freertx);
747 printf(_("counts.freeino = %llu\n"),
748 (unsigned long long) fscounts.freeino);
749 printf(_("counts.allocino = %llu\n"),
750 (unsigned long long) fscounts.allocino);
751 }
e246ba5f
NS
752 return 0;
753}
754
ef25c9e4
CM
755static void
756inode_help(void)
757{
758 printf(_(
759"\n"
870ecc22 760"Query physical information about an inode"
ef25c9e4 761"\n"
870ecc22
ES
762" Default: -- Return 1 if any inode number greater than 32 bits exists in\n"
763" the filesystem, or 0 if none exist\n"
764" num -- Return inode number [num] if in use, or 0 if not in use\n"
765" -n num -- Return the next used inode after [num]\n"
766" -v -- Verbose mode - display returned inode number's size in bits\n"
ef25c9e4
CM
767"\n"));
768}
769
d0e8bb48
ES
770static __u64
771get_last_inode(void)
772{
773 __u64 lastip = 0;
774 __u64 lastgrp = 0;
775 __s32 ocount = 0;
776 __u64 last_ino;
777 struct xfs_inogrp igroup[1024];
778 struct xfs_fsop_bulkreq bulkreq;
779
780 bulkreq.lastip = &lastip;
781 bulkreq.ubuffer = &igroup;
782 bulkreq.icount = sizeof(igroup) / sizeof(struct xfs_inogrp);
783 bulkreq.ocount = &ocount;
784
785 for (;;) {
786 if (xfsctl(file->name, file->fd, XFS_IOC_FSINUMBERS,
787 &bulkreq)) {
788 perror("XFS_IOC_FSINUMBERS");
789 return 0;
790 }
791
792 /* Did we reach the last inode? */
793 if (ocount == 0)
794 break;
795
796 /* last inode in igroup table */
797 lastgrp = ocount;
798 }
799
800 lastgrp--;
801
802 /* The last inode number in use */
803 last_ino = igroup[lastgrp].xi_startino +
804 libxfs_highbit64(igroup[lastgrp].xi_allocmask);
805
806 return last_ino;
807}
808
ef25c9e4
CM
809static int
810inode_f(
811 int argc,
812 char **argv)
813{
814 __s32 count = 0;
d5b046de 815 __u64 result_ino = 0;
5afa1b2d 816 __u64 userino = NULLFSINO;
ef25c9e4
CM
817 char *p;
818 int c;
819 int verbose = 0;
820 int ret_next = 0;
821 int cmd = 0;
ef25c9e4
CM
822 struct xfs_fsop_bulkreq bulkreq;
823 struct xfs_bstat bstat;
824
825 while ((c = getopt(argc, argv, "nv")) != EOF) {
826 switch (c) {
827 case 'v':
828 verbose = 1;
829 break;
830 case 'n':
831 ret_next = 1;
832 break;
833 default:
834 return command_usage(&inode_cmd);
835 }
836 }
837
5afa1b2d 838 /* Last arg (if present) should be an inode number */
ef25c9e4 839 if (optind < argc) {
ef25c9e4
CM
840 userino = strtoull(argv[optind], &p, 10);
841 if ((*p != '\0')) {
5afa1b2d
ES
842 printf(_("%s is not a numeric inode value\n"),
843 argv[optind]);
ef25c9e4
CM
844 exitcode = 1;
845 return 0;
846 }
5afa1b2d
ES
847 optind++;
848 }
849
850 /* Extra junk? */
851 if (optind < argc)
852 return command_usage(&inode_cmd);
853
854 /* -n option requires an inode number */
855 if (ret_next && userino == NULLFSINO)
856 return command_usage(&inode_cmd);
857
d5b046de
ES
858 if (userino == NULLFSINO) {
859 /* We are finding last inode in use */
860 result_ino = get_last_inode();
861 if (!result_ino) {
862 exitcode = 1;
863 return 0;
864 }
865 } else {
5afa1b2d
ES
866 if (ret_next) /* get next inode */
867 cmd = XFS_IOC_FSBULKSTAT;
868 else /* get this inode */
869 cmd = XFS_IOC_FSBULKSTAT_SINGLE;
ef25c9e4
CM
870
871 bulkreq.lastip = &userino;
872 bulkreq.icount = 1;
873 bulkreq.ubuffer = &bstat;
874 bulkreq.ocount = &count;
875
876 if (xfsctl(file->name, file->fd, cmd, &bulkreq)) {
d5b046de
ES
877 if (!ret_next && errno == EINVAL) {
878 /* Not in use */
879 result_ino = 0;
ef25c9e4
CM
880 } else {
881 perror("xfsctl");
d5b046de
ES
882 exitcode = 1;
883 return 0;
ef25c9e4 884 }
19706950
ES
885 } else if (ret_next) {
886 /* The next inode in use, or 0 if none */
887 if (*bulkreq.ocount)
888 result_ino = bstat.bs_ino;
889 else
890 result_ino = 0;
891 } else {
892 /* The inode we asked about */
d5b046de 893 result_ino = userino;
19706950 894 }
d5b046de
ES
895 }
896
897 if (verbose && result_ino) {
898 /* Requested verbose and we have an answer */
899 printf("%llu:%d\n", result_ino,
900 result_ino > XFS_MAXINUMBER_32 ? 64 : 32);
901 } else if (userino == NULLFSINO) {
902 /* Just checking 32 or 64 bit presence, non-verbose */
903 printf("%d\n", result_ino > XFS_MAXINUMBER_32 ? 1 : 0);
904 } else {
905 /* We asked about a specific inode, non-verbose */
906 printf("%llu\n", result_ino);
ef25c9e4
CM
907 }
908
ef25c9e4
CM
909 return 0;
910}
911
e246ba5f
NS
912void
913open_init(void)
914{
ad765595
AM
915 open_cmd.name = "open";
916 open_cmd.altname = "o";
e246ba5f
NS
917 open_cmd.cfunc = open_f;
918 open_cmd.argmin = 0;
919 open_cmd.argmax = -1;
48c46ee3 920 open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
da2b3c09 921 open_cmd.args = _("[-acdrstxT] [path]");
48c46ee3 922 open_cmd.oneline = _("open the file specified by path");
e246ba5f
NS
923 open_cmd.help = open_help;
924
ad765595 925 stat_cmd.name = "stat";
e246ba5f
NS
926 stat_cmd.cfunc = stat_f;
927 stat_cmd.argmin = 0;
928 stat_cmd.argmax = 1;
48c46ee3 929 stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
e246ba5f 930 stat_cmd.args = _("[-v]");
48c46ee3
NS
931 stat_cmd.oneline = _("statistics on the currently open file");
932
ad765595
AM
933 close_cmd.name = "close";
934 close_cmd.altname = "c";
48c46ee3
NS
935 close_cmd.cfunc = close_f;
936 close_cmd.argmin = 0;
937 close_cmd.argmax = 0;
938 close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
939 close_cmd.oneline = _("close the current open file");
e246ba5f 940
ad765595 941 statfs_cmd.name = "statfs";
e246ba5f 942 statfs_cmd.cfunc = statfs_f;
48c46ee3 943 statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
e246ba5f
NS
944 statfs_cmd.oneline =
945 _("statistics on the filesystem of the currently open file");
946
ad765595 947 chproj_cmd.name = "chproj";
5ecb3de2 948 chproj_cmd.cfunc = chproj_f;
3d93ccb7 949 chproj_cmd.args = _("[-D | -R] projid");
5ecb3de2 950 chproj_cmd.argmin = 1;
3d93ccb7 951 chproj_cmd.argmax = -1;
73b54bb6 952 chproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
5ecb3de2
NS
953 chproj_cmd.oneline =
954 _("change project identifier on the currently open file");
3d93ccb7 955 chproj_cmd.help = chproj_help;
5ecb3de2 956
ad765595 957 lsproj_cmd.name = "lsproj";
5ecb3de2 958 lsproj_cmd.cfunc = lsproj_f;
3d93ccb7 959 lsproj_cmd.args = _("[-D | -R]");
5ecb3de2 960 lsproj_cmd.argmin = 0;
3d93ccb7 961 lsproj_cmd.argmax = -1;
5ecb3de2
NS
962 lsproj_cmd.flags = CMD_NOMAP_OK;
963 lsproj_cmd.oneline =
964 _("list project identifier set on the currently open file");
3d93ccb7 965 lsproj_cmd.help = lsproj_help;
5ecb3de2 966
ad765595 967 extsize_cmd.name = "extsize";
9b5ee343 968 extsize_cmd.cfunc = extsize_f;
0e51fd13
NS
969 extsize_cmd.args = _("[-D | -R] [extsize]");
970 extsize_cmd.argmin = 0;
971 extsize_cmd.argmax = -1;
48c46ee3 972 extsize_cmd.flags = CMD_NOMAP_OK;
9b5ee343 973 extsize_cmd.oneline =
ff1f79a7 974 _("get/set preferred extent size (in bytes) for the open file");
0e51fd13 975 extsize_cmd.help = extsize_help;
9b5ee343 976
ef25c9e4
CM
977 inode_cmd.name = "inode";
978 inode_cmd.cfunc = inode_f;
870ecc22 979 inode_cmd.args = _("[-nv] [num]");
ef25c9e4 980 inode_cmd.argmin = 0;
870ecc22 981 inode_cmd.argmax = 3;
ef25c9e4
CM
982 inode_cmd.flags = CMD_NOMAP_OK;
983 inode_cmd.oneline =
984 _("Query inode number usage in the filesystem");
985 inode_cmd.help = inode_help;
986
e246ba5f
NS
987 add_command(&open_cmd);
988 add_command(&stat_cmd);
48c46ee3 989 add_command(&close_cmd);
e246ba5f 990 add_command(&statfs_cmd);
5ecb3de2
NS
991 add_command(&chproj_cmd);
992 add_command(&lsproj_cmd);
ae541a2b 993 add_command(&extsize_cmd);
ef25c9e4 994 add_command(&inode_cmd);
e246ba5f 995}