1 /*
2 * f2fs_io.c - f2fs ioctl utility
3 *
4 * Author: Jaegeuk Kim <jaegeuk@kernel.org>
5 *
6 * Copied portion of the code from ../f2fscrypt.c
7 */
8
9 #ifndef _GNU_SOURCE
10 #define _GNU_SOURCE
11 #endif
12 #ifndef _LARGEFILE_SOURCE
13 #define _LARGEFILE_SOURCE
14 #endif
15 #ifndef _LARGEFILE64_SOURCE
16 #define _LARGEFILE64_SOURCE
17 #endif
18 #ifndef O_LARGEFILE
19 #define O_LARGEFILE 0
20 #endif
21 #ifndef __SANE_USERSPACE_TYPES__
22 #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
23 #endif
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <inttypes.h>
29 #include <limits.h>
30 #include <linux/fs.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/mman.h>
38 #include <sys/sendfile.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <termios.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 #include <android_config.h>
49
50 #include "f2fs_io.h"
51
52 struct cmd_desc {
53 const char *cmd_name;
54 void (*cmd_func)(int, char **, const struct cmd_desc *);
55 const char *cmd_desc;
56 const char *cmd_help;
57 int cmd_flags;
58 };
59
60 static void __attribute__((noreturn))
do_die(const char * format,va_list va,int err)61 do_die(const char *format, va_list va, int err)
62 {
63 vfprintf(stderr, format, va);
64 if (err)
65 fprintf(stderr, ": %s", strerror(err));
66 putc('\n', stderr);
67 exit(1);
68 }
69
70 static void __attribute__((noreturn, format(printf, 1, 2)))
die_errno(const char * format,...)71 die_errno(const char *format, ...)
72 {
73 va_list va;
74
75 va_start(va, format);
76 do_die(format, va, errno);
77 va_end(va);
78 }
79
80 static void __attribute__((noreturn, format(printf, 1, 2)))
die(const char * format,...)81 die(const char *format, ...)
82 {
83 va_list va;
84
85 va_start(va, format);
86 do_die(format, va, 0);
87 va_end(va);
88 }
89
xmalloc(size_t size)90 static void *xmalloc(size_t size)
91 {
92 void *p = malloc(size);
93
94 if (!p)
95 die("Memory alloc failed (requested %zu bytes)", size);
96 return p;
97 }
98
aligned_xalloc(size_t alignment,size_t size)99 static void *aligned_xalloc(size_t alignment, size_t size)
100 {
101 void *p = aligned_alloc(alignment, size);
102
103 if (!p)
104 die("Memory alloc failed (requested %zu bytes)", size);
105 return p;
106 }
107
xopen(const char * pathname,int flags,mode_t mode)108 static int xopen(const char *pathname, int flags, mode_t mode)
109 {
110 int fd = open(pathname, flags, mode);
111
112 if (fd < 0)
113 die_errno("Failed to open %s", pathname);
114 return fd;
115 }
116
xread(int fd,void * buf,size_t count)117 static ssize_t xread(int fd, void *buf, size_t count)
118 {
119 ssize_t ret = read(fd, buf, count);
120
121 if (ret < 0)
122 die_errno("read failed");
123 return ret;
124 }
125
full_write(int fd,const void * buf,size_t count)126 static void full_write(int fd, const void *buf, size_t count)
127 {
128 while (count) {
129 ssize_t ret = write(fd, buf, count);
130
131 if (ret < 0)
132 die_errno("write failed");
133 buf = (char *)buf + ret;
134 count -= ret;
135 }
136 }
137
138 #ifdef HAVE_MACH_TIME_H
get_current_us()139 static u64 get_current_us()
140 {
141 return mach_absolute_time() / 1000;
142 }
143 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
get_current_us()144 static u64 get_current_us()
145 {
146 struct timespec t;
147 t.tv_sec = t.tv_nsec = 0;
148 clock_gettime(CLOCK_BOOTTIME, &t);
149 return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
150 }
151 #else
get_current_us()152 static u64 get_current_us()
153 {
154 return 0;
155 }
156 #endif
157
158 #define fsync_desc "fsync"
159 #define fsync_help \
160 "f2fs_io fsync [file]\n\n" \
161 "fsync given the file\n" \
162
do_fsync(int argc,char ** argv,const struct cmd_desc * cmd)163 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
164 {
165 int fd;
166
167 if (argc != 2) {
168 fputs("Excess arguments\n\n", stderr);
169 fputs(cmd->cmd_help, stderr);
170 exit(1);
171 }
172
173 fd = xopen(argv[1], O_WRONLY, 0);
174
175 if (fsync(fd) != 0)
176 die_errno("fsync failed");
177
178 printf("fsync a file\n");
179 exit(0);
180 }
181
182 #define set_verity_desc "Set fs-verity"
183 #define set_verity_help \
184 "f2fs_io set_verity [file]\n\n" \
185 "Set fsverity bit given a file\n" \
186
do_set_verity(int argc,char ** argv,const struct cmd_desc * cmd)187 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
188 {
189 int ret, fd;
190
191 if (argc != 2) {
192 fputs("Excess arguments\n\n", stderr);
193 fputs(cmd->cmd_help, stderr);
194 exit(1);
195 }
196
197 fd = open(argv[1], O_RDWR);
198
199 ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
200 if (ret < 0) {
201 perror("FS_IOC_ENABLE_VERITY");
202 exit(1);
203 }
204
205 printf("Set fsverity bit to %s\n", argv[1]);
206 exit(0);
207 }
208
209 #define getflags_desc "getflags ioctl"
210 #define getflags_help \
211 "f2fs_io getflags [file]\n\n" \
212 "get a flag given the file\n" \
213 "flag can show \n" \
214 " encryption\n" \
215 " nocow(pinned)\n" \
216 " inline_data\n" \
217 " verity\n" \
218 " casefold\n" \
219 " compression\n" \
220 " nocompression\n" \
221 " immutable\n"
222
do_getflags(int argc,char ** argv,const struct cmd_desc * cmd)223 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
224 {
225 long flag = 0;
226 int ret, fd;
227 int exist = 0;
228
229 if (argc != 2) {
230 fputs("Excess arguments\n\n", stderr);
231 fputs(cmd->cmd_help, stderr);
232 exit(1);
233 }
234
235 fd = xopen(argv[1], O_RDONLY, 0);
236
237 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
238 printf("get a flag on %s ret=%d, flags=", argv[1], ret);
239 if (flag & FS_CASEFOLD_FL) {
240 printf("casefold");
241 exist = 1;
242 }
243 if (flag & FS_COMPR_FL) {
244 if (exist)
245 printf(",");
246 printf("compression");
247 exist = 1;
248 }
249 if (flag & FS_NOCOMP_FL) {
250 if (exist)
251 printf(",");
252 printf("nocompression");
253 exist = 1;
254 }
255 if (flag & FS_ENCRYPT_FL) {
256 if (exist)
257 printf(",");
258 printf("encrypt");
259 exist = 1;
260 }
261 if (flag & FS_VERITY_FL) {
262 if (exist)
263 printf(",");
264 printf("verity");
265 exist = 1;
266 }
267 if (flag & FS_INLINE_DATA_FL) {
268 if (exist)
269 printf(",");
270 printf("inline_data");
271 exist = 1;
272 }
273 if (flag & FS_NOCOW_FL) {
274 if (exist)
275 printf(",");
276 printf("nocow(pinned)");
277 exist = 1;
278 }
279 if (flag & FS_IMMUTABLE_FL) {
280 if (exist)
281 printf(",");
282 printf("immutable");
283 exist = 1;
284 }
285 if (!exist)
286 printf("none");
287 printf("\n");
288 exit(0);
289 }
290
291 #define setflags_desc "setflags ioctl"
292 #define setflags_help \
293 "f2fs_io setflags [flag] [file]\n\n" \
294 "set a flag given the file\n" \
295 "flag can be\n" \
296 " casefold\n" \
297 " compression\n" \
298 " nocompression\n" \
299 " noimmutable\n"
300
do_setflags(int argc,char ** argv,const struct cmd_desc * cmd)301 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
302 {
303 long flag = 0;
304 int ret, fd;
305
306 if (argc != 3) {
307 fputs("Excess arguments\n\n", stderr);
308 fputs(cmd->cmd_help, stderr);
309 exit(1);
310 }
311
312 fd = xopen(argv[2], O_RDONLY, 0);
313
314 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
315 printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
316 if (ret)
317 die_errno("F2FS_IOC_GETFLAGS failed");
318
319 if (!strcmp(argv[1], "casefold"))
320 flag |= FS_CASEFOLD_FL;
321 else if (!strcmp(argv[1], "compression"))
322 flag |= FS_COMPR_FL;
323 else if (!strcmp(argv[1], "nocompression"))
324 flag |= FS_NOCOMP_FL;
325 else if (!strcmp(argv[1], "noimmutable"))
326 flag &= ~FS_IMMUTABLE_FL;
327
328 ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
329 printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
330 exit(0);
331 }
332
333 #define shutdown_desc "shutdown filesystem"
334 #define shutdown_help \
335 "f2fs_io shutdown [level] [dir]\n\n" \
336 "Freeze and stop all IOs given mount point\n" \
337 "level can be\n" \
338 " 0 : going down with full sync\n" \
339 " 1 : going down with checkpoint only\n" \
340 " 2 : going down with no sync\n" \
341 " 3 : going down with metadata flush\n" \
342 " 4 : going down with fsck mark\n"
343
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)344 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
345 {
346 u32 flag;
347 int ret, fd;
348
349 if (argc != 3) {
350 fputs("Excess arguments\n\n", stderr);
351 fputs(cmd->cmd_help, stderr);
352 exit(1);
353 }
354
355 flag = atoi(argv[1]);
356 if (flag >= F2FS_GOING_DOWN_MAX) {
357 fputs("Wrong level\n\n", stderr);
358 fputs(cmd->cmd_help, stderr);
359 exit(1);
360 }
361 fd = xopen(argv[2], O_RDONLY, 0);
362
363 ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
364 if (ret < 0)
365 die_errno("F2FS_IOC_SHUTDOWN failed");
366
367 printf("Shutdown %s with level=%d\n", argv[2], flag);
368 exit(0);
369 }
370
371 #define pinfile_desc "pin file control"
372 #define pinfile_help \
373 "f2fs_io pinfile [get|set] [file]\n\n" \
374 "get/set pinning given the file\n" \
375
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)376 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
377 {
378 u32 pin;
379 int ret, fd;
380
381 if (argc != 3) {
382 fputs("Excess arguments\n\n", stderr);
383 fputs(cmd->cmd_help, stderr);
384 exit(1);
385 }
386
387 fd = xopen(argv[2], O_RDONLY, 0);
388
389 ret = -1;
390 if (!strcmp(argv[1], "set")) {
391 pin = 1;
392 ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
393 if (ret != 0)
394 die_errno("F2FS_IOC_SET_PIN_FILE failed");
395 printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
396 } else if (!strcmp(argv[1], "get")) {
397 unsigned int flags;
398
399 ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
400 if (ret < 0)
401 die_errno("F2FS_IOC_GET_PIN_FILE failed");
402
403 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
404 if (ret < 0)
405 die_errno("F2FS_IOC_GETFLAGS failed");
406
407 printf("get_pin_file: %s with %u blocks moved in %s\n",
408 (flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
409 pin, argv[2]);
410 }
411 exit(0);
412 }
413
414 #define fallocate_desc "fallocate"
415 #define fallocate_help \
416 "f2fs_io fallocate [keep_size] [offset] [length] [file]\n\n" \
417 "fallocate given the file\n" \
418 " [keep_size] : 1 or 0\n" \
419
do_fallocate(int argc,char ** argv,const struct cmd_desc * cmd)420 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
421 {
422 int fd;
423 off_t offset, length;
424 struct stat sb;
425 int mode = 0;
426
427 if (argc != 5) {
428 fputs("Excess arguments\n\n", stderr);
429 fputs(cmd->cmd_help, stderr);
430 exit(1);
431 }
432
433 if (!strcmp(argv[1], "1"))
434 mode |= FALLOC_FL_KEEP_SIZE;
435
436 offset = atoi(argv[2]);
437 length = atoll(argv[3]);
438
439 fd = xopen(argv[4], O_RDWR, 0);
440
441 if (fallocate(fd, mode, offset, length) != 0)
442 die_errno("fallocate failed");
443
444 if (fstat(fd, &sb) != 0)
445 die_errno("fstat failed");
446
447 printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
448 exit(0);
449 }
450
451 #define erase_desc "erase a block device"
452 #define erase_help \
453 "f2fs_io erase [block_device_path]\n\n" \
454 "Send DISCARD | BLKSECDISCARD comamnd to" \
455 "block device in block_device_path\n" \
456
do_erase(int argc,char ** argv,const struct cmd_desc * cmd)457 static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
458 {
459 int fd, ret;
460 struct stat st;
461 u64 range[2];
462
463 if (argc != 2) {
464 fputs("Excess arguments\n\n", stderr);
465 fputs(cmd->cmd_help, stderr);
466 exit(1);
467 }
468
469 if (stat(argv[1], &st) != 0) {
470 fputs("stat error\n", stderr);
471 exit(1);
472 }
473
474 if (!S_ISBLK(st.st_mode)) {
475 fputs(argv[1], stderr);
476 fputs(" is not a block device\n", stderr);
477 exit(1);
478 }
479
480 fd = xopen(argv[1], O_WRONLY, 0);
481
482 range[0] = 0;
483 ret = ioctl(fd, BLKGETSIZE64, &range[1]);
484 if (ret < 0) {
485 fputs("get size failed\n", stderr);
486 exit(1);
487 }
488
489 ret = ioctl(fd, BLKSECDISCARD, &range);
490 if (ret < 0) {
491 ret = ioctl(fd, BLKDISCARD, &range);
492 if (ret < 0) {
493 fputs("Discard failed\n", stderr);
494 exit(1);
495 }
496 }
497
498 exit(0);
499 }
500
501 #define write_desc "write data into file"
502 #define write_help \
503 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n" \
504 "Write given patten data in file_path\n" \
505 "pattern can be\n" \
506 " zero : zeros\n" \
507 " inc_num : incrementing numbers\n" \
508 " rand : random numbers\n" \
509 "IO can be\n" \
510 " buffered : buffered IO\n" \
511 " dio : O_DIRECT\n" \
512 " dsync : O_DIRECT | O_DSYNC\n" \
513 " osync : O_SYNC\n" \
514 " atomic_commit : atomic write & commit\n" \
515 " atomic_abort : atomic write & abort\n" \
516 " atomic_rcommit: atomic replace & commit\n" \
517 " atomic_rabort : atomic replace & abort\n" \
518 "{delay} is in ms unit and optional only for atomic operations\n"
519
do_write(int argc,char ** argv,const struct cmd_desc * cmd)520 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
521 {
522 u64 buf_size = 0, inc_num = 0, written = 0;
523 u64 offset;
524 char *buf = NULL;
525 unsigned bs, count, i;
526 int flags = 0;
527 int fd;
528 u64 total_time = 0, max_time = 0, max_time_t = 0;
529 bool atomic_commit = false, atomic_abort = false, replace = false;
530 int useconds = 0;
531
532 srand(time(0));
533
534 if (argc < 7 || argc > 8) {
535 fputs("Excess arguments\n\n", stderr);
536 fputs(cmd->cmd_help, stderr);
537 exit(1);
538 }
539
540 bs = atoi(argv[1]);
541 if (bs > 1024)
542 die("Too big chunk size - limit: 4MB");
543
544 buf_size = bs * 4096;
545
546 offset = atoi(argv[2]) * buf_size;
547
548 buf = aligned_xalloc(4096, buf_size);
549 count = atoi(argv[3]);
550
551 if (!strcmp(argv[4], "zero"))
552 memset(buf, 0, buf_size);
553 else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
554 die("Wrong pattern type");
555
556 if (!strcmp(argv[5], "dio")) {
557 flags |= O_DIRECT;
558 } else if (!strcmp(argv[5], "dsync")) {
559 flags |= O_DIRECT | O_DSYNC;
560 } else if (!strcmp(argv[5], "osync")) {
561 flags |= O_SYNC;
562 } else if (!strcmp(argv[5], "atomic_commit")) {
563 atomic_commit = true;
564 } else if (!strcmp(argv[5], "atomic_abort")) {
565 atomic_abort = true;
566 } else if (!strcmp(argv[5], "atomic_rcommit")) {
567 atomic_commit = true;
568 replace = true;
569 } else if (!strcmp(argv[5], "atomic_rabort")) {
570 atomic_abort = true;
571 replace = true;
572 } else if (strcmp(argv[5], "buffered")) {
573 die("Wrong IO type");
574 }
575
576 fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
577
578 if (atomic_commit || atomic_abort) {
579 int ret;
580
581 if (argc == 8)
582 useconds = atoi(argv[7]) * 1000;
583
584 if (replace)
585 ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE);
586 else
587 ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
588
589 if (ret < 0) {
590 fputs("setting atomic file mode failed\n", stderr);
591 exit(1);
592 }
593 }
594
595 total_time = get_current_us();
596 for (i = 0; i < count; i++) {
597 uint64_t ret;
598
599 if (!strcmp(argv[4], "inc_num"))
600 *(int *)buf = inc_num++;
601 else if (!strcmp(argv[4], "rand"))
602 *(int *)buf = rand();
603
604 /* write data */
605 max_time_t = get_current_us();
606 ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
607 max_time_t = get_current_us() - max_time_t;
608 if (max_time < max_time_t)
609 max_time = max_time_t;
610 if (ret != buf_size)
611 break;
612 written += ret;
613 }
614
615 if (useconds)
616 usleep(useconds);
617
618 if (atomic_commit) {
619 int ret;
620
621 ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
622 if (ret < 0) {
623 fputs("committing atomic write failed\n", stderr);
624 exit(1);
625 }
626 } else if (atomic_abort) {
627 int ret;
628
629 ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
630 if (ret < 0) {
631 fputs("aborting atomic write failed\n", stderr);
632 exit(1);
633 }
634 }
635
636 printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
637 written, argv[4],
638 get_current_us() - total_time,
639 max_time);
640 exit(0);
641 }
642
643 #define read_desc "read data from file"
644 #define read_help \
645 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n" \
646 "Read data in file_path and print nbytes\n" \
647 "IO can be\n" \
648 " buffered : buffered IO\n" \
649 " dio : direct IO\n" \
650 " mmap : mmap IO\n" \
651
do_read(int argc,char ** argv,const struct cmd_desc * cmd)652 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
653 {
654 u64 buf_size = 0, ret = 0, read_cnt = 0;
655 u64 offset;
656 char *buf = NULL;
657 char *data;
658 char *print_buf = NULL;
659 unsigned bs, count, i, print_bytes;
660 int flags = 0;
661 int do_mmap = 0;
662 int fd;
663
664 if (argc != 7) {
665 fputs("Excess arguments\n\n", stderr);
666 fputs(cmd->cmd_help, stderr);
667 exit(1);
668 }
669
670 bs = atoi(argv[1]);
671 if (bs > 1024)
672 die("Too big chunk size - limit: 4MB");
673 buf_size = bs * 4096;
674
675 offset = atoi(argv[2]) * buf_size;
676
677 buf = aligned_xalloc(4096, buf_size);
678
679 count = atoi(argv[3]);
680 if (!strcmp(argv[4], "dio"))
681 flags |= O_DIRECT;
682 else if (!strcmp(argv[4], "mmap"))
683 do_mmap = 1;
684 else if (strcmp(argv[4], "buffered"))
685 die("Wrong IO type");
686
687 print_bytes = atoi(argv[5]);
688 if (print_bytes > buf_size)
689 die("Print_nbytes should be less then chunk_size in kb");
690
691 print_buf = xmalloc(print_bytes);
692
693 fd = xopen(argv[6], O_RDONLY | flags, 0);
694
695 if (do_mmap) {
696 data = mmap(NULL, count * buf_size, PROT_READ,
697 MAP_SHARED, fd, offset);
698 if (data == MAP_FAILED)
699 die("Mmap failed");
700 }
701
702 for (i = 0; i < count; i++) {
703 if (do_mmap) {
704 memcpy(buf, data + offset + buf_size * i, buf_size);
705 ret = buf_size;
706 } else {
707 ret = pread(fd, buf, buf_size, offset + buf_size * i);
708 }
709 if (ret != buf_size)
710 break;
711
712 read_cnt += ret;
713 if (i == 0)
714 memcpy(print_buf, buf, print_bytes);
715 }
716 printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
717 printf("%08"PRIx64" : ", offset);
718 for (i = 1; i <= print_bytes; i++) {
719 printf("%02x", print_buf[i - 1]);
720 if (i % 16 == 0)
721 printf("\n%08"PRIx64" : ", offset + 16 * i);
722 else if (i % 2 == 0)
723 printf(" ");
724 }
725 printf("\n");
726 exit(0);
727 }
728
729 #define randread_desc "random read data from file"
730 #define randread_help \
731 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n" \
732 "Do random read data in file_path\n" \
733 "IO can be\n" \
734 " buffered : buffered IO\n" \
735 " dio : direct IO\n" \
736
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)737 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
738 {
739 u64 buf_size = 0, ret = 0, read_cnt = 0;
740 u64 idx, end_idx, aligned_size;
741 char *buf = NULL;
742 unsigned bs, count, i;
743 int flags = 0;
744 int fd;
745 time_t t;
746 struct stat stbuf;
747
748 if (argc != 5) {
749 fputs("Excess arguments\n\n", stderr);
750 fputs(cmd->cmd_help, stderr);
751 exit(1);
752 }
753
754 bs = atoi(argv[1]);
755 if (bs > 1024)
756 die("Too big chunk size - limit: 4MB");
757 buf_size = bs * 4096;
758
759 buf = aligned_xalloc(4096, buf_size);
760
761 count = atoi(argv[2]);
762 if (!strcmp(argv[3], "dio"))
763 flags |= O_DIRECT;
764 else if (strcmp(argv[3], "buffered"))
765 die("Wrong IO type");
766
767 fd = xopen(argv[4], O_RDONLY | flags, 0);
768
769 if (fstat(fd, &stbuf) != 0)
770 die_errno("fstat of source file failed");
771
772 aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
773 if (aligned_size < buf_size)
774 die("File is too small to random read");
775 end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
776
777 srand((unsigned) time(&t));
778
779 for (i = 0; i < count; i++) {
780 idx = rand() % end_idx;
781
782 ret = pread(fd, buf, buf_size, 4096 * idx);
783 if (ret != buf_size)
784 break;
785
786 read_cnt += ret;
787 }
788 printf("Read %"PRIu64" bytes\n", read_cnt);
789 exit(0);
790 }
791
792 #define fiemap_desc "get block address in file"
793 #define fiemap_help \
794 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
795
796 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)797 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
798 {
799 unsigned int i;
800 int fd, extents_mem_size;
801 u64 start, length;
802 u32 mapped_extents;
803 struct fiemap *fm = xmalloc(sizeof(struct fiemap));
804
805 if (argc != 4) {
806 fputs("Excess arguments\n\n", stderr);
807 fputs(cmd->cmd_help, stderr);
808 exit(1);
809 }
810
811 memset(fm, 0, sizeof(struct fiemap));
812 start = atoi(argv[1]) * F2FS_BLKSIZE;
813 length = atoi(argv[2]) * F2FS_BLKSIZE;
814 fm->fm_start = start;
815 fm->fm_length = length;
816
817 fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
818
819 printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
820 start / F2FS_BLKSIZE, length / F2FS_BLKSIZE);
821 if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
822 die_errno("FIEMAP failed");
823
824 mapped_extents = fm->fm_mapped_extents;
825 extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
826 free(fm);
827 fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
828
829 memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
830 fm->fm_start = start;
831 fm->fm_length = length;
832 fm->fm_extent_count = mapped_extents;
833
834 if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
835 die_errno("FIEMAP failed");
836
837 printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
838 for (i = 0; i < fm->fm_mapped_extents; i++) {
839 printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
840 fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
841 fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
842
843 if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
844 break;
845 }
846 printf("\n");
847 free(fm);
848 exit(0);
849 }
850 #else
do_fiemap(int UNUSED (argc),char ** UNUSED (argv),const struct cmd_desc * UNUSED (cmd))851 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
852 const struct cmd_desc *UNUSED(cmd))
853 {
854 die("Not support for this platform");
855 }
856 #endif
857
858 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
859 #define gc_urgent_help \
860 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
861 " - f2fs_io gc_urgent sda21 start\n" \
862 " - f2fs_io gc_urgent sda21 end\n" \
863 " - f2fs_io gc_urgent sda21 run 10\n" \
864
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)865 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
866 {
867 char command[255];
868
869 if (argc == 3 && !strcmp(argv[2], "start")) {
870 printf("gc_urgent: start on %s\n", argv[1]);
871 sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
872 if (system(command))
873 exit(1);
874 } else if (argc == 3 && !strcmp(argv[2], "end")) {
875 printf("gc_urgent: end on %s\n", argv[1]);
876 sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
877 if (system(command))
878 exit(1);
879 } else if (argc == 4 && !strcmp(argv[2], "run")) {
880 printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
881 sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
882 if (system(command))
883 exit(1);
884 sleep(atoi(argv[3]));
885 printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
886 sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
887 if (system(command))
888 exit(1);
889 } else {
890 fputs("Excess arguments\n\n", stderr);
891 fputs(cmd->cmd_help, stderr);
892 exit(1);
893 }
894 }
895
896 #define defrag_file_desc "do defragment on file"
897 #define defrag_file_help \
898 "f2fs_io defrag_file [start] [length] [file_path]\n\n" \
899 " start : start offset of defragment region, unit: bytes\n" \
900 " length : bytes number of defragment region\n" \
901
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)902 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
903 {
904 struct f2fs_defragment df;
905 u64 len;
906 int ret, fd;
907
908 if (argc != 4) {
909 fputs("Excess arguments\n\n", stderr);
910 fputs(cmd->cmd_help, stderr);
911 exit(1);
912 }
913
914 df.start = atoll(argv[1]);
915 df.len = len = atoll(argv[2]);
916
917 fd = xopen(argv[3], O_RDWR, 0);
918
919 ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
920 if (ret < 0)
921 die_errno("F2FS_IOC_DEFRAGMENT failed");
922
923 printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
924 argv[3], df.start, df.start + len);
925 exit(0);
926 }
927
928 #define copy_desc "copy a file"
929 #define copy_help \
930 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n" \
931 " src_path : path to source file\n" \
932 " dst_path : path to destination file\n" \
933 " -d : use direct I/O\n" \
934 " -m : mmap the source file\n" \
935 " -s : use sendfile\n" \
936
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)937 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
938 {
939 int c;
940 int src_fd;
941 int dst_fd;
942 int open_flags = 0;
943 bool mmap_source_file = false;
944 bool use_sendfile = false;
945 ssize_t ret;
946
947 while ((c = getopt(argc, argv, "dms")) != -1) {
948 switch (c) {
949 case 'd':
950 open_flags |= O_DIRECT;
951 break;
952 case 'm':
953 mmap_source_file = true;
954 break;
955 case 's':
956 use_sendfile = true;
957 break;
958 default:
959 fputs(cmd->cmd_help, stderr);
960 exit(2);
961 }
962 }
963 argc -= optind;
964 argv += optind;
965 if (argc != 2) {
966 fputs("Wrong number of arguments\n\n", stderr);
967 fputs(cmd->cmd_help, stderr);
968 exit(2);
969 }
970 if (mmap_source_file && use_sendfile)
971 die("-m and -s are mutually exclusive");
972
973 src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
974 dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
975
976 if (mmap_source_file) {
977 struct stat stbuf;
978 void *src_addr;
979
980 if (fstat(src_fd, &stbuf) != 0)
981 die_errno("fstat of source file failed");
982
983 if ((size_t)stbuf.st_size != stbuf.st_size)
984 die("Source file is too large");
985
986 src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
987 src_fd, 0);
988 if (src_addr == MAP_FAILED)
989 die("mmap of source file failed");
990
991 full_write(dst_fd, src_addr, stbuf.st_size);
992
993 munmap(src_addr, stbuf.st_size);
994 } else if (use_sendfile) {
995 while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
996 ;
997 if (ret < 0)
998 die_errno("sendfile failed");
999 } else {
1000 char *buf = aligned_xalloc(4096, 4096);
1001
1002 while ((ret = xread(src_fd, buf, 4096)) > 0)
1003 full_write(dst_fd, buf, ret);
1004 free(buf);
1005 }
1006 close(src_fd);
1007 close(dst_fd);
1008 }
1009
1010 #define get_cblocks_desc "get number of reserved blocks on compress inode"
1011 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
1012
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1013 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1014 {
1015 unsigned long long blkcnt;
1016 int ret, fd;
1017
1018 if (argc != 2) {
1019 fputs("Excess arguments\n\n", stderr);
1020 fputs(cmd->cmd_help, stderr);
1021 exit(1);
1022 }
1023
1024 fd = xopen(argv[1], O_RDONLY, 0);
1025
1026 ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1027 if (ret < 0)
1028 die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1029
1030 printf("%llu\n", blkcnt);
1031
1032 exit(0);
1033 }
1034
1035 #define release_cblocks_desc "release reserved blocks on compress inode"
1036 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1037
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1038 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1039 {
1040 unsigned long long blkcnt;
1041 int ret, fd;
1042
1043 if (argc != 2) {
1044 fputs("Excess arguments\n\n", stderr);
1045 fputs(cmd->cmd_help, stderr);
1046 exit(1);
1047 }
1048
1049 fd = xopen(argv[1], O_RDONLY, 0);
1050
1051 ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1052 if (ret < 0)
1053 die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1054
1055 printf("%llu\n", blkcnt);
1056
1057 exit(0);
1058 }
1059
1060 #define reserve_cblocks_desc "reserve blocks on compress inode"
1061 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1062
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1063 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1064 {
1065 unsigned long long blkcnt;
1066 int ret, fd;
1067
1068 if (argc != 2) {
1069 fputs("Excess arguments\n\n", stderr);
1070 fputs(cmd->cmd_help, stderr);
1071 exit(1);
1072 }
1073
1074 fd = xopen(argv[1], O_RDONLY, 0);
1075
1076 ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1077 if (ret < 0)
1078 die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1079
1080 printf("%llu\n", blkcnt);
1081
1082 exit(0);
1083 }
1084
1085 #define get_coption_desc "get compression option of a compressed file"
1086 #define get_coption_help \
1087 "f2fs_io get_coption [file]\n\n" \
1088 " algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
1089 " log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1090
do_get_coption(int argc,char ** argv,const struct cmd_desc * cmd)1091 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1092 {
1093 struct f2fs_comp_option option;
1094 int ret, fd;
1095
1096 if (argc != 2) {
1097 fputs("Excess arguments\n\n", stderr);
1098 fputs(cmd->cmd_help, stderr);
1099 exit(1);
1100 }
1101
1102 fd = xopen(argv[1], O_RDONLY, 0);
1103
1104 ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1105 if (ret < 0)
1106 die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1107
1108 printf("compression algorithm:%u\n", option.algorithm);
1109 printf("compression cluster log size:%u\n", option.log_cluster_size);
1110
1111 exit(0);
1112 }
1113
1114 #define set_coption_desc "set compression option of a compressed file"
1115 #define set_coption_help \
1116 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n" \
1117 " algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
1118 " log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1119
do_set_coption(int argc,char ** argv,const struct cmd_desc * cmd)1120 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1121 {
1122 struct f2fs_comp_option option;
1123 int fd, ret;
1124
1125 if (argc != 4) {
1126 fputs("Excess arguments\n\n", stderr);
1127 fputs(cmd->cmd_help, stderr);
1128 exit(1);
1129 }
1130
1131 option.algorithm = atoi(argv[1]);
1132 option.log_cluster_size = atoi(argv[2]);
1133
1134 fd = xopen(argv[3], O_WRONLY, 0);
1135
1136 ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1137 if (ret < 0)
1138 die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1139
1140 printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1141 option.algorithm, option.log_cluster_size);
1142 exit(0);
1143 }
1144
1145 #define decompress_desc "decompress an already compressed file"
1146 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1147
do_decompress(int argc,char ** argv,const struct cmd_desc * cmd)1148 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1149 {
1150 int fd, ret;
1151
1152 if (argc != 2) {
1153 fputs("Excess arguments\n\n", stderr);
1154 fputs(cmd->cmd_help, stderr);
1155 exit(1);
1156 }
1157
1158 fd = xopen(argv[1], O_WRONLY, 0);
1159
1160 ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1161 if (ret < 0)
1162 die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1163
1164 exit(0);
1165 }
1166
1167 #define compress_desc "compress a compression enabled file"
1168 #define compress_help "f2fs_io compress [file_path]\n\n"
1169
do_compress(int argc,char ** argv,const struct cmd_desc * cmd)1170 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1171 {
1172 int fd, ret;
1173
1174 if (argc != 2) {
1175 fputs("Excess arguments\n\n", stderr);
1176 fputs(cmd->cmd_help, stderr);
1177 exit(1);
1178 }
1179
1180 fd = xopen(argv[1], O_WRONLY, 0);
1181
1182 ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1183 if (ret < 0)
1184 die_errno("F2FS_IOC_COMPRESS_FILE failed");
1185
1186 exit(0);
1187 }
1188
1189 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1190 #define get_filename_encrypt_mode_help \
1191 "f2fs_io filename_encrypt_mode [file or directory path]\n\n" \
1192 "Get the file name encription mode of the given file/directory.\n" \
1193
do_get_filename_encrypt_mode(int argc,char ** argv,const struct cmd_desc * cmd)1194 static void do_get_filename_encrypt_mode (int argc, char **argv,
1195 const struct cmd_desc *cmd)
1196 {
1197 static const char *enc_name[] = {
1198 "invalid", /* FSCRYPT_MODE_INVALID (0) */
1199 "aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */
1200 "aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */
1201 "aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */
1202 "aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */
1203 "aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */
1204 "aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */
1205 "speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */
1206 "speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */
1207 "adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */
1208 "aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */
1209 };
1210 int fd, mode, ret;
1211 struct fscrypt_get_policy_ex_arg arg;
1212
1213 if (argc != 2) {
1214 fputs("Excess arguments\n\n", stderr);
1215 fputs(cmd->cmd_help, stderr);
1216 exit(1);
1217 }
1218
1219 fd = xopen(argv[1], O_RDONLY, 0);
1220 arg.policy_size = sizeof(arg.policy);
1221 ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1222 if (ret != 0 && errno == ENOTTY)
1223 ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1224 close(fd);
1225
1226 if (ret) {
1227 perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1228 exit(1);
1229 }
1230
1231 switch (arg.policy.version) {
1232 case FSCRYPT_POLICY_V1:
1233 mode = arg.policy.v1.filenames_encryption_mode;
1234 break;
1235 case FSCRYPT_POLICY_V2:
1236 mode = arg.policy.v2.filenames_encryption_mode;
1237 break;
1238 default:
1239 printf("Do not support policy version: %d\n",
1240 arg.policy.version);
1241 exit(1);
1242 }
1243
1244 if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1245 printf("Do not support algorithm: %d\n", mode);
1246 exit(1);
1247 }
1248 printf ("%s\n", enc_name[mode]);
1249 exit(0);
1250 }
1251
1252 #define rename_desc "rename source to target file with fsync option"
1253 #define rename_help \
1254 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n" \
1255 "e.g., f2fs_io rename source dest 1\n" \
1256 " 1. open(source)\n" \
1257 " 2. rename(source, dest)\n" \
1258 " 3. fsync(source)\n" \
1259 " 4. close(source)\n"
1260
do_rename(int argc,char ** argv,const struct cmd_desc * cmd)1261 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1262 {
1263 int fd = -1;
1264 int ret;
1265
1266 if (argc != 4) {
1267 fputs("Excess arguments\n\n", stderr);
1268 fputs(cmd->cmd_help, stderr);
1269 exit(1);
1270 }
1271
1272 if (atoi(argv[3]))
1273 fd = xopen(argv[1], O_WRONLY, 0);
1274
1275 ret = rename(argv[1], argv[2]);
1276 if (ret < 0)
1277 die_errno("rename failed");
1278
1279 if (fd >= 0) {
1280 if (fsync(fd) != 0)
1281 die_errno("fsync failed: %s", argv[1]);
1282 close(fd);
1283 }
1284 exit(0);
1285 }
1286
1287 #define gc_desc "trigger filesystem GC"
1288 #define gc_help "f2fs_io gc sync_mode [file_path]\n\n"
1289
do_gc(int argc,char ** argv,const struct cmd_desc * cmd)1290 static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
1291 {
1292 u32 sync;
1293 int ret, fd;
1294
1295 if (argc != 3) {
1296 fputs("Excess arguments\n\n", stderr);
1297 fputs(cmd->cmd_help, stderr);
1298 exit(1);
1299 }
1300
1301 sync = atoi(argv[1]);
1302
1303 fd = xopen(argv[2], O_RDONLY, 0);
1304
1305 ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync);
1306 if (ret < 0)
1307 die_errno("F2FS_IOC_GARBAGE_COLLECT failed");
1308
1309 printf("trigger %s gc ret=%d\n",
1310 sync ? "synchronous" : "asynchronous", ret);
1311 exit(0);
1312 }
1313
1314 #define CMD_HIDDEN 0x0001
1315 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1316 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1317
1318 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1319 const struct cmd_desc cmd_list[] = {
1320 _CMD(help),
1321 CMD(fsync),
1322 CMD(set_verity),
1323 CMD(getflags),
1324 CMD(setflags),
1325 CMD(shutdown),
1326 CMD(pinfile),
1327 CMD(fallocate),
1328 CMD(erase),
1329 CMD(write),
1330 CMD(read),
1331 CMD(randread),
1332 CMD(fiemap),
1333 CMD(gc_urgent),
1334 CMD(defrag_file),
1335 CMD(copy),
1336 CMD(get_cblocks),
1337 CMD(release_cblocks),
1338 CMD(reserve_cblocks),
1339 CMD(get_coption),
1340 CMD(set_coption),
1341 CMD(decompress),
1342 CMD(compress),
1343 CMD(get_filename_encrypt_mode),
1344 CMD(rename),
1345 CMD(gc),
1346 { NULL, NULL, NULL, NULL, 0 }
1347 };
1348
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))1349 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1350 {
1351 const struct cmd_desc *p;
1352
1353 if (argc > 1) {
1354 for (p = cmd_list; p->cmd_name; p++) {
1355 if (p->cmd_flags & CMD_HIDDEN)
1356 continue;
1357 if (strcmp(p->cmd_name, argv[1]) == 0) {
1358 putc('\n', stdout);
1359 fputs("USAGE:\n ", stdout);
1360 fputs(p->cmd_help, stdout);
1361 exit(0);
1362 }
1363 }
1364 printf("Unknown command: %s\n\n", argv[1]);
1365 }
1366
1367 fputs("Available commands:\n", stdout);
1368 for (p = cmd_list; p->cmd_name; p++) {
1369 if (p->cmd_flags & CMD_HIDDEN)
1370 continue;
1371 printf(" %-20s %s\n", p->cmd_name, p->cmd_desc);
1372 }
1373 printf("\nTo get more information on a command, "
1374 "type 'f2fs_io help cmd'\n");
1375 exit(0);
1376 }
1377
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))1378 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1379 void *UNUSED(context))
1380 {
1381 exit(-1);
1382 }
1383
sigcatcher_setup(void)1384 static void sigcatcher_setup(void)
1385 {
1386 struct sigaction sa;
1387
1388 memset(&sa, 0, sizeof(struct sigaction));
1389 sa.sa_sigaction = die_signal_handler;
1390 sa.sa_flags = SA_SIGINFO;
1391
1392 sigaction(SIGHUP, &sa, 0);
1393 sigaction(SIGINT, &sa, 0);
1394 sigaction(SIGQUIT, &sa, 0);
1395 sigaction(SIGFPE, &sa, 0);
1396 sigaction(SIGILL, &sa, 0);
1397 sigaction(SIGBUS, &sa, 0);
1398 sigaction(SIGSEGV, &sa, 0);
1399 sigaction(SIGABRT, &sa, 0);
1400 sigaction(SIGPIPE, &sa, 0);
1401 sigaction(SIGALRM, &sa, 0);
1402 sigaction(SIGTERM, &sa, 0);
1403 sigaction(SIGUSR1, &sa, 0);
1404 sigaction(SIGUSR2, &sa, 0);
1405 sigaction(SIGPOLL, &sa, 0);
1406 sigaction(SIGPROF, &sa, 0);
1407 sigaction(SIGSYS, &sa, 0);
1408 sigaction(SIGTRAP, &sa, 0);
1409 sigaction(SIGVTALRM, &sa, 0);
1410 sigaction(SIGXCPU, &sa, 0);
1411 sigaction(SIGXFSZ, &sa, 0);
1412 }
1413
main(int argc,char ** argv)1414 int main(int argc, char **argv)
1415 {
1416 const struct cmd_desc *cmd;
1417
1418 if (argc < 2)
1419 do_help(argc, argv, cmd_list);
1420
1421 sigcatcher_setup();
1422 for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1423 if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1424 cmd->cmd_func(argc - 1, argv + 1, cmd);
1425 exit(0);
1426 }
1427 }
1428 printf("Unknown command: %s\n\n", argv[1]);
1429 do_help(1, argv, cmd_list);
1430 return 0;
1431 }
1432