]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/open.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
12 #include "libfrog/fsgeom.h"
13 #include "libfrog/bulkstat.h"
17 #define __O_TMPFILE 0100000000
18 #elif defined(__hppa__)
19 #define __O_TMPFILE 040000000
20 #elif defined(__sparc__)
21 #define __O_TMPFILE 0x2000000
23 #define __O_TMPFILE 020000000
25 #endif /* __O_TMPFILE */
28 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
33 #define O_PATH 040000000
34 #elif defined(__hppa__)
35 #define O_PATH 020000000
36 #elif defined(__sparc__)
37 #define O_PATH 0x1000000
39 #define O_PATH 010000000
43 static cmdinfo_t open_cmd
;
44 static cmdinfo_t close_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 cmdinfo_t chmod_cmd
;
56 struct xfs_fsop_geom
*geom
,
59 struct fs_path
*fs_path
)
62 struct stat st
= { 0 };
66 oflags
= flags
& IO_READONLY
? O_RDONLY
: O_RDWR
;
67 if (flags
& IO_APPEND
)
71 if (flags
& IO_DIRECT
)
77 if (flags
& IO_NONBLOCK
)
79 if (flags
& IO_TMPFILE
)
83 if (flags
& IO_NOFOLLOW
)
87 * if we've been passed a pipe to open, don't block waiting for a
88 * reader or writer to appear. We want to either succeed or error out
91 if (stat(path
, &st
) < 0 && errno
!= ENOENT
) {
95 if (S_ISFIFO(st
.st_mode
))
98 fd
= open(path
, oflags
, mode
);
100 if (errno
== EISDIR
&&
101 ((oflags
& (O_RDWR
|O_TMPFILE
)) == O_RDWR
)) {
102 /* make it as if we asked for O_RDONLY & try again */
105 flags
|= IO_READONLY
;
106 fd
= open(path
, oflags
, mode
);
117 if (!geom
|| !platform_test_xfs_fd(fd
))
120 if (flags
& IO_PATH
) {
121 /* Can't call ioctl() on O_PATH fds */
122 memset(geom
, 0, sizeof(*geom
));
126 ret
= xfrog_geometry(fd
, geom
);
129 perror("XFS_IOC_FSGEOMETRY");
135 if (!(flags
& (IO_READONLY
| IO_PATH
)) && (flags
& IO_REALTIME
)) {
138 if (xfsctl(path
, fd
, FS_IOC_FSGETXATTR
, &attr
) < 0) {
139 perror("FS_IOC_FSGETXATTR");
143 if (!(attr
.fsx_xflags
& FS_XFLAG_REALTIME
)) {
144 attr
.fsx_xflags
|= FS_XFLAG_REALTIME
;
145 if (xfsctl(path
, fd
, FS_IOC_FSSETXATTR
, &attr
) < 0) {
146 perror("FS_IOC_FSSETXATTR");
154 fsp
= fs_table_lookup(path
, FS_MOUNT_POINT
);
156 memset(fs_path
, 0, sizeof(*fs_path
));
167 struct xfs_fsop_geom
*geometry
,
169 struct fs_path
*fs_path
)
173 filename
= strdup(name
);
180 /* Extend the table of currently open files */
181 filetable
= (fileio_t
*)realloc(filetable
, /* growing */
182 ++filecount
* sizeof(fileio_t
));
191 /* Finally, make this the new active open file */
192 file
= &filetable
[filecount
- 1];
195 file
->name
= filename
;
196 file
->geom
= *geometry
;
197 file
->fs_path
= *fs_path
;
206 " opens a new file in the requested mode\n"
209 " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
211 " Opens a file for subsequent use by all of the other xfs_io commands.\n"
212 " With no arguments, open uses the stat command to show the current file.\n"
213 " -a -- open with the O_APPEND flag (append-only mode)\n"
214 " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
215 " -f -- open with O_CREAT (create the file if it doesn't exist)\n"
216 " -m -- permissions to use in case a new file is created (default 0600)\n"
217 " -n -- open with O_NONBLOCK\n"
218 " -r -- open with O_RDONLY, the default is O_RDWR\n"
219 " -s -- open with O_SYNC\n"
220 " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
221 " -R -- mark the file as a realtime XFS file immediately after opening it\n"
222 " -T -- open with O_TMPFILE (create a file not visible in the namespace)\n"
223 " -P -- open with O_PATH (create an fd that is merely a location reference)\n"
224 " -L -- open with O_NOFOLLOW (don't follow symlink)\n"
225 " Note1: usually read/write direct IO requests must be blocksize aligned;\n"
226 " some kernels, however, allow sectorsize alignment for direct IO.\n"
227 " Note2: the bmap for non-regular files can be obtained provided the file\n"
228 " was opened correctly (in particular, must be opened read-only).\n"
237 int c
, fd
, flags
= 0;
240 struct xfs_fsop_geom geometry
= { 0 };
245 return stat_f(argc
, argv
);
246 fprintf(stderr
, _("no files are open, try 'help open'\n"));
250 while ((c
= getopt(argc
, argv
, "FLPRTacdfm:nrstx")) != EOF
) {
253 /* Ignored / deprecated now, handled automatically */
266 mode
= strtoul(optarg
, &sp
, 0);
267 if (!sp
|| sp
== optarg
) {
268 printf(_("non-numeric mode -- %s\n"), optarg
);
273 flags
|= IO_NONBLOCK
;
276 flags
|= IO_READONLY
;
285 case 'x': /* backwards compatibility */
286 flags
|= IO_REALTIME
;
295 flags
|= IO_NOFOLLOW
;
298 return command_usage(&open_cmd
);
302 if (optind
!= argc
- 1)
303 return command_usage(&open_cmd
);
305 if ((flags
& (IO_READONLY
|IO_TMPFILE
)) == (IO_READONLY
|IO_TMPFILE
)) {
306 fprintf(stderr
, _("-T and -r options are incompatible\n"));
310 if ((flags
& (IO_PATH
|IO_NOFOLLOW
)) &&
311 (flags
& ~(IO_PATH
|IO_NOFOLLOW
))) {
312 fprintf(stderr
, _("-P and -L are incompatible with the other options\n"));
316 fd
= openfile(argv
[optind
], &geometry
, flags
, mode
, &fsp
);
320 if (!platform_test_xfs_fd(fd
))
323 addfile(argv
[optind
], fd
, &geometry
, flags
, &fsp
);
335 if (close(file
->fd
) < 0) {
341 /* Shuffle the file table entries down over the removed entry */
342 offset
= file
- &filetable
[0];
343 length
= filecount
* sizeof(fileio_t
);
344 length
-= (offset
+ 1) * sizeof(fileio_t
);
346 memmove(file
, file
+ 1, length
);
348 /* Resize the memory allocated for the table, possibly freeing */
350 filetable
= (fileio_t
*)realloc(filetable
, /* shrinking */
351 filecount
* sizeof(fileio_t
));
352 if (offset
== filecount
)
354 file
= filetable
+ offset
;
357 file
= filetable
= NULL
;
368 " displays the project identifier associated with the current path\n"
371 " -R -- recursively descend (useful when current path is a directory)\n"
372 " -D -- recursively descend, but only list projects on directories\n"
379 const struct stat
*stat
,
386 if (recurse_dir
&& !S_ISDIR(stat
->st_mode
))
389 if ((fd
= open(path
, O_RDONLY
)) == -1) {
390 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
391 progname
, path
, strerror(errno
));
393 if (getprojid(path
, fd
, &projid
) == 0)
394 printf("[%u] %s\n", (unsigned int)projid
, path
);
408 recurse_all
= recurse_dir
= 0;
409 while ((c
= getopt(argc
, argv
, "DR")) != EOF
) {
420 return command_usage(&lsproj_cmd
);
425 return command_usage(&lsproj_cmd
);
427 if (recurse_all
|| recurse_dir
)
428 nftw(file
->name
, lsproj_callback
,
429 100, FTW_PHYS
| FTW_MOUNT
| FTW_DEPTH
);
430 else if (getprojid(file
->name
, file
->fd
, &projid
) < 0)
433 printf(_("projid = %u\n"), (unsigned int)projid
);
442 " modifies the project identifier associated with the current path\n"
444 " -R -- recursively descend (useful when current path is a directory)\n"
445 " -D -- recursively descend, only modifying projects on directories\n"
452 const struct stat
*stat
,
458 if (recurse_dir
&& !S_ISDIR(stat
->st_mode
))
461 if ((fd
= open(path
, O_RDONLY
)) == -1) {
462 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
463 progname
, path
, strerror(errno
));
465 if (setprojid(path
, fd
, prid
) < 0)
479 recurse_all
= recurse_dir
= 0;
480 while ((c
= getopt(argc
, argv
, "DR")) != EOF
) {
491 return command_usage(&chproj_cmd
);
495 if (argc
!= optind
+ 1)
496 return command_usage(&chproj_cmd
);
498 prid
= prid_from_string(argv
[optind
]);
500 printf(_("invalid project ID -- %s\n"), argv
[optind
]);
504 if (recurse_all
|| recurse_dir
)
505 nftw(file
->name
, chproj_callback
,
506 100, FTW_PHYS
| FTW_MOUNT
| FTW_DEPTH
);
507 else if (setprojid(file
->name
, file
->fd
, prid
) < 0)
517 " report or modify preferred extent size (in bytes) for the current path\n"
519 " -R -- recursively descend (useful when current path is a directory)\n"
520 " -D -- recursively descend, only modifying extsize on directories\n"
525 get_extsize(const char *path
, int fd
)
529 if ((xfsctl(path
, fd
, FS_IOC_FSGETXATTR
, &fsx
)) < 0) {
530 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
531 progname
, path
, strerror(errno
));
534 printf("[%u] %s\n", fsx
.fsx_extsize
, path
);
539 set_extsize(const char *path
, int fd
, long extsz
)
544 if (fstat(fd
, &stat
) < 0) {
548 if ((xfsctl(path
, fd
, FS_IOC_FSGETXATTR
, &fsx
)) < 0) {
549 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
550 progname
, path
, strerror(errno
));
554 if (S_ISREG(stat
.st_mode
)) {
555 fsx
.fsx_xflags
|= FS_XFLAG_EXTSIZE
;
556 } else if (S_ISDIR(stat
.st_mode
)) {
557 fsx
.fsx_xflags
|= FS_XFLAG_EXTSZINHERIT
;
559 printf(_("invalid target file type - file %s\n"), path
);
562 fsx
.fsx_extsize
= extsz
;
564 if ((xfsctl(path
, fd
, FS_IOC_FSSETXATTR
, &fsx
)) < 0) {
565 printf("%s: FS_IOC_FSSETXATTR %s: %s\n",
566 progname
, path
, strerror(errno
));
574 get_extsize_callback(
576 const struct stat
*stat
,
582 if (recurse_dir
&& !S_ISDIR(stat
->st_mode
))
585 if ((fd
= open(path
, O_RDONLY
)) == -1) {
586 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
587 progname
, path
, strerror(errno
));
589 get_extsize(path
, fd
);
596 set_extsize_callback(
598 const struct stat
*stat
,
604 if (recurse_dir
&& !S_ISDIR(stat
->st_mode
))
607 if ((fd
= open(path
, O_RDONLY
)) == -1) {
608 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
609 progname
, path
, strerror(errno
));
611 set_extsize(path
, fd
, extsize
);
622 size_t blocksize
, sectsize
;
625 recurse_all
= recurse_dir
= 0;
626 init_cvtnum(&blocksize
, §size
);
627 while ((c
= getopt(argc
, argv
, "DR")) != EOF
) {
638 return command_usage(&extsize_cmd
);
643 extsize
= (long)cvtnum(blocksize
, sectsize
, argv
[optind
]);
645 printf(_("non-numeric extsize argument -- %s\n"),
653 if (recurse_all
|| recurse_dir
)
654 nftw(file
->name
, (extsize
>= 0) ?
655 set_extsize_callback
: get_extsize_callback
,
656 100, FTW_PHYS
| FTW_MOUNT
| FTW_DEPTH
);
657 else if (extsize
>= 0)
658 set_extsize(file
->name
, file
->fd
, extsize
);
660 get_extsize(file
->name
, file
->fd
);
669 "Query physical information about an inode"
671 " Default: -- Return 1 if any inode number greater than 32 bits exists in\n"
672 " the filesystem, or 0 if none exist\n"
673 " num -- Return inode number [num] if in use, or 0 if not in use\n"
674 " -n num -- Return the next used inode after [num]\n"
675 " -v -- Verbose mode - display returned inode number's size in bits\n"
679 #define IGROUP_NR (1024)
683 struct xfs_fd xfd
= XFS_FD_INIT(file
->fd
);
685 uint32_t lastgrp
= 0;
688 struct xfs_inogrp igroup
[IGROUP_NR
];
693 ret
= xfrog_inumbers(&xfd
, &lastip
, IGROUP_NR
, igroup
,
697 perror("XFS_IOC_FSINUMBERS");
701 /* Did we reach the last inode? */
705 /* last inode in igroup table */
714 /* The last inode number in use */
715 last_ino
= igroup
[lastgrp
].xi_startino
+
716 libxfs_highbit64(igroup
[lastgrp
].xi_allocmask
);
726 struct xfs_bstat bstat
;
728 uint64_t result_ino
= 0;
729 uint64_t userino
= NULLFSINO
;
736 while ((c
= getopt(argc
, argv
, "nv")) != EOF
) {
745 return command_usage(&inode_cmd
);
749 /* Last arg (if present) should be an inode number */
751 userino
= strtoull(argv
[optind
], &p
, 10);
753 printf(_("%s is not a numeric inode value\n"),
763 return command_usage(&inode_cmd
);
765 /* -n option requires an inode number */
766 if (ret_next
&& userino
== NULLFSINO
)
767 return command_usage(&inode_cmd
);
769 if (userino
== NULLFSINO
) {
770 /* We are finding last inode in use */
771 result_ino
= get_last_inode();
776 } else if (ret_next
) {
777 struct xfs_fd xfd
= XFS_FD_INIT(file
->fd
);
780 ret
= xfrog_bulkstat(&xfd
, &userino
, 1, &bstat
, &count
);
788 /* The next inode in use, or 0 if none */
790 result_ino
= bstat
.bs_ino
;
794 struct xfs_fd xfd
= XFS_FD_INIT(file
->fd
);
797 ret
= xfrog_bulkstat_single(&xfd
, userino
, &bstat
);
803 perror("bulkstat_single");
807 result_ino
= bstat
.bs_ino
;
811 if (verbose
&& result_ino
) {
812 /* Requested verbose and we have an answer */
813 printf("%llu:%d\n", (unsigned long long)result_ino
,
814 result_ino
> XFS_MAXINUMBER_32
? 64 : 32);
815 } else if (userino
== NULLFSINO
) {
816 /* Just checking 32 or 64 bit presence, non-verbose */
817 printf("%d\n", result_ino
> XFS_MAXINUMBER_32
? 1 : 0);
819 /* We asked about a specific inode, non-verbose */
820 printf("%llu\n", (unsigned long long)result_ino
);
831 " Change the read/write permissions on the current file\n"
834 " -r -- make the file read only (0444 permissions)\n"
835 " -w -- make the file read/write (0664 permissions)\n"
844 mode_t mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
847 while ((c
= getopt(argc
, argv
, "rw")) != EOF
) {
852 mode
|= S_IWUSR
| S_IWGRP
;
855 return command_usage(&chmod_cmd
);
860 return command_usage(&chmod_cmd
);
862 if (fchmod(file
->fd
, mode
) < 0) {
871 open_cmd
.name
= "open";
872 open_cmd
.altname
= "o";
873 open_cmd
.cfunc
= open_f
;
875 open_cmd
.argmax
= -1;
876 open_cmd
.flags
= CMD_NOMAP_OK
| CMD_NOFILE_OK
|
877 CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
878 open_cmd
.args
= _("[-acdrstxRTPL] [-m mode] [path]");
879 open_cmd
.oneline
= _("open the file specified by path");
880 open_cmd
.help
= open_help
;
882 close_cmd
.name
= "close";
883 close_cmd
.altname
= "c";
884 close_cmd
.cfunc
= close_f
;
885 close_cmd
.argmin
= 0;
886 close_cmd
.argmax
= 0;
887 close_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
888 close_cmd
.oneline
= _("close the current open file");
890 chproj_cmd
.name
= "chproj";
891 chproj_cmd
.cfunc
= chproj_f
;
892 chproj_cmd
.args
= _("[-D | -R] projid");
893 chproj_cmd
.argmin
= 1;
894 chproj_cmd
.argmax
= -1;
895 chproj_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
;
897 _("change project identifier on the currently open file");
898 chproj_cmd
.help
= chproj_help
;
900 lsproj_cmd
.name
= "lsproj";
901 lsproj_cmd
.cfunc
= lsproj_f
;
902 lsproj_cmd
.args
= _("[-D | -R]");
903 lsproj_cmd
.argmin
= 0;
904 lsproj_cmd
.argmax
= -1;
905 lsproj_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
;
907 _("list project identifier set on the currently open file");
908 lsproj_cmd
.help
= lsproj_help
;
910 extsize_cmd
.name
= "extsize";
911 extsize_cmd
.cfunc
= extsize_f
;
912 extsize_cmd
.args
= _("[-D | -R] [extsize]");
913 extsize_cmd
.argmin
= 0;
914 extsize_cmd
.argmax
= -1;
915 extsize_cmd
.flags
= CMD_NOMAP_OK
;
916 extsize_cmd
.oneline
=
917 _("get/set preferred extent size (in bytes) for the open file");
918 extsize_cmd
.help
= extsize_help
;
920 inode_cmd
.name
= "inode";
921 inode_cmd
.cfunc
= inode_f
;
922 inode_cmd
.args
= _("[-nv] [num]");
923 inode_cmd
.argmin
= 0;
924 inode_cmd
.argmax
= 3;
925 inode_cmd
.flags
= CMD_NOMAP_OK
| CMD_FLAG_ONESHOT
;
927 _("Query inode number usage in the filesystem");
928 inode_cmd
.help
= inode_help
;
930 chmod_cmd
.name
= "chmod";
931 chmod_cmd
.cfunc
= chmod_f
;
932 chmod_cmd
.args
= _("-r | -w");
933 chmod_cmd
.argmin
= 1;
934 chmod_cmd
.argmax
= 1;
935 chmod_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
937 _("change the read/write permissions on the currently open file");
938 chmod_cmd
.help
= chmod_help
;
940 add_command(&open_cmd
);
941 add_command(&close_cmd
);
942 add_command(&chproj_cmd
);
943 add_command(&lsproj_cmd
);
944 add_command(&extsize_cmd
);
945 add_command(&inode_cmd
);
946 add_command(&chmod_cmd
);