• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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           : direct IO\n"				\
512 "  osync         : O_SYNC\n"				\
513 "  atomic_commit : atomic write & commit\n"		\
514 "  atomic_abort  : atomic write & abort\n"		\
515 "{delay} is in ms unit and optional only for atomic_commit and atomic_abort\n"
516 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)517 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
518 {
519 	u64 buf_size = 0, inc_num = 0, written = 0;
520 	u64 offset;
521 	char *buf = NULL;
522 	unsigned bs, count, i;
523 	int flags = 0;
524 	int fd;
525 	u64 total_time = 0, max_time = 0, max_time_t = 0;
526 	bool atomic_commit = false, atomic_abort = false;
527 	int useconds = 0;
528 
529 	srand(time(0));
530 
531 	if (argc < 7 || argc > 8) {
532 		fputs("Excess arguments\n\n", stderr);
533 		fputs(cmd->cmd_help, stderr);
534 		exit(1);
535 	}
536 
537 	bs = atoi(argv[1]);
538 	if (bs > 1024)
539 		die("Too big chunk size - limit: 4MB");
540 
541 	buf_size = bs * 4096;
542 
543 	offset = atoi(argv[2]) * buf_size;
544 
545 	buf = aligned_xalloc(4096, buf_size);
546 	count = atoi(argv[3]);
547 
548 	if (!strcmp(argv[4], "zero"))
549 		memset(buf, 0, buf_size);
550 	else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
551 		die("Wrong pattern type");
552 
553 	if (!strcmp(argv[5], "dio"))
554 		flags |= O_DIRECT;
555 	else if (!strcmp(argv[5], "osync"))
556 		flags |= O_SYNC;
557 	else if (!strcmp(argv[5], "atomic_commit"))
558 		atomic_commit = true;
559 	else if (!strcmp(argv[5], "atomic_abort"))
560 		atomic_abort = true;
561 	else if (strcmp(argv[5], "buffered"))
562 		die("Wrong IO type");
563 
564 	fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
565 
566 	if (atomic_commit || atomic_abort) {
567 		int ret;
568 
569 		if (argc == 8)
570 			useconds = atoi(argv[7]) * 1000;
571 
572 		ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
573 		if (ret < 0) {
574 			fputs("setting atomic file mode failed\n", stderr);
575 			exit(1);
576 		}
577 	}
578 
579 	total_time = get_current_us();
580 	for (i = 0; i < count; i++) {
581 		uint64_t ret;
582 
583 		if (!strcmp(argv[4], "inc_num"))
584 			*(int *)buf = inc_num++;
585 		else if (!strcmp(argv[4], "rand"))
586 			*(int *)buf = rand();
587 
588 		/* write data */
589 		max_time_t = get_current_us();
590 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
591 		max_time_t = get_current_us() - max_time_t;
592 		if (max_time < max_time_t)
593 			max_time = max_time_t;
594 		if (ret != buf_size)
595 			break;
596 		written += ret;
597 	}
598 
599 	if (useconds)
600 		usleep(useconds);
601 
602 	if (atomic_commit) {
603 		int ret;
604 
605 		ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
606 		if (ret < 0) {
607 			fputs("committing atomic write failed\n", stderr);
608 			exit(1);
609 		}
610 	} else if (atomic_abort) {
611 		int ret;
612 
613 		ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
614 		if (ret < 0) {
615 			fputs("aborting atomic write failed\n", stderr);
616 			exit(1);
617 		}
618 	}
619 
620 	printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
621 				written, argv[4],
622 				get_current_us() - total_time,
623 				max_time);
624 	exit(0);
625 }
626 
627 #define read_desc "read data from file"
628 #define read_help					\
629 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n"	\
630 "Read data in file_path and print nbytes\n"		\
631 "IO can be\n"						\
632 "  buffered : buffered IO\n"				\
633 "  dio      : direct IO\n"				\
634 "  mmap     : mmap IO\n"				\
635 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)636 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
637 {
638 	u64 buf_size = 0, ret = 0, read_cnt = 0;
639 	u64 offset;
640 	char *buf = NULL;
641 	char *data;
642 	char *print_buf = NULL;
643 	unsigned bs, count, i, print_bytes;
644 	int flags = 0;
645 	int do_mmap = 0;
646 	int fd;
647 
648 	if (argc != 7) {
649 		fputs("Excess arguments\n\n", stderr);
650 		fputs(cmd->cmd_help, stderr);
651 		exit(1);
652 	}
653 
654 	bs = atoi(argv[1]);
655 	if (bs > 1024)
656 		die("Too big chunk size - limit: 4MB");
657 	buf_size = bs * 4096;
658 
659 	offset = atoi(argv[2]) * buf_size;
660 
661 	buf = aligned_xalloc(4096, buf_size);
662 
663 	count = atoi(argv[3]);
664 	if (!strcmp(argv[4], "dio"))
665 		flags |= O_DIRECT;
666 	else if (!strcmp(argv[4], "mmap"))
667 		do_mmap = 1;
668 	else if (strcmp(argv[4], "buffered"))
669 		die("Wrong IO type");
670 
671 	print_bytes = atoi(argv[5]);
672 	if (print_bytes > buf_size)
673 		die("Print_nbytes should be less then chunk_size in kb");
674 
675 	print_buf = xmalloc(print_bytes);
676 
677 	fd = xopen(argv[6], O_RDONLY | flags, 0);
678 
679 	if (do_mmap) {
680 		data = mmap(NULL, count * buf_size, PROT_READ,
681 						MAP_SHARED, fd, offset);
682 		if (data == MAP_FAILED)
683 			die("Mmap failed");
684 	}
685 
686 	for (i = 0; i < count; i++) {
687 		if (do_mmap) {
688 			memcpy(buf, data + offset + buf_size * i, buf_size);
689 			ret = buf_size;
690 		} else {
691 			ret = pread(fd, buf, buf_size, offset + buf_size * i);
692 		}
693 		if (ret != buf_size)
694 			break;
695 
696 		read_cnt += ret;
697 		if (i == 0)
698 			memcpy(print_buf, buf, print_bytes);
699 	}
700 	printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
701 	printf("%08"PRIx64" : ", offset);
702 	for (i = 1; i <= print_bytes; i++) {
703 		printf("%02x", print_buf[i - 1]);
704 		if (i % 16 == 0)
705 			printf("\n%08"PRIx64" : ", offset + 16 * i);
706 		else if (i % 2 == 0)
707 			printf(" ");
708 	}
709 	printf("\n");
710 	exit(0);
711 }
712 
713 #define randread_desc "random read data from file"
714 #define randread_help					\
715 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n"	\
716 "Do random read data in file_path\n"		\
717 "IO can be\n"						\
718 "  buffered : buffered IO\n"				\
719 "  dio      : direct IO\n"				\
720 
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)721 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
722 {
723 	u64 buf_size = 0, ret = 0, read_cnt = 0;
724 	u64 idx, end_idx, aligned_size;
725 	char *buf = NULL;
726 	unsigned bs, count, i;
727 	int flags = 0;
728 	int fd;
729 	time_t t;
730 	struct stat stbuf;
731 
732 	if (argc != 5) {
733 		fputs("Excess arguments\n\n", stderr);
734 		fputs(cmd->cmd_help, stderr);
735 		exit(1);
736 	}
737 
738 	bs = atoi(argv[1]);
739 	if (bs > 1024)
740 		die("Too big chunk size - limit: 4MB");
741 	buf_size = bs * 4096;
742 
743 	buf = aligned_xalloc(4096, buf_size);
744 
745 	count = atoi(argv[2]);
746 	if (!strcmp(argv[3], "dio"))
747 		flags |= O_DIRECT;
748 	else if (strcmp(argv[3], "buffered"))
749 		die("Wrong IO type");
750 
751 	fd = xopen(argv[4], O_RDONLY | flags, 0);
752 
753 	if (fstat(fd, &stbuf) != 0)
754 		die_errno("fstat of source file failed");
755 
756 	aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
757 	if (aligned_size < buf_size)
758 		die("File is too small to random read");
759 	end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
760 
761 	srand((unsigned) time(&t));
762 
763 	for (i = 0; i < count; i++) {
764 		idx = rand() % end_idx;
765 
766 		ret = pread(fd, buf, buf_size, 4096 * idx);
767 		if (ret != buf_size)
768 			break;
769 
770 		read_cnt += ret;
771 	}
772 	printf("Read %"PRIu64" bytes\n", read_cnt);
773 	exit(0);
774 }
775 
776 #define fiemap_desc "get block address in file"
777 #define fiemap_help					\
778 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
779 
780 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)781 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
782 {
783 	unsigned int i;
784 	int fd, extents_mem_size;
785 	u64 start, length;
786 	u32 mapped_extents;
787 	struct fiemap *fm = xmalloc(sizeof(struct fiemap));
788 
789 	if (argc != 4) {
790 		fputs("Excess arguments\n\n", stderr);
791 		fputs(cmd->cmd_help, stderr);
792 		exit(1);
793 	}
794 
795 	memset(fm, 0, sizeof(struct fiemap));
796 	start = atoi(argv[1]) * F2FS_BLKSIZE;
797 	length = atoi(argv[2]) * F2FS_BLKSIZE;
798 	fm->fm_start = start;
799 	fm->fm_length = length;
800 
801 	fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
802 
803 	printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
804 				start / F2FS_BLKSIZE, length / F2FS_BLKSIZE);
805 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
806 		die_errno("FIEMAP failed");
807 
808 	mapped_extents = fm->fm_mapped_extents;
809 	extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
810 	free(fm);
811 	fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
812 
813 	memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
814 	fm->fm_start = start;
815 	fm->fm_length = length;
816 	fm->fm_extent_count = mapped_extents;
817 
818 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
819 		die_errno("FIEMAP failed");
820 
821 	printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
822 	for (i = 0; i < fm->fm_mapped_extents; i++) {
823 		printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
824 		    fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
825 		    fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
826 
827 		if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
828 			break;
829 	}
830 	printf("\n");
831 	free(fm);
832 	exit(0);
833 }
834 #else
do_fiemap(int UNUSED (argc),char ** UNUSED (argv),const struct cmd_desc * UNUSED (cmd))835 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
836 			const struct cmd_desc *UNUSED(cmd))
837 {
838 	die("Not support for this platform");
839 }
840 #endif
841 
842 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
843 #define gc_urgent_help					\
844 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
845 " - f2fs_io gc_urgent sda21 start\n"		\
846 " - f2fs_io gc_urgent sda21 end\n"		\
847 " - f2fs_io gc_urgent sda21 run 10\n"		\
848 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)849 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
850 {
851 	char command[255];
852 
853 	if (argc == 3 && !strcmp(argv[2], "start")) {
854 		printf("gc_urgent: start on %s\n", argv[1]);
855 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
856 		if (system(command))
857 			exit(1);
858 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
859 		printf("gc_urgent: end on %s\n", argv[1]);
860 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
861 		if (system(command))
862 			exit(1);
863 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
864 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
865 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
866 		if (system(command))
867 			exit(1);
868 		sleep(atoi(argv[3]));
869 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
870 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
871 		if (system(command))
872 			exit(1);
873 	} else {
874 		fputs("Excess arguments\n\n", stderr);
875 		fputs(cmd->cmd_help, stderr);
876 		exit(1);
877 	}
878 }
879 
880 #define defrag_file_desc "do defragment on file"
881 #define defrag_file_help						\
882 "f2fs_io defrag_file [start] [length] [file_path]\n\n"		\
883 "  start     : start offset of defragment region, unit: bytes\n"	\
884 "  length    : bytes number of defragment region\n"			\
885 
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)886 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
887 {
888 	struct f2fs_defragment df;
889 	u64 len;
890 	int ret, fd;
891 
892 	if (argc != 4) {
893 		fputs("Excess arguments\n\n", stderr);
894 		fputs(cmd->cmd_help, stderr);
895 		exit(1);
896 	}
897 
898 	df.start = atoll(argv[1]);
899 	df.len = len = atoll(argv[2]);
900 
901 	fd = xopen(argv[3], O_RDWR, 0);
902 
903 	ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
904 	if (ret < 0)
905 		die_errno("F2FS_IOC_DEFRAGMENT failed");
906 
907 	printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
908 			argv[3], df.start, df.start + len);
909 	exit(0);
910 }
911 
912 #define copy_desc "copy a file"
913 #define copy_help							\
914 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n"			\
915 "  src_path  : path to source file\n"					\
916 "  dst_path  : path to destination file\n"				\
917 "  -d        : use direct I/O\n"					\
918 "  -m        : mmap the source file\n"					\
919 "  -s        : use sendfile\n"						\
920 
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)921 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
922 {
923 	int c;
924 	int src_fd;
925 	int dst_fd;
926 	int open_flags = 0;
927 	bool mmap_source_file = false;
928 	bool use_sendfile = false;
929 	ssize_t ret;
930 
931 	while ((c = getopt(argc, argv, "dms")) != -1) {
932 		switch (c) {
933 		case 'd':
934 			open_flags |= O_DIRECT;
935 			break;
936 		case 'm':
937 			mmap_source_file = true;
938 			break;
939 		case 's':
940 			use_sendfile = true;
941 			break;
942 		default:
943 			fputs(cmd->cmd_help, stderr);
944 			exit(2);
945 		}
946 	}
947 	argc -= optind;
948 	argv += optind;
949 	if (argc != 2) {
950 		fputs("Wrong number of arguments\n\n", stderr);
951 		fputs(cmd->cmd_help, stderr);
952 		exit(2);
953 	}
954 	if (mmap_source_file && use_sendfile)
955 		die("-m and -s are mutually exclusive");
956 
957 	src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
958 	dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
959 
960 	if (mmap_source_file) {
961 		struct stat stbuf;
962 		void *src_addr;
963 
964 		if (fstat(src_fd, &stbuf) != 0)
965 			die_errno("fstat of source file failed");
966 
967 		if ((size_t)stbuf.st_size != stbuf.st_size)
968 			die("Source file is too large");
969 
970 		src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
971 				src_fd, 0);
972 		if (src_addr == MAP_FAILED)
973 			die("mmap of source file failed");
974 
975 		full_write(dst_fd, src_addr, stbuf.st_size);
976 
977 		munmap(src_addr, stbuf.st_size);
978 	} else if (use_sendfile) {
979 		while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
980 			;
981 		if (ret < 0)
982 			die_errno("sendfile failed");
983 	} else {
984 		char *buf = aligned_xalloc(4096, 4096);
985 
986 		while ((ret = xread(src_fd, buf, 4096)) > 0)
987 			full_write(dst_fd, buf, ret);
988 		free(buf);
989 	}
990 	close(src_fd);
991 	close(dst_fd);
992 }
993 
994 #define get_cblocks_desc "get number of reserved blocks on compress inode"
995 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
996 
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)997 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
998 {
999 	unsigned long long blkcnt;
1000 	int ret, fd;
1001 
1002 	if (argc != 2) {
1003 		fputs("Excess arguments\n\n", stderr);
1004 		fputs(cmd->cmd_help, stderr);
1005 		exit(1);
1006 	}
1007 
1008 	fd = xopen(argv[1], O_RDONLY, 0);
1009 
1010 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1011 	if (ret < 0)
1012 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1013 
1014 	printf("%llu\n", blkcnt);
1015 
1016 	exit(0);
1017 }
1018 
1019 #define release_cblocks_desc "release reserved blocks on compress inode"
1020 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1021 
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1022 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1023 {
1024 	unsigned long long blkcnt;
1025 	int ret, fd;
1026 
1027 	if (argc != 2) {
1028 		fputs("Excess arguments\n\n", stderr);
1029 		fputs(cmd->cmd_help, stderr);
1030 		exit(1);
1031 	}
1032 
1033 	fd = xopen(argv[1], O_RDONLY, 0);
1034 
1035 	ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1036 	if (ret < 0)
1037 		die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1038 
1039 	printf("%llu\n", blkcnt);
1040 
1041 	exit(0);
1042 }
1043 
1044 #define reserve_cblocks_desc "reserve blocks on compress inode"
1045 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1046 
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1047 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1048 {
1049 	unsigned long long blkcnt;
1050 	int ret, fd;
1051 
1052 	if (argc != 2) {
1053 		fputs("Excess arguments\n\n", stderr);
1054 		fputs(cmd->cmd_help, stderr);
1055 		exit(1);
1056 	}
1057 
1058 	fd = xopen(argv[1], O_RDONLY, 0);
1059 
1060 	ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1061 	if (ret < 0)
1062 		die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1063 
1064 	printf("%llu\n", blkcnt);
1065 
1066 	exit(0);
1067 }
1068 
1069 #define get_coption_desc "get compression option of a compressed file"
1070 #define get_coption_help						\
1071 "f2fs_io get_coption [file]\n\n"	\
1072 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1073 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1074 
do_get_coption(int argc,char ** argv,const struct cmd_desc * cmd)1075 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1076 {
1077 	struct f2fs_comp_option option;
1078 	int ret, fd;
1079 
1080 	if (argc != 2) {
1081 		fputs("Excess arguments\n\n", stderr);
1082 		fputs(cmd->cmd_help, stderr);
1083 		exit(1);
1084 	}
1085 
1086 	fd = xopen(argv[1], O_RDONLY, 0);
1087 
1088 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1089 	if (ret < 0)
1090 		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1091 
1092 	printf("compression algorithm:%u\n", option.algorithm);
1093 	printf("compression cluster log size:%u\n", option.log_cluster_size);
1094 
1095 	exit(0);
1096 }
1097 
1098 #define set_coption_desc "set compression option of a compressed file"
1099 #define set_coption_help						\
1100 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n"	\
1101 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1102 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1103 
do_set_coption(int argc,char ** argv,const struct cmd_desc * cmd)1104 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1105 {
1106 	struct f2fs_comp_option option;
1107 	int fd, ret;
1108 
1109 	if (argc != 4) {
1110 		fputs("Excess arguments\n\n", stderr);
1111 		fputs(cmd->cmd_help, stderr);
1112 		exit(1);
1113 	}
1114 
1115 	option.algorithm = atoi(argv[1]);
1116 	option.log_cluster_size = atoi(argv[2]);
1117 
1118 	fd = xopen(argv[3], O_WRONLY, 0);
1119 
1120 	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1121 	if (ret < 0)
1122 		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1123 
1124 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1125 			option.algorithm, option.log_cluster_size);
1126 	exit(0);
1127 }
1128 
1129 #define decompress_desc "decompress an already compressed file"
1130 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1131 
do_decompress(int argc,char ** argv,const struct cmd_desc * cmd)1132 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1133 {
1134 	int fd, ret;
1135 
1136 	if (argc != 2) {
1137 		fputs("Excess arguments\n\n", stderr);
1138 		fputs(cmd->cmd_help, stderr);
1139 		exit(1);
1140 	}
1141 
1142 	fd = xopen(argv[1], O_WRONLY, 0);
1143 
1144 	ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1145 	if (ret < 0)
1146 		die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1147 
1148 	exit(0);
1149 }
1150 
1151 #define compress_desc "compress a compression enabled file"
1152 #define compress_help "f2fs_io compress [file_path]\n\n"
1153 
do_compress(int argc,char ** argv,const struct cmd_desc * cmd)1154 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1155 {
1156 	int fd, ret;
1157 
1158 	if (argc != 2) {
1159 		fputs("Excess arguments\n\n", stderr);
1160 		fputs(cmd->cmd_help, stderr);
1161 		exit(1);
1162 	}
1163 
1164 	fd = xopen(argv[1], O_WRONLY, 0);
1165 
1166 	ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1167 	if (ret < 0)
1168 		die_errno("F2FS_IOC_COMPRESS_FILE failed");
1169 
1170 	exit(0);
1171 }
1172 
1173 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1174 #define get_filename_encrypt_mode_help					\
1175 "f2fs_io filename_encrypt_mode [file or directory path]\n\n"		\
1176 "Get the file name encription mode of the given file/directory.\n"	\
1177 
do_get_filename_encrypt_mode(int argc,char ** argv,const struct cmd_desc * cmd)1178 static void do_get_filename_encrypt_mode (int argc, char **argv,
1179 						const struct cmd_desc *cmd)
1180 {
1181 	static const char *enc_name[] = {
1182 		"invalid", /* FS_ENCRYPTION_MODE_INVALID (0) */
1183 		"aes-256-xts", /* FS_ENCRYPTION_MODE_AES_256_XTS (1) */
1184 		"aes-256-gcm", /* FS_ENCRYPTION_MODE_AES_256_GCM (2) */
1185 		"aes-256-cbc", /* FS_ENCRYPTION_MODE_AES_256_CBC (3) */
1186 		"aes-256-cts", /* FS_ENCRYPTION_MODE_AES_256_CTS (4) */
1187 		"aes-128-cbc", /* FS_ENCRYPTION_MODE_AES_128_CBC (5) */
1188 		"aes-128-cts", /* FS_ENCRYPTION_MODE_AES_128_CTS (6) */
1189 		"speck128-256-xts", /* FS_ENCRYPTION_MODE_SPECK128_256_XTS (7) */
1190 		"speck128-256-cts", /* FS_ENCRYPTION_MODE_SPECK128_256_CTS (8) */
1191 		"adiantum", /* FS_ENCRYPTION_MODE_ADIANTUM (9) */
1192 	};
1193 	int fd, mode, ret;
1194 	struct fscrypt_get_policy_ex_arg arg;
1195 
1196 	if (argc != 2) {
1197 		fputs("Excess arguments\n\n", stderr);
1198 		fputs(cmd->cmd_help, stderr);
1199 		exit(1);
1200 	}
1201 
1202 	fd = xopen(argv[1], O_RDONLY, 0);
1203 	arg.policy_size = sizeof(arg.policy);
1204 	ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1205 	if (ret != 0 && errno == ENOTTY)
1206 		ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1207 	close(fd);
1208 
1209 	if (ret) {
1210 		perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1211 		exit(1);
1212 	}
1213 
1214 	switch (arg.policy.version) {
1215 	case FSCRYPT_POLICY_V1:
1216 		mode = arg.policy.v1.filenames_encryption_mode;
1217 		break;
1218 	case FSCRYPT_POLICY_V2:
1219 		mode = arg.policy.v2.filenames_encryption_mode;
1220 		break;
1221 	default:
1222 		printf("Do not support policy version: %d\n",
1223 							arg.policy.version);
1224 		exit(1);
1225 	}
1226 
1227 	if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1228 		printf("Do not support algorithm: %d\n", mode);
1229 		exit(1);
1230 	}
1231 	printf ("%s\n", enc_name[mode]);
1232 	exit(0);
1233 }
1234 
1235 #define rename_desc "rename source to target file with fsync option"
1236 #define rename_help							\
1237 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n"	\
1238 "e.g., f2fs_io rename source dest 1\n"					\
1239 "      1. open(source)\n"						\
1240 "      2. rename(source, dest)\n"					\
1241 "      3. fsync(source)\n"						\
1242 "      4. close(source)\n"
1243 
do_rename(int argc,char ** argv,const struct cmd_desc * cmd)1244 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1245 {
1246 	int fd = -1;
1247 	int ret;
1248 
1249 	if (argc != 4) {
1250 		fputs("Excess arguments\n\n", stderr);
1251 		fputs(cmd->cmd_help, stderr);
1252 		exit(1);
1253 	}
1254 
1255 	if (atoi(argv[3]))
1256 		fd = xopen(argv[1], O_WRONLY, 0);
1257 
1258 	ret = rename(argv[1], argv[2]);
1259 	if (ret < 0)
1260 		die_errno("rename failed");
1261 
1262 	if (fd >= 0) {
1263 		if (fsync(fd) != 0)
1264 			die_errno("fsync failed: %s", argv[1]);
1265 		close(fd);
1266 	}
1267 	exit(0);
1268 }
1269 
1270 #define CMD_HIDDEN 	0x0001
1271 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1272 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1273 
1274 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1275 const struct cmd_desc cmd_list[] = {
1276 	_CMD(help),
1277 	CMD(fsync),
1278 	CMD(set_verity),
1279 	CMD(getflags),
1280 	CMD(setflags),
1281 	CMD(shutdown),
1282 	CMD(pinfile),
1283 	CMD(fallocate),
1284 	CMD(erase),
1285 	CMD(write),
1286 	CMD(read),
1287 	CMD(randread),
1288 	CMD(fiemap),
1289 	CMD(gc_urgent),
1290 	CMD(defrag_file),
1291 	CMD(copy),
1292 	CMD(get_cblocks),
1293 	CMD(release_cblocks),
1294 	CMD(reserve_cblocks),
1295 	CMD(get_coption),
1296 	CMD(set_coption),
1297 	CMD(decompress),
1298 	CMD(compress),
1299 	CMD(get_filename_encrypt_mode),
1300 	CMD(rename),
1301 	{ NULL, NULL, NULL, NULL, 0 }
1302 };
1303 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))1304 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1305 {
1306 	const struct cmd_desc *p;
1307 
1308 	if (argc > 1) {
1309 		for (p = cmd_list; p->cmd_name; p++) {
1310 			if (p->cmd_flags & CMD_HIDDEN)
1311 				continue;
1312 			if (strcmp(p->cmd_name, argv[1]) == 0) {
1313 				putc('\n', stdout);
1314 				fputs("USAGE:\n  ", stdout);
1315 				fputs(p->cmd_help, stdout);
1316 				exit(0);
1317 			}
1318 		}
1319 		printf("Unknown command: %s\n\n", argv[1]);
1320 	}
1321 
1322 	fputs("Available commands:\n", stdout);
1323 	for (p = cmd_list; p->cmd_name; p++) {
1324 		if (p->cmd_flags & CMD_HIDDEN)
1325 			continue;
1326 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
1327 	}
1328 	printf("\nTo get more information on a command, "
1329 	       "type 'f2fs_io help cmd'\n");
1330 	exit(0);
1331 }
1332 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))1333 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1334 				void *UNUSED(context))
1335 {
1336 	exit(-1);
1337 }
1338 
sigcatcher_setup(void)1339 static void sigcatcher_setup(void)
1340 {
1341 	struct sigaction	sa;
1342 
1343 	memset(&sa, 0, sizeof(struct sigaction));
1344 	sa.sa_sigaction = die_signal_handler;
1345 	sa.sa_flags = SA_SIGINFO;
1346 
1347 	sigaction(SIGHUP, &sa, 0);
1348 	sigaction(SIGINT, &sa, 0);
1349 	sigaction(SIGQUIT, &sa, 0);
1350 	sigaction(SIGFPE, &sa, 0);
1351 	sigaction(SIGILL, &sa, 0);
1352 	sigaction(SIGBUS, &sa, 0);
1353 	sigaction(SIGSEGV, &sa, 0);
1354 	sigaction(SIGABRT, &sa, 0);
1355 	sigaction(SIGPIPE, &sa, 0);
1356 	sigaction(SIGALRM, &sa, 0);
1357 	sigaction(SIGTERM, &sa, 0);
1358 	sigaction(SIGUSR1, &sa, 0);
1359 	sigaction(SIGUSR2, &sa, 0);
1360 	sigaction(SIGPOLL, &sa, 0);
1361 	sigaction(SIGPROF, &sa, 0);
1362 	sigaction(SIGSYS, &sa, 0);
1363 	sigaction(SIGTRAP, &sa, 0);
1364 	sigaction(SIGVTALRM, &sa, 0);
1365 	sigaction(SIGXCPU, &sa, 0);
1366 	sigaction(SIGXFSZ, &sa, 0);
1367 }
1368 
main(int argc,char ** argv)1369 int main(int argc, char **argv)
1370 {
1371 	const struct cmd_desc *cmd;
1372 
1373 	if (argc < 2)
1374 		do_help(argc, argv, cmd_list);
1375 
1376 	sigcatcher_setup();
1377 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1378 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1379 			cmd->cmd_func(argc - 1, argv + 1, cmd);
1380 			exit(0);
1381 		}
1382 	}
1383 	printf("Unknown command: %s\n\n", argv[1]);
1384 	do_help(1, argv, cmd_list);
1385 	return 0;
1386 }
1387