]>
Commit | Line | Data |
---|---|---|
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 | 41 | static cmdinfo_t open_cmd; |
48c46ee3 | 42 | static cmdinfo_t close_cmd; |
5ecb3de2 NS |
43 | static cmdinfo_t chproj_cmd; |
44 | static cmdinfo_t lsproj_cmd; | |
9b5ee343 | 45 | static cmdinfo_t extsize_cmd; |
ef25c9e4 | 46 | static cmdinfo_t inode_cmd; |
3d93ccb7 | 47 | static prid_t prid; |
0e51fd13 | 48 | static long extsize; |
48c46ee3 | 49 | |
e246ba5f NS |
50 | int |
51 | openfile( | |
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 |
141 | int |
142 | addfile( | |
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 | ||
179 | static void | |
180 | open_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 | ||
210 | static int | |
211 | open_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 |
305 | static int |
306 | close_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 |
341 | static void |
342 | lsproj_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 | ||
354 | static int | |
355 | lsproj_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 |
378 | static int |
379 | lsproj_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 | ||
415 | static void | |
416 | chproj_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 | ||
427 | static int | |
428 | chproj_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 | ||
450 | static int | |
451 | chproj_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 |
490 | static void |
491 | extsize_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 | ||
502 | static int | |
503 | get_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 | ||
516 | static int | |
517 | set_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 | ||
551 | static int | |
552 | get_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 | ||
573 | static int | |
574 | set_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 | ||
595 | static int | |
596 | extsize_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, §size); | |
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 |
642 | static void |
643 | inode_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 |
657 | static __u64 |
658 | get_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 |
696 | static int |
697 | inode_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 |
799 | void |
800 | open_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 | } |