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