]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/open.c
libfrog: refactor open-coded bulkstat calls
[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 "fsgeom.h"
13 #include "libfrog/bulkstat.h"
14
15 #ifndef __O_TMPFILE
16 #if defined __alpha__
17 #define __O_TMPFILE 0100000000
18 #elif defined(__hppa__)
19 #define __O_TMPFILE 040000000
20 #elif defined(__sparc__)
21 #define __O_TMPFILE 0x2000000
22 #else
23 #define __O_TMPFILE 020000000
24 #endif
25 #endif /* __O_TMPFILE */
26
27 #ifndef O_TMPFILE
28 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
29 #endif
30
31 #ifndef O_PATH
32 #if defined __alpha__
33 #define O_PATH 040000000
34 #elif defined(__hppa__)
35 #define O_PATH 020000000
36 #elif defined(__sparc__)
37 #define O_PATH 0x1000000
38 #else
39 #define O_PATH 010000000
40 #endif
41 #endif /* O_PATH */
42
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;
50 static prid_t prid;
51 static long extsize;
52
53 int
54 openfile(
55 char *path,
56 struct xfs_fsop_geom *geom,
57 int flags,
58 mode_t mode,
59 struct fs_path *fs_path)
60 {
61 struct fs_path *fsp;
62 struct stat st = { 0 };
63 int fd;
64 int oflags;
65
66 oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
67 if (flags & IO_APPEND)
68 oflags |= O_APPEND;
69 if (flags & IO_CREAT)
70 oflags |= O_CREAT;
71 if (flags & IO_DIRECT)
72 oflags |= O_DIRECT;
73 if (flags & IO_OSYNC)
74 oflags |= O_SYNC;
75 if (flags & IO_TRUNC)
76 oflags |= O_TRUNC;
77 if (flags & IO_NONBLOCK)
78 oflags |= O_NONBLOCK;
79 if (flags & IO_TMPFILE)
80 oflags |= O_TMPFILE;
81 if (flags & IO_PATH)
82 oflags |= O_PATH;
83 if (flags & IO_NOFOLLOW)
84 oflags |= O_NOFOLLOW;
85
86 /*
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
89 * immediately.
90 */
91 if (stat(path, &st) < 0 && errno != ENOENT) {
92 perror("stat");
93 return -1;
94 }
95 if (S_ISFIFO(st.st_mode))
96 oflags |= O_NONBLOCK;
97
98 fd = open(path, oflags, mode);
99 if (fd < 0) {
100 if (errno == EISDIR &&
101 ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) {
102 /* make it as if we asked for O_RDONLY & try again */
103 oflags &= ~O_RDWR;
104 oflags |= O_RDONLY;
105 flags |= IO_READONLY;
106 fd = open(path, oflags, mode);
107 if (fd < 0) {
108 perror(path);
109 return -1;
110 }
111 } else {
112 perror(path);
113 return -1;
114 }
115 }
116
117 if (!geom || !platform_test_xfs_fd(fd))
118 return fd;
119
120 if (flags & IO_PATH) {
121 /* Can't call ioctl() on O_PATH fds */
122 memset(geom, 0, sizeof(*geom));
123 } else {
124 int ret;
125
126 ret = xfrog_geometry(fd, geom);
127 if (ret) {
128 errno = ret;
129 perror("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 static __u64
680 get_last_inode(void)
681 {
682 __u64 lastip = 0;
683 __u64 lastgrp = 0;
684 __s32 ocount = 0;
685 __u64 last_ino;
686 struct xfs_inogrp igroup[1024];
687 struct xfs_fsop_bulkreq bulkreq;
688
689 bulkreq.lastip = &lastip;
690 bulkreq.ubuffer = &igroup;
691 bulkreq.icount = sizeof(igroup) / sizeof(struct xfs_inogrp);
692 bulkreq.ocount = &ocount;
693
694 for (;;) {
695 if (xfsctl(file->name, file->fd, XFS_IOC_FSINUMBERS,
696 &bulkreq)) {
697 perror("XFS_IOC_FSINUMBERS");
698 return 0;
699 }
700
701 /* Did we reach the last inode? */
702 if (ocount == 0)
703 break;
704
705 /* last inode in igroup table */
706 lastgrp = ocount;
707 }
708
709 if (lastgrp == 0)
710 return 0;
711
712 lastgrp--;
713
714 /* The last inode number in use */
715 last_ino = igroup[lastgrp].xi_startino +
716 libxfs_highbit64(igroup[lastgrp].xi_allocmask);
717
718 return last_ino;
719 }
720
721 static int
722 inode_f(
723 int argc,
724 char **argv)
725 {
726 struct xfs_bstat bstat;
727 uint32_t count = 0;
728 uint64_t result_ino = 0;
729 uint64_t userino = NULLFSINO;
730 char *p;
731 int c;
732 int verbose = 0;
733 int ret_next = 0;
734 int ret;
735
736 while ((c = getopt(argc, argv, "nv")) != EOF) {
737 switch (c) {
738 case 'v':
739 verbose = 1;
740 break;
741 case 'n':
742 ret_next = 1;
743 break;
744 default:
745 return command_usage(&inode_cmd);
746 }
747 }
748
749 /* Last arg (if present) should be an inode number */
750 if (optind < argc) {
751 userino = strtoull(argv[optind], &p, 10);
752 if ((*p != '\0')) {
753 printf(_("%s is not a numeric inode value\n"),
754 argv[optind]);
755 exitcode = 1;
756 return 0;
757 }
758 optind++;
759 }
760
761 /* Extra junk? */
762 if (optind < argc)
763 return command_usage(&inode_cmd);
764
765 /* -n option requires an inode number */
766 if (ret_next && userino == NULLFSINO)
767 return command_usage(&inode_cmd);
768
769 if (userino == NULLFSINO) {
770 /* We are finding last inode in use */
771 result_ino = get_last_inode();
772 if (!result_ino) {
773 exitcode = 1;
774 return 0;
775 }
776 } else if (ret_next) {
777 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
778
779 /* get next inode */
780 ret = xfrog_bulkstat(&xfd, &userino, 1, &bstat, &count);
781 if (ret) {
782 errno = ret;
783 perror("bulkstat");
784 exitcode = 1;
785 return 0;
786 }
787
788 /* The next inode in use, or 0 if none */
789 if (count)
790 result_ino = bstat.bs_ino;
791 else
792 result_ino = 0;
793 } else {
794 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
795
796 /* get this inode */
797 ret = xfrog_bulkstat_single(&xfd, userino, &bstat);
798 if (ret == EINVAL) {
799 /* Not in use */
800 result_ino = 0;
801 } else if (ret) {
802 errno = ret;
803 perror("bulkstat_single");
804 exitcode = 1;
805 return 0;
806 } else {
807 result_ino = bstat.bs_ino;
808 }
809 }
810
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);
818 } else {
819 /* We asked about a specific inode, non-verbose */
820 printf("%llu\n", (unsigned long long)result_ino);
821 }
822
823 return 0;
824 }
825
826 static void
827 chmod_help(void)
828 {
829 printf(_(
830 "\n"
831 " Change the read/write permissions on the current file\n"
832 "\n"
833 " Options:\n"
834 " -r -- make the file read only (0444 permissions)\n"
835 " -w -- make the file read/write (0664 permissions)\n"
836 "\n"));
837 }
838
839 static int
840 chmod_f(
841 int argc,
842 char **argv)
843 {
844 mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
845 int c;
846
847 while ((c = getopt(argc, argv, "rw")) != EOF) {
848 switch (c) {
849 case 'r':
850 break;
851 case 'w':
852 mode |= S_IWUSR | S_IWGRP;
853 break;
854 default:
855 return command_usage(&chmod_cmd);
856 }
857 }
858
859 if (argc != optind)
860 return command_usage(&chmod_cmd);
861
862 if (fchmod(file->fd, mode) < 0) {
863 exitcode = 1;
864 perror("fchmod");
865 }
866 return 0;
867 }
868 void
869 open_init(void)
870 {
871 open_cmd.name = "open";
872 open_cmd.altname = "o";
873 open_cmd.cfunc = open_f;
874 open_cmd.argmin = 0;
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;
881
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");
889
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;
896 chproj_cmd.oneline =
897 _("change project identifier on the currently open file");
898 chproj_cmd.help = chproj_help;
899
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;
906 lsproj_cmd.oneline =
907 _("list project identifier set on the currently open file");
908 lsproj_cmd.help = lsproj_help;
909
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;
919
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;
926 inode_cmd.oneline =
927 _("Query inode number usage in the filesystem");
928 inode_cmd.help = inode_help;
929
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;
936 chmod_cmd.oneline =
937 _("change the read/write permissions on the currently open file");
938 chmod_cmd.help = chmod_help;
939
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);
947 }