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