]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/open.c
xfs_io: fix inode command help and argsmax
[thirdparty/xfsprogs-dev.git] / io / open.c
1 /*
2 * Copyright (c) 2003-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 "command.h"
20 #include "input.h"
21 #include "init.h"
22 #include "io.h"
23 #include "libxfs.h"
24
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
41 static cmdinfo_t open_cmd;
42 static cmdinfo_t stat_cmd;
43 static cmdinfo_t close_cmd;
44 static cmdinfo_t statfs_cmd;
45 static cmdinfo_t chproj_cmd;
46 static cmdinfo_t lsproj_cmd;
47 static cmdinfo_t extsize_cmd;
48 static cmdinfo_t inode_cmd;
49 static prid_t prid;
50 static long extsize;
51
52 off64_t
53 filesize(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
64 static char *
65 filetype(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
86 static int
87 stat_f(
88 int argc,
89 char **argv)
90 {
91 struct dioattr dio;
92 struct fsxattr fsx, fsxa;
93 struct stat64 st;
94 int verbose = (argc == 2 && !strcmp(argv[1], "-v"));
95
96 printf(_("fd.path = \"%s\"\n"), file->name);
97 printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"),
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") : "",
102 file->flags & IO_APPEND ? _(",append-only") : "",
103 file->flags & IO_NONBLOCK ? _(",non-block") : "",
104 file->flags & IO_TMPFILE ? _(",tmpfile") : "");
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;
120 if ((xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0 ||
121 (xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTRA, &fsxa)) < 0) {
122 perror("FS_IOC_FSGETXATTR");
123 } else {
124 printf(_("fsxattr.xflags = 0x%x "), fsx.fsx_xflags);
125 printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1);
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);
137 }
138 return 0;
139 }
140
141 int
142 openfile(
143 char *path,
144 xfs_fsop_geom_t *geom,
145 int flags,
146 mode_t mode)
147 {
148 int fd;
149 int oflags;
150
151 oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
152 if (flags & IO_APPEND)
153 oflags |= O_APPEND;
154 if (flags & IO_CREAT)
155 oflags |= O_CREAT;
156 if (flags & IO_DIRECT)
157 oflags |= O_DIRECT;
158 if (flags & IO_OSYNC)
159 oflags |= O_SYNC;
160 if (flags & IO_TRUNC)
161 oflags |= O_TRUNC;
162 if (flags & IO_NONBLOCK)
163 oflags |= O_NONBLOCK;
164 if (flags & IO_TMPFILE)
165 oflags |= O_TMPFILE;
166
167 fd = open(path, oflags, mode);
168 if (fd < 0) {
169 if (errno == EISDIR &&
170 ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) {
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 }
184 }
185
186 if (!geom || !platform_test_xfs_fd(fd))
187 return fd;
188
189 if (xfsctl(path, fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
190 perror("XFS_IOC_FSGEOMETRY");
191 close(fd);
192 return -1;
193 }
194
195 if (!(flags & IO_READONLY) && (flags & IO_REALTIME)) {
196 struct fsxattr attr;
197
198 if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &attr) < 0) {
199 perror("FS_IOC_FSGETXATTR");
200 close(fd);
201 return -1;
202 }
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");
207 close(fd);
208 return -1;
209 }
210 }
211 }
212 return fd;
213 }
214
215 int
216 addfile(
217 char *name,
218 int fd,
219 xfs_fsop_geom_t *geometry,
220 int flags)
221 {
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;
248 return 0;
249 }
250
251 static void
252 open_help(void)
253 {
254 printf(_(
255 "\n"
256 " opens a new file in the requested mode\n"
257 "\n"
258 " Example:\n"
259 " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
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"
264 " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
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"
267 " -n -- open with O_NONBLOCK\n"
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"
271 " -R -- mark the file as a realtime XFS file immediately after opening it\n"
272 " -T -- open with O_TMPFILE (create a file not visible in the namespace)\n"
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"
276 " was opened correctly (in particular, must be opened read-only).\n"
277 "\n"));
278 }
279
280 static int
281 open_f(
282 int argc,
283 char **argv)
284 {
285 int c, fd, flags = 0;
286 char *sp;
287 mode_t mode = 0600;
288 xfs_fsop_geom_t geometry = { 0 };
289
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 }
296
297 while ((c = getopt(argc, argv, "FRTacdfm:nrstx")) != EOF) {
298 switch (c) {
299 case 'F':
300 /* Ignored / deprecated now, handled automatically */
301 break;
302 case 'a':
303 flags |= IO_APPEND;
304 break;
305 case 'c':
306 case 'f':
307 flags |= IO_CREAT;
308 break;
309 case 'd':
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 }
318 break;
319 case 'n':
320 flags |= IO_NONBLOCK;
321 break;
322 case 'r':
323 flags |= IO_READONLY;
324 break;
325 case 's':
326 flags |= IO_OSYNC;
327 break;
328 case 't':
329 flags |= IO_TRUNC;
330 break;
331 case 'R':
332 case 'x': /* backwards compatibility */
333 flags |= IO_REALTIME;
334 break;
335 case 'T':
336 flags |= IO_TMPFILE;
337 break;
338 default:
339 return command_usage(&open_cmd);
340 }
341 }
342
343 if (optind != argc - 1)
344 return command_usage(&open_cmd);
345
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
351 fd = openfile(argv[optind], &geometry, flags, mode);
352 if (fd < 0)
353 return 0;
354
355 if (!platform_test_xfs_fd(fd))
356 flags |= IO_FOREIGN;
357
358 addfile(argv[optind], fd, &geometry, flags);
359 return 0;
360 }
361
362 static int
363 close_f(
364 int argc,
365 char **argv)
366 {
367 size_t length;
368 unsigned int offset;
369
370 if (close(file->fd) < 0) {
371 perror("close");
372 return 0;
373 }
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;
393 }
394 filelist_f();
395 return 0;
396 }
397
398 static void
399 lsproj_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
411 static int
412 lsproj_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)
429 printf("[%u] %s\n", (unsigned int)projid, path);
430 close(fd);
431 }
432 return 0;
433 }
434
435 static int
436 lsproj_f(
437 int argc,
438 char **argv)
439 {
440 prid_t projid;
441 int c;
442
443 recurse_all = recurse_dir = 0;
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
468 printf(_("projid = %u\n"), (unsigned int)projid);
469 return 0;
470 }
471
472 static void
473 chproj_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
484 static int
485 chproj_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))
494 return 0;
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);
503 }
504 return 0;
505 }
506
507 static int
508 chproj_f(
509 int argc,
510 char **argv)
511 {
512 int c;
513
514 recurse_all = recurse_dir = 0;
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]);
536 return 0;
537 }
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");
544 return 0;
545 }
546
547 static void
548 extsize_help(void)
549 {
550 printf(_(
551 "\n"
552 " report or modify preferred extent size (in bytes) for the current path\n"
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
559 static int
560 get_extsize(const char *path, int fd)
561 {
562 struct fsxattr fsx;
563
564 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
565 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
566 progname, path, strerror(errno));
567 return 0;
568 }
569 printf("[%u] %s\n", fsx.fsx_extsize, path);
570 return 0;
571 }
572
573 static int
574 set_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 }
583 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
584 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
585 progname, path, strerror(errno));
586 return 0;
587 }
588
589 if (S_ISREG(stat.st_mode)) {
590 fsx.fsx_xflags |= FS_XFLAG_EXTSIZE;
591 } else if (S_ISDIR(stat.st_mode)) {
592 fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT;
593 } else {
594 printf(_("invalid target file type - file %s\n"), path);
595 return 0;
596 }
597 fsx.fsx_extsize = extsz;
598
599 if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) {
600 printf("%s: FS_IOC_FSSETXATTR %s: %s\n",
601 progname, path, strerror(errno));
602 return 0;
603 }
604
605 return 0;
606 }
607
608 static int
609 get_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
630 static int
631 set_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
652 static int
653 extsize_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
699 static int
700 statfs_f(
701 int argc,
702 char **argv)
703 {
704 struct xfs_fsop_counts fscounts;
705 struct xfs_fsop_geom fsgeo;
706 struct statfs st;
707
708 printf(_("fd.path = \"%s\"\n"), file->name);
709 if (platform_fstatfs(file->fd, &st) < 0) {
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);
714 #if defined(__sgi__)
715 printf(_("statfs.f_frsize = %lld\n"), (long long) st.f_frsize);
716 #else
717 printf(_("statfs.f_bavail = %lld\n"), (long long) st.f_bavail);
718 #endif
719 printf(_("statfs.f_files = %lld\n"), (long long) st.f_files);
720 printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree);
721 }
722 if (file->flags & IO_FOREIGN)
723 return 0;
724 if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
725 perror("XFS_IOC_FSGEOMETRY_V1");
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 }
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 }
752 return 0;
753 }
754
755 static void
756 inode_help(void)
757 {
758 printf(_(
759 "\n"
760 "Query physical information about an inode"
761 "\n"
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"
767 "\n"));
768 }
769
770 static int
771 inode_f(
772 int argc,
773 char **argv)
774 {
775 __s32 count = 0;
776 __s32 lastgrp = 0;
777 __u64 last = 0;
778 __u64 lastino = 0;
779 __u64 userino = 0;
780 char *p;
781 int c;
782 int verbose = 0;
783 int ret_next = 0;
784 int cmd = 0;
785 struct xfs_inogrp igroup[1024];
786 struct xfs_fsop_bulkreq bulkreq;
787 struct xfs_bstat bstat;
788
789 while ((c = getopt(argc, argv, "nv")) != EOF) {
790 switch (c) {
791 case 'v':
792 verbose = 1;
793 break;
794 case 'n':
795 ret_next = 1;
796 break;
797 default:
798 return command_usage(&inode_cmd);
799 }
800 }
801
802 /*
803 * Inode number can be passed with or without extra arguments, so we
804 * should handle inode numbers passed by user out of getopt()
805 */
806 if (optind < argc) {
807
808 if (ret_next) {
809 cmd = XFS_IOC_FSBULKSTAT;
810 } else {
811 if ((argc > 2) && !verbose)
812 return command_usage(&inode_cmd);
813 else
814 cmd = XFS_IOC_FSBULKSTAT_SINGLE;
815 }
816
817 userino = strtoull(argv[optind], &p, 10);
818 if ((*p != '\0')) {
819 printf(_("[num] must be a numeric value\n"));
820 exitcode = 1;
821 return 0;
822 }
823
824 bulkreq.lastip = &userino;
825 bulkreq.icount = 1;
826 bulkreq.ubuffer = &bstat;
827 bulkreq.ocount = &count;
828
829 if (xfsctl(file->name, file->fd, cmd, &bulkreq)) {
830 if (errno == EINVAL) {
831 if (!ret_next)
832 printf("0\n");
833 } else {
834 perror("xfsctl");
835 }
836 exitcode = 1;
837 return 0;
838 }
839
840 if (ret_next)
841 userino = bstat.bs_ino;
842
843 if (verbose)
844 printf("%llu:%d\n",
845 userino,
846 userino > XFS_MAXINUMBER_32 ? 64 : 32);
847 else
848 /* Inode in use */
849 printf("%llu\n", userino);
850 return 0;
851
852 /* -n option must not be used stand alone */
853 } else if (ret_next) {
854 return command_usage(&inode_cmd);
855 }
856
857 bulkreq.lastip = &last;
858 bulkreq.icount = 1024; /* User-defined maybe!? */
859 bulkreq.ubuffer = &igroup;
860 bulkreq.ocount = &count;
861
862 for (;;) {
863 if (xfsctl(file->name, file->fd, XFS_IOC_FSINUMBERS,
864 &bulkreq)) {
865 perror("XFS_IOC_FSINUMBERS");
866 exitcode = 1;
867 return 0;
868 }
869
870 if (count == 0)
871 break;
872
873 lastgrp = count;
874 }
875
876 lastgrp--;
877 lastino = igroup[lastgrp].xi_startino +
878 libxfs_highbit64(igroup[lastgrp].xi_allocmask);
879
880 if (verbose)
881 printf("%llu:%d\n", lastino,
882 lastino > XFS_MAXINUMBER_32 ? 64 : 32);
883 else
884 printf("%d\n", lastino > XFS_MAXINUMBER_32 ? 1 : 0);
885
886 return 0;
887 }
888
889 void
890 open_init(void)
891 {
892 open_cmd.name = "open";
893 open_cmd.altname = "o";
894 open_cmd.cfunc = open_f;
895 open_cmd.argmin = 0;
896 open_cmd.argmax = -1;
897 open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
898 open_cmd.args = _("[-acdrstxT] [path]");
899 open_cmd.oneline = _("open the file specified by path");
900 open_cmd.help = open_help;
901
902 stat_cmd.name = "stat";
903 stat_cmd.cfunc = stat_f;
904 stat_cmd.argmin = 0;
905 stat_cmd.argmax = 1;
906 stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
907 stat_cmd.args = _("[-v]");
908 stat_cmd.oneline = _("statistics on the currently open file");
909
910 close_cmd.name = "close";
911 close_cmd.altname = "c";
912 close_cmd.cfunc = close_f;
913 close_cmd.argmin = 0;
914 close_cmd.argmax = 0;
915 close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
916 close_cmd.oneline = _("close the current open file");
917
918 statfs_cmd.name = "statfs";
919 statfs_cmd.cfunc = statfs_f;
920 statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
921 statfs_cmd.oneline =
922 _("statistics on the filesystem of the currently open file");
923
924 chproj_cmd.name = "chproj";
925 chproj_cmd.cfunc = chproj_f;
926 chproj_cmd.args = _("[-D | -R] projid");
927 chproj_cmd.argmin = 1;
928 chproj_cmd.argmax = -1;
929 chproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
930 chproj_cmd.oneline =
931 _("change project identifier on the currently open file");
932 chproj_cmd.help = chproj_help;
933
934 lsproj_cmd.name = "lsproj";
935 lsproj_cmd.cfunc = lsproj_f;
936 lsproj_cmd.args = _("[-D | -R]");
937 lsproj_cmd.argmin = 0;
938 lsproj_cmd.argmax = -1;
939 lsproj_cmd.flags = CMD_NOMAP_OK;
940 lsproj_cmd.oneline =
941 _("list project identifier set on the currently open file");
942 lsproj_cmd.help = lsproj_help;
943
944 extsize_cmd.name = "extsize";
945 extsize_cmd.cfunc = extsize_f;
946 extsize_cmd.args = _("[-D | -R] [extsize]");
947 extsize_cmd.argmin = 0;
948 extsize_cmd.argmax = -1;
949 extsize_cmd.flags = CMD_NOMAP_OK;
950 extsize_cmd.oneline =
951 _("get/set preferred extent size (in bytes) for the open file");
952 extsize_cmd.help = extsize_help;
953
954 inode_cmd.name = "inode";
955 inode_cmd.cfunc = inode_f;
956 inode_cmd.args = _("[-nv] [num]");
957 inode_cmd.argmin = 0;
958 inode_cmd.argmax = 3;
959 inode_cmd.flags = CMD_NOMAP_OK;
960 inode_cmd.oneline =
961 _("Query inode number usage in the filesystem");
962 inode_cmd.help = inode_help;
963
964 add_command(&open_cmd);
965 add_command(&stat_cmd);
966 add_command(&close_cmd);
967 add_command(&statfs_cmd);
968 add_command(&chproj_cmd);
969 add_command(&lsproj_cmd);
970 add_command(&extsize_cmd);
971 add_command(&inode_cmd);
972 }