]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/open.c
08425ebd432b105096bc76e219b05ee93748fb9f
[thirdparty/xfsprogs-dev.git] / io / open.c
1 /*
2 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include <xfs/libxfs.h>
20 #include <xfs/command.h>
21 #include <xfs/input.h>
22 #include "init.h"
23 #include "io.h"
24
25 static cmdinfo_t open_cmd;
26 static cmdinfo_t stat_cmd;
27 static cmdinfo_t close_cmd;
28 static cmdinfo_t setfl_cmd;
29 static cmdinfo_t statfs_cmd;
30 static cmdinfo_t chproj_cmd;
31 static cmdinfo_t lsproj_cmd;
32 static cmdinfo_t extsize_cmd;
33 static prid_t prid;
34
35 off64_t
36 filesize(void)
37 {
38 struct stat64 st;
39
40 if (fstat64(file->fd, &st) < 0) {
41 perror("fstat64");
42 return -1;
43 }
44 return st.st_size;
45 }
46
47 static char *
48 filetype(mode_t mode)
49 {
50 switch (mode & S_IFMT) {
51 case S_IFSOCK:
52 return _("socket");
53 case S_IFDIR:
54 return _("directory");
55 case S_IFCHR:
56 return _("char device");
57 case S_IFBLK:
58 return _("block device");
59 case S_IFREG:
60 return _("regular file");
61 case S_IFLNK:
62 return _("symbolic link");
63 case S_IFIFO:
64 return _("fifo");
65 }
66 return NULL;
67 }
68
69 static int
70 stat_f(
71 int argc,
72 char **argv)
73 {
74 struct fsxattr fsx;
75 struct stat64 st;
76 int verbose = (argc == 2 && !strcmp(argv[1], "-v"));
77
78 printf(_("fd.path = \"%s\"\n"), file->name);
79 printf(_("fd.flags = %s,%s,%s%s%s%s\n"),
80 file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
81 file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
82 file->flags & IO_READONLY ? _("read-only") : _("read-write"),
83 file->flags & IO_REALTIME ? _(",real-time") : "",
84 file->flags & IO_APPEND ? _(",append-only") : "",
85 file->flags & IO_NONBLOCK ? _(",non-block") : "");
86 if (fstat64(file->fd, &st) < 0) {
87 perror("fstat64");
88 } else {
89 printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
90 printf(_("stat.type = %s\n"), filetype(st.st_mode));
91 printf(_("stat.size = %lld\n"), (long long)st.st_size);
92 printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
93 if (verbose) {
94 printf(_("stat.atime = %s"), ctime(&st.st_atime));
95 printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
96 printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
97 }
98 }
99 if (file->flags & IO_FOREIGN)
100 return 0;
101 if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
102 perror("XFS_IOC_FSGETXATTR");
103 } else {
104 printf(_("xattr.xflags = 0x%x "), fsx.fsx_xflags);
105 printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1);
106 printf(_("xattr.extsize = %u\n"), fsx.fsx_extsize);
107 printf(_("xattr.nextents = %u\n"), fsx.fsx_nextents);
108 }
109 return 0;
110 }
111
112 int
113 openfile(
114 char *path,
115 xfs_fsop_geom_t *geom,
116 int flags,
117 mode_t mode)
118 {
119 int fd;
120 int oflags;
121
122 oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
123 if (flags & IO_APPEND)
124 oflags |= O_APPEND;
125 if (flags & IO_CREAT)
126 oflags |= O_CREAT;
127 if (flags & IO_DIRECT)
128 oflags |= O_DIRECT;
129 if (flags & IO_OSYNC)
130 oflags |= O_SYNC;
131 if (flags & IO_TRUNC)
132 oflags |= O_TRUNC;
133 if (flags & IO_NONBLOCK)
134 oflags |= O_NONBLOCK;
135
136 fd = open(path, oflags, mode);
137 if (fd < 0) {
138 perror(path);
139 return -1;
140 }
141
142 if (!geom)
143 return fd;
144
145 if (!platform_test_xfs_fd(fd)) {
146 fprintf(stderr, _("%s: specified file "
147 "[\"%s\"] is not on an XFS filesystem\n"),
148 progname, path);
149 close(fd);
150 return -1;
151 }
152
153 if (xfsctl(path, fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
154 perror("XFS_IOC_FSGEOMETRY");
155 close(fd);
156 return -1;
157 }
158
159 if (!(flags & IO_READONLY) && (flags & IO_REALTIME)) {
160 struct fsxattr attr;
161
162 if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &attr) < 0) {
163 perror("XFS_IOC_FSGETXATTR");
164 close(fd);
165 return -1;
166 }
167 if (!(attr.fsx_xflags & XFS_XFLAG_REALTIME)) {
168 attr.fsx_xflags |= XFS_XFLAG_REALTIME;
169 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &attr) < 0) {
170 perror("XFS_IOC_FSSETXATTR");
171 close(fd);
172 return -1;
173 }
174 }
175 }
176 return fd;
177 }
178
179 int
180 addfile(
181 char *name,
182 int fd,
183 xfs_fsop_geom_t *geometry,
184 int flags)
185 {
186 char *filename;
187
188 filename = strdup(name);
189 if (!filename) {
190 perror("strdup");
191 close(fd);
192 return -1;
193 }
194
195 /* Extend the table of currently open files */
196 filetable = (fileio_t *)realloc(filetable, /* growing */
197 ++filecount * sizeof(fileio_t));
198 if (!filetable) {
199 perror("realloc");
200 filecount = 0;
201 free(filename);
202 close(fd);
203 return -1;
204 }
205
206 /* Finally, make this the new active open file */
207 file = &filetable[filecount - 1];
208 file->fd = fd;
209 file->flags = flags;
210 file->name = filename;
211 file->geom = *geometry;
212 return 0;
213 }
214
215 static void
216 open_help(void)
217 {
218 printf(_(
219 "\n"
220 " opens a new file in the requested mode\n"
221 "\n"
222 " Example:\n"
223 " 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
224 "\n"
225 " Opens a file for subsequent use by all of the other xfs_io commands.\n"
226 " With no arguments, open uses the stat command to show the current file.\n"
227 " -F -- foreign filesystem file, disallow XFS-specific commands\n"
228 " -a -- open with the O_APPEND flag (append-only mode)\n"
229 " -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
230 " -f -- open with O_CREAT (create the file if it doesn't exist)\n"
231 " -m -- permissions to use in case a new file is created (default 0600)\n"
232 " -n -- open with O_NONBLOCK\n"
233 " -r -- open with O_RDONLY, the default is O_RDWR\n"
234 " -s -- open with O_SYNC\n"
235 " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
236 " -R -- mark the file as a realtime XFS file immediately after opening it\n"
237 " Note1: usually read/write direct IO requests must be blocksize aligned;\n"
238 " some kernels, however, allow sectorsize alignment for direct IO.\n"
239 " Note2: the bmap for non-regular files can be obtained provided the file\n"
240 " was opened correctly (in particular, must be opened read-only).\n"
241 "\n"));
242 }
243
244 static int
245 open_f(
246 int argc,
247 char **argv)
248 {
249 int c, fd, flags = 0;
250 char *sp;
251 mode_t mode = 0600;
252 xfs_fsop_geom_t geometry = { 0 };
253
254 if (argc == 1) {
255 if (file)
256 return stat_f(argc, argv);
257 fprintf(stderr, _("no files are open, try 'help open'\n"));
258 return 0;
259 }
260
261 while ((c = getopt(argc, argv, "FRacdfm:nrstx")) != EOF) {
262 switch (c) {
263 case 'F':
264 flags |= IO_FOREIGN;
265 break;
266 case 'a':
267 flags |= IO_APPEND;
268 break;
269 case 'c':
270 case 'f':
271 flags |= IO_CREAT;
272 break;
273 case 'd':
274 flags |= IO_DIRECT;
275 break;
276 case 'm':
277 mode = strtoul(optarg, &sp, 0);
278 if (!sp || sp == optarg) {
279 printf(_("non-numeric mode -- %s\n"), optarg);
280 return 0;
281 }
282 break;
283 case 'n':
284 flags |= IO_NONBLOCK;
285 break;
286 case 'r':
287 flags |= IO_READONLY;
288 break;
289 case 's':
290 flags |= IO_OSYNC;
291 break;
292 case 't':
293 flags |= IO_TRUNC;
294 break;
295 case 'R':
296 case 'x': /* backwards compatibility */
297 flags |= IO_REALTIME;
298 break;
299 default:
300 return command_usage(&open_cmd);
301 }
302 }
303
304 if (optind != argc - 1)
305 return command_usage(&open_cmd);
306
307 fd = openfile(argv[optind], flags & IO_FOREIGN ?
308 NULL : &geometry, flags, mode);
309 if (fd < 0)
310 return 0;
311
312 addfile(argv[optind], fd, &geometry, flags);
313 return 0;
314 }
315
316 static int
317 close_f(
318 int argc,
319 char **argv)
320 {
321 size_t length;
322 unsigned int offset;
323
324 if (close(file->fd) < 0) {
325 perror("close");
326 return 0;
327 }
328 free(file->name);
329
330 /* Shuffle the file table entries down over the removed entry */
331 offset = file - &filetable[0];
332 length = filecount * sizeof(fileio_t);
333 length -= (offset + 1) * sizeof(fileio_t);
334 if (length)
335 memmove(file, file + 1, length);
336
337 /* Resize the memory allocated for the table, possibly freeing */
338 if (--filecount) {
339 filetable = (fileio_t *)realloc(filetable, /* shrinking */
340 filecount * sizeof(fileio_t));
341 if (offset == filecount)
342 offset--;
343 file = filetable + offset;
344 } else {
345 free(filetable);
346 file = filetable = NULL;
347 }
348 filelist_f();
349 return 0;
350 }
351
352 static void
353 lsproj_help(void)
354 {
355 printf(_(
356 "\n"
357 " displays the project identifier associated with the current path\n"
358 "\n"
359 " Options:\n"
360 " -R -- recursively descend (useful when current path is a directory)\n"
361 " -D -- recursively descend, but only list projects on directories\n"
362 "\n"));
363 }
364
365 static int
366 lsproj_callback(
367 const char *path,
368 const struct stat *stat,
369 int status,
370 struct FTW *data)
371 {
372 prid_t projid;
373 int fd;
374
375 if (recurse_dir && !S_ISDIR(stat->st_mode))
376 return 0;
377
378 if ((fd = open(path, O_RDONLY)) == -1) {
379 fprintf(stderr, _("%s: cannot open %s: %s\n"),
380 progname, path, strerror(errno));
381 } else {
382 if (getprojid(path, fd, &projid) == 0)
383 printf("[%u] %s\n", projid, path);
384 close(fd);
385 }
386 return 0;
387 }
388
389 static int
390 lsproj_f(
391 int argc,
392 char **argv)
393 {
394 prid_t projid;
395 int c;
396
397 while ((c = getopt(argc, argv, "DR")) != EOF) {
398 switch (c) {
399 case 'D':
400 recurse_all = 0;
401 recurse_dir = 1;
402 break;
403 case 'R':
404 recurse_all = 1;
405 recurse_dir = 0;
406 break;
407 default:
408 return command_usage(&lsproj_cmd);
409 }
410 }
411
412 if (argc != optind)
413 return command_usage(&lsproj_cmd);
414
415 if (recurse_all || recurse_dir)
416 nftw(file->name, lsproj_callback,
417 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
418 else if (getprojid(file->name, file->fd, &projid) < 0)
419 perror("getprojid");
420 else
421 printf(_("projid = %u\n"), projid);
422 return 0;
423 }
424
425 static void
426 chproj_help(void)
427 {
428 printf(_(
429 "\n"
430 " modifies the project identifier associated with the current path\n"
431 "\n"
432 " -R -- recursively descend (useful when current path is a directory)\n"
433 " -D -- recursively descend, only modifying projects on directories\n"
434 "\n"));
435 }
436
437 static int
438 chproj_callback(
439 const char *path,
440 const struct stat *stat,
441 int status,
442 struct FTW *data)
443 {
444 int fd;
445
446 if (recurse_dir && !S_ISDIR(stat->st_mode))
447 return 0;
448
449 if ((fd = open(path, O_RDONLY)) == -1) {
450 fprintf(stderr, _("%s: cannot open %s: %s\n"),
451 progname, path, strerror(errno));
452 } else {
453 if (setprojid(path, fd, prid) < 0)
454 perror("setprojid");
455 close(fd);
456 }
457 return 0;
458 }
459
460 static int
461 chproj_f(
462 int argc,
463 char **argv)
464 {
465 int c;
466
467 while ((c = getopt(argc, argv, "DR")) != EOF) {
468 switch (c) {
469 case 'D':
470 recurse_all = 0;
471 recurse_dir = 1;
472 break;
473 case 'R':
474 recurse_all = 1;
475 recurse_dir = 0;
476 break;
477 default:
478 return command_usage(&chproj_cmd);
479 }
480 }
481
482 if (argc != optind + 1)
483 return command_usage(&chproj_cmd);
484
485 prid = prid_from_string(argv[optind]);
486 if (prid == -1) {
487 printf(_("invalid project ID -- %s\n"), argv[optind]);
488 return 0;
489 }
490
491 if (recurse_all || recurse_dir)
492 nftw(file->name, chproj_callback,
493 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
494 else if (setprojid(file->name, file->fd, prid) < 0)
495 perror("setprojid");
496 return 0;
497 }
498
499 static int
500 setfl_f(
501 int argc,
502 char **argv)
503 {
504 int c, flags;
505
506 flags = fcntl(file->fd, F_GETFL, 0);
507 if (flags < 0) {
508 perror("fcntl(F_GETFL)");
509 return 0;
510 }
511
512 while ((c = getopt(argc, argv, "ad")) != EOF) {
513 switch (c) {
514 case 'a':
515 if (flags & O_APPEND)
516 flags |= O_APPEND;
517 else
518 flags &= ~O_APPEND;
519 break;
520 case 'd':
521 if (flags & O_DIRECT)
522 flags |= O_DIRECT;
523 else
524 flags &= ~O_DIRECT;
525 break;
526 default:
527 printf(_("invalid setfl argument -- '%c'\n"), c);
528 return 0;
529 }
530 }
531
532 if (fcntl(file->fd, F_SETFL, flags) < 0)
533 perror("fcntl(F_SETFL)");
534
535 return 0;
536 }
537
538 static int
539 extsize_f(
540 int argc,
541 char **argv)
542 {
543 struct fsxattr fsx;
544 struct stat64 stat;
545 long extsize;
546 size_t blocksize, sectsize;
547
548 init_cvtnum(&blocksize, &sectsize);
549 extsize = (long)cvtnum(blocksize, sectsize, argv[1]);
550 if (extsize < 0) {
551 printf(_("non-numeric extsize argument -- %s\n"), argv[1]);
552 return 0;
553 }
554 if (fstat64(file->fd, &stat) < 0) {
555 perror("fstat64");
556 return 0;
557 }
558 if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
559 perror("XFS_IOC_FSGETXATTR");
560 return 0;
561 }
562
563 if (S_ISREG(stat.st_mode)) {
564 fsx.fsx_xflags |= XFS_XFLAG_EXTSIZE;
565 } else if (S_ISDIR(stat.st_mode)) {
566 fsx.fsx_xflags |= XFS_XFLAG_EXTSZINHERIT;
567 } else {
568 printf(_("invalid target file type - file %s\n"), file->name);
569 return 0;
570 }
571 fsx.fsx_extsize = extsize;
572
573 if ((xfsctl(file->name, file->fd, XFS_IOC_FSSETXATTR, &fsx)) < 0) {
574 perror("XFS_IOC_FSSETXATTR");
575 return 0;
576 }
577
578 return 0;
579 }
580
581 static int
582 statfs_f(
583 int argc,
584 char **argv)
585 {
586 struct xfs_fsop_counts fscounts;
587 struct xfs_fsop_geom fsgeo;
588 struct statfs st;
589
590 printf(_("fd.path = \"%s\"\n"), file->name);
591 if (platform_fstatfs(file->fd, &st) < 0) {
592 perror("fstatfs");
593 } else {
594 printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize);
595 printf(_("statfs.f_blocks = %lld\n"), (long long) st.f_blocks);
596 #if defined(__sgi__)
597 printf(_("statfs.f_frsize = %lld\n"), (long long) st.f_frsize);
598 #else
599 printf(_("statfs.f_bavail = %lld\n"), (long long) st.f_bavail);
600 #endif
601 printf(_("statfs.f_files = %lld\n"), (long long) st.f_files);
602 printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree);
603 }
604 if (file->flags & IO_FOREIGN)
605 return 0;
606 if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
607 perror("XFS_IOC_FSGEOMETRY_V1");
608 } else {
609 printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
610 printf(_("geom.agcount = %u\n"), fsgeo.agcount);
611 printf(_("geom.agblocks = %u\n"), fsgeo.agblocks);
612 printf(_("geom.datablocks = %llu\n"),
613 (unsigned long long) fsgeo.datablocks);
614 printf(_("geom.rtblocks = %llu\n"),
615 (unsigned long long) fsgeo.rtblocks);
616 printf(_("geom.rtextents = %llu\n"),
617 (unsigned long long) fsgeo.rtextents);
618 printf(_("geom.rtextsize = %u\n"), fsgeo.rtextsize);
619 printf(_("geom.sunit = %u\n"), fsgeo.sunit);
620 printf(_("geom.swidth = %u\n"), fsgeo.swidth);
621 }
622 if ((xfsctl(file->name, file->fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
623 perror("XFS_IOC_FSCOUNTS");
624 } else {
625 printf(_("counts.freedata = %llu\n"),
626 (unsigned long long) fscounts.freedata);
627 printf(_("counts.freertx = %llu\n"),
628 (unsigned long long) fscounts.freertx);
629 printf(_("counts.freeino = %llu\n"),
630 (unsigned long long) fscounts.freeino);
631 printf(_("counts.allocino = %llu\n"),
632 (unsigned long long) fscounts.allocino);
633 }
634 return 0;
635 }
636
637 void
638 open_init(void)
639 {
640 open_cmd.name = _("open");
641 open_cmd.altname = _("o");
642 open_cmd.cfunc = open_f;
643 open_cmd.argmin = 0;
644 open_cmd.argmax = -1;
645 open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
646 open_cmd.args = _("[-acdrstx] [path]");
647 open_cmd.oneline = _("open the file specified by path");
648 open_cmd.help = open_help;
649
650 stat_cmd.name = _("stat");
651 stat_cmd.cfunc = stat_f;
652 stat_cmd.argmin = 0;
653 stat_cmd.argmax = 1;
654 stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
655 stat_cmd.args = _("[-v]");
656 stat_cmd.oneline = _("statistics on the currently open file");
657
658 close_cmd.name = _("close");
659 close_cmd.altname = _("c");
660 close_cmd.cfunc = close_f;
661 close_cmd.argmin = 0;
662 close_cmd.argmax = 0;
663 close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
664 close_cmd.oneline = _("close the current open file");
665
666 setfl_cmd.name = _("setfl");
667 setfl_cmd.cfunc = setfl_f;
668 setfl_cmd.args = _("[-adx]");
669 setfl_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
670 setfl_cmd.oneline =
671 _("set/clear append/direct flags on the open file");
672
673 statfs_cmd.name = _("statfs");
674 statfs_cmd.cfunc = statfs_f;
675 statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
676 statfs_cmd.oneline =
677 _("statistics on the filesystem of the currently open file");
678
679 chproj_cmd.name = _("chproj");
680 chproj_cmd.cfunc = chproj_f;
681 chproj_cmd.args = _("[-D | -R] projid");
682 chproj_cmd.argmin = 1;
683 chproj_cmd.argmax = -1;
684 chproj_cmd.flags = CMD_NOMAP_OK;
685 chproj_cmd.oneline =
686 _("change project identifier on the currently open file");
687 chproj_cmd.help = chproj_help;
688
689 lsproj_cmd.name = _("lsproj");
690 lsproj_cmd.cfunc = lsproj_f;
691 lsproj_cmd.args = _("[-D | -R]");
692 lsproj_cmd.argmin = 0;
693 lsproj_cmd.argmax = -1;
694 lsproj_cmd.flags = CMD_NOMAP_OK;
695 lsproj_cmd.oneline =
696 _("list project identifier set on the currently open file");
697 lsproj_cmd.help = lsproj_help;
698
699 extsize_cmd.name = _("extsize");
700 extsize_cmd.cfunc = extsize_f;
701 extsize_cmd.argmin = 1;
702 extsize_cmd.argmax = 1;
703 extsize_cmd.flags = CMD_NOMAP_OK;
704 extsize_cmd.oneline =
705 _("set prefered extent size (in bytes) for the open file");
706
707 add_command(&open_cmd);
708 add_command(&stat_cmd);
709 add_command(&close_cmd);
710 add_command(&setfl_cmd);
711 add_command(&statfs_cmd);
712 add_command(&chproj_cmd);
713 add_command(&lsproj_cmd);
714 add_command(&extsize_cmd);
715 }