]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/open.c
a5192e87288f45e389e7fdf4706e3263c84f6369
[thirdparty/xfsprogs-dev.git] / io / open.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "command.h"
8 #include "input.h"
9 #include "init.h"
10 #include "io.h"
11 #include "libxfs.h"
12 #include "libfrog/logging.h"
13 #include "libfrog/fsgeom.h"
14 #include "libfrog/bulkstat.h"
15
16 #ifndef __O_TMPFILE
17 #if defined __alpha__
18 #define __O_TMPFILE 0100000000
19 #elif defined(__hppa__)
20 #define __O_TMPFILE 040000000
21 #elif defined(__sparc__)
22 #define __O_TMPFILE 0x2000000
23 #else
24 #define __O_TMPFILE 020000000
25 #endif
26 #endif /* __O_TMPFILE */
27
28 #ifndef O_TMPFILE
29 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
30 #endif
31
32 #ifndef O_PATH
33 #if defined __alpha__
34 #define O_PATH 040000000
35 #elif defined(__hppa__)
36 #define O_PATH 020000000
37 #elif defined(__sparc__)
38 #define O_PATH 0x1000000
39 #else
40 #define O_PATH 010000000
41 #endif
42 #endif /* O_PATH */
43
44 static cmdinfo_t open_cmd;
45 static cmdinfo_t close_cmd;
46 static cmdinfo_t chproj_cmd;
47 static cmdinfo_t lsproj_cmd;
48 static cmdinfo_t extsize_cmd;
49 static cmdinfo_t inode_cmd;
50 static cmdinfo_t chmod_cmd;
51 static prid_t prid;
52 static long extsize;
53
54 int
55 openfile(
56 char *path,
57 struct xfs_fsop_geom *geom,
58 int flags,
59 mode_t mode,
60 struct fs_path *fs_path)
61 {
62 struct fs_path *fsp;
63 struct stat st = { 0 };
64 int fd;
65 int oflags;
66
67 oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
68 if (flags & IO_APPEND)
69 oflags |= O_APPEND;
70 if (flags & IO_CREAT)
71 oflags |= O_CREAT;
72 if (flags & IO_DIRECT)
73 oflags |= O_DIRECT;
74 if (flags & IO_OSYNC)
75 oflags |= O_SYNC;
76 if (flags & IO_TRUNC)
77 oflags |= O_TRUNC;
78 if (flags & IO_NONBLOCK)
79 oflags |= O_NONBLOCK;
80 if (flags & IO_TMPFILE)
81 oflags |= O_TMPFILE;
82 if (flags & IO_PATH)
83 oflags |= O_PATH;
84 if (flags & IO_NOFOLLOW)
85 oflags |= O_NOFOLLOW;
86
87 /*
88 * if we've been passed a pipe to open, don't block waiting for a
89 * reader or writer to appear. We want to either succeed or error out
90 * immediately.
91 */
92 if (stat(path, &st) < 0 && errno != ENOENT) {
93 perror("stat");
94 return -1;
95 }
96 if (S_ISFIFO(st.st_mode))
97 oflags |= O_NONBLOCK;
98
99 fd = open(path, oflags, mode);
100 if (fd < 0) {
101 if (errno == EISDIR &&
102 ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) {
103 /* make it as if we asked for O_RDONLY & try again */
104 oflags &= ~O_RDWR;
105 oflags |= O_RDONLY;
106 flags |= IO_READONLY;
107 fd = open(path, oflags, mode);
108 if (fd < 0) {
109 perror(path);
110 return -1;
111 }
112 } else {
113 perror(path);
114 return -1;
115 }
116 }
117
118 if (!geom || !platform_test_xfs_fd(fd))
119 return fd;
120
121 if (flags & IO_PATH) {
122 /* Can't call ioctl() on O_PATH fds */
123 memset(geom, 0, sizeof(*geom));
124 } else {
125 int ret;
126
127 ret = xfrog_geometry(fd, geom);
128 if (ret) {
129 xfrog_perror(ret, "XFS_IOC_FSGEOMETRY");
130 close(fd);
131 return -1;
132 }
133 }
134
135 if (!(flags & (IO_READONLY | IO_PATH)) && (flags & IO_REALTIME)) {
136 struct fsxattr attr;
137
138 if (xfsctl(path, fd, FS_IOC_FSGETXATTR, &attr) < 0) {
139 perror("FS_IOC_FSGETXATTR");
140 close(fd);
141 return -1;
142 }
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");
147 close(fd);
148 return -1;
149 }
150 }
151 }
152
153 if (fs_path) {
154 fsp = fs_table_lookup(path, FS_MOUNT_POINT);
155 if (!fsp)
156 memset(fs_path, 0, sizeof(*fs_path));
157 else
158 *fs_path = *fsp;
159 }
160 return fd;
161 }
162
163 int
164 addfile(
165 char *name,
166 int fd,
167 struct xfs_fsop_geom *geometry,
168 int flags,
169 struct fs_path *fs_path)
170 {
171 char *filename;
172
173 filename = strdup(name);
174 if (!filename) {
175 perror("strdup");
176 close(fd);
177 return -1;
178 }
179
180 /* Extend the table of currently open files */
181 filetable = (fileio_t *)realloc(filetable, /* growing */
182 ++filecount * sizeof(fileio_t));
183 if (!filetable) {
184 perror("realloc");
185 filecount = 0;
186 free(filename);
187 close(fd);
188 return -1;
189 }
190
191 /* Finally, make this the new active open file */
192 file = &filetable[filecount - 1];
193 file->fd = fd;
194 file->flags = flags;
195 file->name = filename;
196 file->geom = *geometry;
197 file->fs_path = *fs_path;
198 return 0;
199 }
200
201 static void
202 open_help(void)
203 {
204 printf(_(
205 "\n"
206 " opens a new file in the requested mode\n"
207 "\n"
208 " Example:\n"
209 " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
210 "\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"
229 "\n"));
230 }
231
232 static int
233 open_f(
234 int argc,
235 char **argv)
236 {
237 int c, fd, flags = 0;
238 char *sp;
239 mode_t mode = 0600;
240 struct xfs_fsop_geom geometry = { 0 };
241 struct fs_path fsp;
242
243 if (argc == 1) {
244 if (file)
245 return stat_f(argc, argv);
246 fprintf(stderr, _("no files are open, try 'help open'\n"));
247 return 0;
248 }
249
250 while ((c = getopt(argc, argv, "FLPRTacdfm:nrstx")) != EOF) {
251 switch (c) {
252 case 'F':
253 /* Ignored / deprecated now, handled automatically */
254 break;
255 case 'a':
256 flags |= IO_APPEND;
257 break;
258 case 'c':
259 case 'f':
260 flags |= IO_CREAT;
261 break;
262 case 'd':
263 flags |= IO_DIRECT;
264 break;
265 case 'm':
266 mode = strtoul(optarg, &sp, 0);
267 if (!sp || sp == optarg) {
268 printf(_("non-numeric mode -- %s\n"), optarg);
269 return 0;
270 }
271 break;
272 case 'n':
273 flags |= IO_NONBLOCK;
274 break;
275 case 'r':
276 flags |= IO_READONLY;
277 break;
278 case 's':
279 flags |= IO_OSYNC;
280 break;
281 case 't':
282 flags |= IO_TRUNC;
283 break;
284 case 'R':
285 case 'x': /* backwards compatibility */
286 flags |= IO_REALTIME;
287 break;
288 case 'T':
289 flags |= IO_TMPFILE;
290 break;
291 case 'P':
292 flags |= IO_PATH;
293 break;
294 case 'L':
295 flags |= IO_NOFOLLOW;
296 break;
297 default:
298 return command_usage(&open_cmd);
299 }
300 }
301
302 if (optind != argc - 1)
303 return command_usage(&open_cmd);
304
305 if ((flags & (IO_READONLY|IO_TMPFILE)) == (IO_READONLY|IO_TMPFILE)) {
306 fprintf(stderr, _("-T and -r options are incompatible\n"));
307 return -1;
308 }
309
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"));
313 return -1;
314 }
315
316 fd = openfile(argv[optind], &geometry, flags, mode, &fsp);
317 if (fd < 0)
318 return 0;
319
320 if (!platform_test_xfs_fd(fd))
321 flags |= IO_FOREIGN;
322
323 addfile(argv[optind], fd, &geometry, flags, &fsp);
324 return 0;
325 }
326
327 static int
328 close_f(
329 int argc,
330 char **argv)
331 {
332 size_t length;
333 unsigned int offset;
334
335 if (close(file->fd) < 0) {
336 perror("close");
337 return 0;
338 }
339 free(file->name);
340
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);
345 if (length)
346 memmove(file, file + 1, length);
347
348 /* Resize the memory allocated for the table, possibly freeing */
349 if (--filecount) {
350 filetable = (fileio_t *)realloc(filetable, /* shrinking */
351 filecount * sizeof(fileio_t));
352 if (offset == filecount)
353 offset--;
354 file = filetable + offset;
355 } else {
356 free(filetable);
357 file = filetable = NULL;
358 }
359 filelist_f();
360 return 0;
361 }
362
363 static void
364 lsproj_help(void)
365 {
366 printf(_(
367 "\n"
368 " displays the project identifier associated with the current path\n"
369 "\n"
370 " Options:\n"
371 " -R -- recursively descend (useful when current path is a directory)\n"
372 " -D -- recursively descend, but only list projects on directories\n"
373 "\n"));
374 }
375
376 static int
377 lsproj_callback(
378 const char *path,
379 const struct stat *stat,
380 int status,
381 struct FTW *data)
382 {
383 prid_t projid;
384 int fd;
385
386 if (recurse_dir && !S_ISDIR(stat->st_mode))
387 return 0;
388
389 if ((fd = open(path, O_RDONLY)) == -1) {
390 fprintf(stderr, _("%s: cannot open %s: %s\n"),
391 progname, path, strerror(errno));
392 } else {
393 if (getprojid(path, fd, &projid) == 0)
394 printf("[%u] %s\n", (unsigned int)projid, path);
395 close(fd);
396 }
397 return 0;
398 }
399
400 static int
401 lsproj_f(
402 int argc,
403 char **argv)
404 {
405 prid_t projid;
406 int c;
407
408 recurse_all = recurse_dir = 0;
409 while ((c = getopt(argc, argv, "DR")) != EOF) {
410 switch (c) {
411 case 'D':
412 recurse_all = 0;
413 recurse_dir = 1;
414 break;
415 case 'R':
416 recurse_all = 1;
417 recurse_dir = 0;
418 break;
419 default:
420 return command_usage(&lsproj_cmd);
421 }
422 }
423
424 if (argc != optind)
425 return command_usage(&lsproj_cmd);
426
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)
431 perror("getprojid");
432 else
433 printf(_("projid = %u\n"), (unsigned int)projid);
434 return 0;
435 }
436
437 static void
438 chproj_help(void)
439 {
440 printf(_(
441 "\n"
442 " modifies the project identifier associated with the current path\n"
443 "\n"
444 " -R -- recursively descend (useful when current path is a directory)\n"
445 " -D -- recursively descend, only modifying projects on directories\n"
446 "\n"));
447 }
448
449 static int
450 chproj_callback(
451 const char *path,
452 const struct stat *stat,
453 int status,
454 struct FTW *data)
455 {
456 int fd;
457
458 if (recurse_dir && !S_ISDIR(stat->st_mode))
459 return 0;
460
461 if ((fd = open(path, O_RDONLY)) == -1) {
462 fprintf(stderr, _("%s: cannot open %s: %s\n"),
463 progname, path, strerror(errno));
464 } else {
465 if (setprojid(path, fd, prid) < 0)
466 perror("setprojid");
467 close(fd);
468 }
469 return 0;
470 }
471
472 static int
473 chproj_f(
474 int argc,
475 char **argv)
476 {
477 int c;
478
479 recurse_all = recurse_dir = 0;
480 while ((c = getopt(argc, argv, "DR")) != EOF) {
481 switch (c) {
482 case 'D':
483 recurse_all = 0;
484 recurse_dir = 1;
485 break;
486 case 'R':
487 recurse_all = 1;
488 recurse_dir = 0;
489 break;
490 default:
491 return command_usage(&chproj_cmd);
492 }
493 }
494
495 if (argc != optind + 1)
496 return command_usage(&chproj_cmd);
497
498 prid = prid_from_string(argv[optind]);
499 if (prid == -1) {
500 printf(_("invalid project ID -- %s\n"), argv[optind]);
501 return 0;
502 }
503
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)
508 perror("setprojid");
509 return 0;
510 }
511
512 static void
513 extsize_help(void)
514 {
515 printf(_(
516 "\n"
517 " report or modify preferred extent size (in bytes) for the current path\n"
518 "\n"
519 " -R -- recursively descend (useful when current path is a directory)\n"
520 " -D -- recursively descend, only modifying extsize on directories\n"
521 "\n"));
522 }
523
524 static int
525 get_extsize(const char *path, int fd)
526 {
527 struct fsxattr fsx;
528
529 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
530 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
531 progname, path, strerror(errno));
532 return 0;
533 }
534 printf("[%u] %s\n", fsx.fsx_extsize, path);
535 return 0;
536 }
537
538 static int
539 set_extsize(const char *path, int fd, long extsz)
540 {
541 struct fsxattr fsx;
542 struct stat stat;
543
544 if (fstat(fd, &stat) < 0) {
545 perror("fstat");
546 return 0;
547 }
548 if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
549 printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
550 progname, path, strerror(errno));
551 return 0;
552 }
553
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;
558 } else {
559 printf(_("invalid target file type - file %s\n"), path);
560 return 0;
561 }
562 fsx.fsx_extsize = extsz;
563
564 if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) {
565 printf("%s: FS_IOC_FSSETXATTR %s: %s\n",
566 progname, path, strerror(errno));
567 return 0;
568 }
569
570 return 0;
571 }
572
573 static int
574 get_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 get_extsize(path, fd);
590 close(fd);
591 }
592 return 0;
593 }
594
595 static int
596 set_extsize_callback(
597 const char *path,
598 const struct stat *stat,
599 int status,
600 struct FTW *data)
601 {
602 int fd;
603
604 if (recurse_dir && !S_ISDIR(stat->st_mode))
605 return 0;
606
607 if ((fd = open(path, O_RDONLY)) == -1) {
608 fprintf(stderr, _("%s: cannot open %s: %s\n"),
609 progname, path, strerror(errno));
610 } else {
611 set_extsize(path, fd, extsize);
612 close(fd);
613 }
614 return 0;
615 }
616
617 static int
618 extsize_f(
619 int argc,
620 char **argv)
621 {
622 size_t blocksize, sectsize;
623 int c;
624
625 recurse_all = recurse_dir = 0;
626 init_cvtnum(&blocksize, &sectsize);
627 while ((c = getopt(argc, argv, "DR")) != EOF) {
628 switch (c) {
629 case 'D':
630 recurse_all = 0;
631 recurse_dir = 1;
632 break;
633 case 'R':
634 recurse_all = 1;
635 recurse_dir = 0;
636 break;
637 default:
638 return command_usage(&extsize_cmd);
639 }
640 }
641
642 if (optind < argc) {
643 extsize = (long)cvtnum(blocksize, sectsize, argv[optind]);
644 if (extsize < 0) {
645 printf(_("non-numeric extsize argument -- %s\n"),
646 argv[optind]);
647 return 0;
648 }
649 } else {
650 extsize = -1;
651 }
652
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);
659 else
660 get_extsize(file->name, file->fd);
661 return 0;
662 }
663
664 static void
665 inode_help(void)
666 {
667 printf(_(
668 "\n"
669 "Query physical information about an inode"
670 "\n"
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"
676 "\n"));
677 }
678
679 #define IGROUP_NR (1024)
680 static __u64
681 get_last_inode(void)
682 {
683 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
684 struct xfs_inumbers_req *ireq;
685 uint32_t lastgrp = 0;
686 __u64 last_ino = 0;
687
688 ireq = xfrog_inumbers_alloc_req(IGROUP_NR, 0);
689 if (!ireq) {
690 perror("alloc req");
691 return 0;
692 }
693
694 for (;;) {
695 int ret;
696
697 ret = xfrog_inumbers(&xfd, ireq);
698 if (ret) {
699 xfrog_perror(ret, "XFS_IOC_FSINUMBERS");
700 goto out;
701 }
702
703 /* Did we reach the last inode? */
704 if (ireq->hdr.ocount == 0)
705 break;
706
707 /* last inode in igroup table */
708 lastgrp = ireq->hdr.ocount;
709 }
710
711 if (lastgrp == 0)
712 goto out;
713
714 lastgrp--;
715
716 /* The last inode number in use */
717 last_ino = ireq->inumbers[lastgrp].xi_startino +
718 libxfs_highbit64(ireq->inumbers[lastgrp].xi_allocmask);
719 out:
720 free(ireq);
721
722 return last_ino;
723 }
724
725 static int
726 inode_f(
727 int argc,
728 char **argv)
729 {
730 struct xfs_bulkstat bulkstat;
731 uint64_t result_ino = 0;
732 uint64_t userino = NULLFSINO;
733 char *p;
734 int c;
735 int verbose = 0;
736 int ret_next = 0;
737 int ret;
738
739 while ((c = getopt(argc, argv, "nv")) != EOF) {
740 switch (c) {
741 case 'v':
742 verbose = 1;
743 break;
744 case 'n':
745 ret_next = 1;
746 break;
747 default:
748 return command_usage(&inode_cmd);
749 }
750 }
751
752 /* Last arg (if present) should be an inode number */
753 if (optind < argc) {
754 userino = strtoull(argv[optind], &p, 10);
755 if ((*p != '\0')) {
756 printf(_("%s is not a numeric inode value\n"),
757 argv[optind]);
758 exitcode = 1;
759 return 0;
760 }
761 optind++;
762 }
763
764 /* Extra junk? */
765 if (optind < argc)
766 return command_usage(&inode_cmd);
767
768 /* -n option requires an inode number */
769 if (ret_next && userino == NULLFSINO)
770 return command_usage(&inode_cmd);
771
772 if (userino == NULLFSINO) {
773 /* We are finding last inode in use */
774 result_ino = get_last_inode();
775 if (!result_ino) {
776 exitcode = 1;
777 return 0;
778 }
779 } else if (ret_next) {
780 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
781 struct xfs_bulkstat_req *breq;
782
783 /*
784 * The -n option means that the caller wants to know the number
785 * of the next allocated inode, so we need to increment here.
786 */
787 breq = xfrog_bulkstat_alloc_req(1, userino + 1);
788 if (!breq) {
789 perror("alloc bulkstat");
790 exitcode = 1;
791 return 0;
792 }
793
794 /* get next inode */
795 ret = xfrog_bulkstat(&xfd, breq);
796 if (ret) {
797 xfrog_perror(ret, "bulkstat");
798 free(breq);
799 exitcode = 1;
800 return 0;
801 }
802
803 /* The next inode in use, or 0 if none */
804 if (breq->hdr.ocount)
805 result_ino = breq->bulkstat[0].bs_ino;
806 else
807 result_ino = 0;
808 free(breq);
809 } else {
810 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
811
812 /* get this inode */
813 ret = xfrog_bulkstat_single(&xfd, userino, 0, &bulkstat);
814 if (ret == EINVAL) {
815 /* Not in use */
816 result_ino = 0;
817 } else if (ret) {
818 xfrog_perror(ret, "bulkstat_single");
819 exitcode = 1;
820 return 0;
821 } else {
822 result_ino = bulkstat.bs_ino;
823 }
824 }
825
826 if (verbose && result_ino) {
827 /* Requested verbose and we have an answer */
828 printf("%llu:%d\n", (unsigned long long)result_ino,
829 result_ino > XFS_MAXINUMBER_32 ? 64 : 32);
830 } else if (userino == NULLFSINO) {
831 /* Just checking 32 or 64 bit presence, non-verbose */
832 printf("%d\n", result_ino > XFS_MAXINUMBER_32 ? 1 : 0);
833 } else {
834 /* We asked about a specific inode, non-verbose */
835 printf("%llu\n", (unsigned long long)result_ino);
836 }
837
838 return 0;
839 }
840
841 static void
842 chmod_help(void)
843 {
844 printf(_(
845 "\n"
846 " Change the read/write permissions on the current file\n"
847 "\n"
848 " Options:\n"
849 " -r -- make the file read only (0444 permissions)\n"
850 " -w -- make the file read/write (0664 permissions)\n"
851 "\n"));
852 }
853
854 static int
855 chmod_f(
856 int argc,
857 char **argv)
858 {
859 mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
860 int c;
861
862 while ((c = getopt(argc, argv, "rw")) != EOF) {
863 switch (c) {
864 case 'r':
865 break;
866 case 'w':
867 mode |= S_IWUSR | S_IWGRP;
868 break;
869 default:
870 return command_usage(&chmod_cmd);
871 }
872 }
873
874 if (argc != optind)
875 return command_usage(&chmod_cmd);
876
877 if (fchmod(file->fd, mode) < 0) {
878 exitcode = 1;
879 perror("fchmod");
880 }
881 return 0;
882 }
883 void
884 open_init(void)
885 {
886 open_cmd.name = "open";
887 open_cmd.altname = "o";
888 open_cmd.cfunc = open_f;
889 open_cmd.argmin = 0;
890 open_cmd.argmax = -1;
891 open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK |
892 CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;
893 open_cmd.args = _("[-acdrstxRTPL] [-m mode] [path]");
894 open_cmd.oneline = _("open the file specified by path");
895 open_cmd.help = open_help;
896
897 close_cmd.name = "close";
898 close_cmd.altname = "c";
899 close_cmd.cfunc = close_f;
900 close_cmd.argmin = 0;
901 close_cmd.argmax = 0;
902 close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;
903 close_cmd.oneline = _("close the current open file");
904
905 chproj_cmd.name = "chproj";
906 chproj_cmd.cfunc = chproj_f;
907 chproj_cmd.args = _("[-D | -R] projid");
908 chproj_cmd.argmin = 1;
909 chproj_cmd.argmax = -1;
910 chproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
911 chproj_cmd.oneline =
912 _("change project identifier on the currently open file");
913 chproj_cmd.help = chproj_help;
914
915 lsproj_cmd.name = "lsproj";
916 lsproj_cmd.cfunc = lsproj_f;
917 lsproj_cmd.args = _("[-D | -R]");
918 lsproj_cmd.argmin = 0;
919 lsproj_cmd.argmax = -1;
920 lsproj_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
921 lsproj_cmd.oneline =
922 _("list project identifier set on the currently open file");
923 lsproj_cmd.help = lsproj_help;
924
925 extsize_cmd.name = "extsize";
926 extsize_cmd.cfunc = extsize_f;
927 extsize_cmd.args = _("[-D | -R] [extsize]");
928 extsize_cmd.argmin = 0;
929 extsize_cmd.argmax = -1;
930 extsize_cmd.flags = CMD_NOMAP_OK;
931 extsize_cmd.oneline =
932 _("get/set preferred extent size (in bytes) for the open file");
933 extsize_cmd.help = extsize_help;
934
935 inode_cmd.name = "inode";
936 inode_cmd.cfunc = inode_f;
937 inode_cmd.args = _("[-nv] [num]");
938 inode_cmd.argmin = 0;
939 inode_cmd.argmax = 3;
940 inode_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT;
941 inode_cmd.oneline =
942 _("Query inode number usage in the filesystem");
943 inode_cmd.help = inode_help;
944
945 chmod_cmd.name = "chmod";
946 chmod_cmd.cfunc = chmod_f;
947 chmod_cmd.args = _("-r | -w");
948 chmod_cmd.argmin = 1;
949 chmod_cmd.argmax = 1;
950 chmod_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;
951 chmod_cmd.oneline =
952 _("change the read/write permissions on the currently open file");
953 chmod_cmd.help = chmod_help;
954
955 add_command(&open_cmd);
956 add_command(&close_cmd);
957 add_command(&chproj_cmd);
958 add_command(&lsproj_cmd);
959 add_command(&extsize_cmd);
960 add_command(&inode_cmd);
961 add_command(&chmod_cmd);
962 }