• 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 O_LARGEFILE
13 #define O_LARGEFILE 0
14 #endif
15 #ifndef __SANE_USERSPACE_TYPES__
16 #define __SANE_USERSPACE_TYPES__       /* For PPC64, to get LL64 types */
17 #endif
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <inttypes.h>
23 #include <limits.h>
24 #include <linux/fs.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/mman.h>
32 #include <sys/sendfile.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <termios.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <sys/xattr.h>
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 #include <android_config.h>
44 
45 #include "f2fs_io.h"
46 
47 struct cmd_desc {
48 	const char *cmd_name;
49 	void (*cmd_func)(int, char **, const struct cmd_desc *);
50 	const char *cmd_desc;
51 	const char *cmd_help;
52 	int cmd_flags;
53 };
54 
55 static void __attribute__((noreturn))
do_die(const char * format,va_list va,int err)56 do_die(const char *format, va_list va, int err)
57 {
58 	vfprintf(stderr, format, va);
59 	if (err)
60 		fprintf(stderr, ": %s", strerror(err));
61 	putc('\n', stderr);
62 	exit(1);
63 }
64 
65 static void __attribute__((noreturn, format(printf, 1, 2)))
die_errno(const char * format,...)66 die_errno(const char *format, ...)
67 {
68 	va_list va;
69 
70 	va_start(va, format);
71 	do_die(format, va, errno);
72 	va_end(va);
73 }
74 
75 static void __attribute__((noreturn, format(printf, 1, 2)))
die(const char * format,...)76 die(const char *format, ...)
77 {
78 	va_list va;
79 
80 	va_start(va, format);
81 	do_die(format, va, 0);
82 	va_end(va);
83 }
84 
xmalloc(size_t size)85 static void *xmalloc(size_t size)
86 {
87 	void *p = malloc(size);
88 
89 	if (!p)
90 		die("Memory alloc failed (requested %zu bytes)", size);
91 	return p;
92 }
93 
aligned_xalloc(size_t alignment,size_t size)94 static void *aligned_xalloc(size_t alignment, size_t size)
95 {
96 	void *p = aligned_alloc(alignment, size);
97 
98 	if (!p)
99 		die("Memory alloc failed (requested %zu bytes)", size);
100 	return p;
101 }
102 
xopen(const char * pathname,int flags,mode_t mode)103 static int xopen(const char *pathname, int flags, mode_t mode)
104 {
105 	int fd = open(pathname, flags, mode);
106 
107 	if (fd < 0)
108 		die_errno("Failed to open %s", pathname);
109 	return fd;
110 }
111 
xread(int fd,void * buf,size_t count)112 static ssize_t xread(int fd, void *buf, size_t count)
113 {
114 	ssize_t ret = read(fd, buf, count);
115 
116 	if (ret < 0)
117 		die_errno("read failed");
118 	return ret;
119 }
120 
full_write(int fd,const void * buf,size_t count)121 static void full_write(int fd, const void *buf, size_t count)
122 {
123 	while (count) {
124 		ssize_t ret = write(fd, buf, count);
125 
126 		if (ret < 0)
127 			die_errno("write failed");
128 		buf = (char *)buf + ret;
129 		count -= ret;
130 	}
131 }
132 
133 #ifdef HAVE_MACH_TIME_H
get_current_us()134 static u64 get_current_us()
135 {
136 	return mach_absolute_time() / 1000;
137 }
138 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
get_current_us()139 static u64 get_current_us()
140 {
141 	struct timespec t;
142 	t.tv_sec = t.tv_nsec = 0;
143 	clock_gettime(CLOCK_BOOTTIME, &t);
144 	return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
145 }
146 #else
get_current_us()147 static u64 get_current_us()
148 {
149 	return 0;
150 }
151 #endif
152 
153 #define fsync_desc "fsync"
154 #define fsync_help						\
155 "f2fs_io fsync [file]\n\n"					\
156 "fsync given the file\n"					\
157 
do_fsync(int argc,char ** argv,const struct cmd_desc * cmd)158 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
159 {
160 	int fd;
161 
162 	if (argc != 2) {
163 		fputs("Excess arguments\n\n", stderr);
164 		fputs(cmd->cmd_help, stderr);
165 		exit(1);
166 	}
167 
168 	fd = xopen(argv[1], O_WRONLY, 0);
169 
170 	if (fsync(fd) != 0)
171 		die_errno("fsync failed");
172 
173 	printf("fsync a file\n");
174 	exit(0);
175 }
176 
177 #define set_verity_desc "Set fs-verity"
178 #define set_verity_help					\
179 "f2fs_io set_verity [file]\n\n"				\
180 "Set fsverity bit given a file\n"			\
181 
do_set_verity(int argc,char ** argv,const struct cmd_desc * cmd)182 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
183 {
184 	int ret, fd;
185 
186 	if (argc != 2) {
187 		fputs("Excess arguments\n\n", stderr);
188 		fputs(cmd->cmd_help, stderr);
189 		exit(1);
190 	}
191 
192 	fd = open(argv[1], O_RDWR);
193 
194 	ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
195 	if (ret < 0) {
196 		perror("FS_IOC_ENABLE_VERITY");
197 		exit(1);
198 	}
199 
200 	printf("Set fsverity bit to %s\n", argv[1]);
201 	exit(0);
202 }
203 
204 #define getflags_desc "getflags ioctl"
205 #define getflags_help						\
206 "f2fs_io getflags [file]\n\n"					\
207 "get a flag given the file\n"					\
208 "flag can show \n"						\
209 "  encryption\n"						\
210 "  nocow(pinned)\n"						\
211 "  inline_data\n"						\
212 "  verity\n"							\
213 "  casefold\n"							\
214 "  compression\n"						\
215 "  nocompression\n"						\
216 "  immutable\n"
217 
do_getflags(int argc,char ** argv,const struct cmd_desc * cmd)218 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
219 {
220 	long flag = 0;
221 	int ret, fd;
222 	int exist = 0;
223 
224 	if (argc != 2) {
225 		fputs("Excess arguments\n\n", stderr);
226 		fputs(cmd->cmd_help, stderr);
227 		exit(1);
228 	}
229 
230 	fd = xopen(argv[1], O_RDONLY, 0);
231 
232 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
233 	printf("get a flag on %s ret=%d, flags=", argv[1], ret);
234 	if (flag & FS_CASEFOLD_FL) {
235 		printf("casefold");
236 		exist = 1;
237 	}
238 	if (flag & FS_COMPR_FL) {
239 		if (exist)
240 			printf(",");
241 		printf("compression");
242 		exist = 1;
243 	}
244 	if (flag & FS_NOCOMP_FL) {
245 		if (exist)
246 			printf(",");
247 		printf("nocompression");
248 		exist = 1;
249 	}
250 	if (flag & FS_ENCRYPT_FL) {
251 		if (exist)
252 			printf(",");
253 		printf("encrypt");
254 		exist = 1;
255 	}
256 	if (flag & FS_VERITY_FL) {
257 		if (exist)
258 			printf(",");
259 		printf("verity");
260 		exist = 1;
261 	}
262 	if (flag & FS_INLINE_DATA_FL) {
263 		if (exist)
264 			printf(",");
265 		printf("inline_data");
266 		exist = 1;
267 	}
268 	if (flag & FS_NOCOW_FL) {
269 		if (exist)
270 			printf(",");
271 		printf("nocow(pinned)");
272 		exist = 1;
273 	}
274 	if (flag & FS_IMMUTABLE_FL) {
275 		if (exist)
276 			printf(",");
277 		printf("immutable");
278 		exist = 1;
279 	}
280 	if (!exist)
281 		printf("none");
282 	printf("\n");
283 	exit(0);
284 }
285 
286 #define setflags_desc "setflags ioctl"
287 #define setflags_help						\
288 "f2fs_io setflags [flag] [file]\n\n"				\
289 "set a flag given the file\n"					\
290 "flag can be\n"							\
291 "  casefold\n"							\
292 "  compression\n"						\
293 "  nocompression\n"						\
294 "  noimmutable\n"
295 
do_setflags(int argc,char ** argv,const struct cmd_desc * cmd)296 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
297 {
298 	long flag = 0;
299 	int ret, fd;
300 
301 	if (argc != 3) {
302 		fputs("Excess arguments\n\n", stderr);
303 		fputs(cmd->cmd_help, stderr);
304 		exit(1);
305 	}
306 
307 	fd = xopen(argv[2], O_RDONLY, 0);
308 
309 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
310 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
311 	if (ret)
312 		die_errno("F2FS_IOC_GETFLAGS failed");
313 
314 	if (!strcmp(argv[1], "casefold"))
315 		flag |= FS_CASEFOLD_FL;
316 	else if (!strcmp(argv[1], "compression"))
317 		flag |= FS_COMPR_FL;
318 	else if (!strcmp(argv[1], "nocompression"))
319 		flag |= FS_NOCOMP_FL;
320 	else if (!strcmp(argv[1], "noimmutable"))
321 		flag &= ~FS_IMMUTABLE_FL;
322 
323 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
324 	printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
325 	exit(0);
326 }
327 
328 #define clearflags_desc "clearflags ioctl"
329 #define clearflags_help						\
330 "f2fs_io clearflags [flag] [file]\n\n"				\
331 "clear a flag given the file\n"					\
332 "flag can be\n"							\
333 "  compression\n"						\
334 "  nocompression\n"						\
335 
do_clearflags(int argc,char ** argv,const struct cmd_desc * cmd)336 static void do_clearflags(int argc, char **argv, const struct cmd_desc *cmd)
337 {
338 	long flag = 0;
339 	int ret, fd;
340 
341 	if (argc != 3) {
342 		fputs("Excess arguments\n\n", stderr);
343 		fputs(cmd->cmd_help, stderr);
344 		exit(1);
345 	}
346 
347 	fd = xopen(argv[2], O_RDONLY, 0);
348 
349 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
350 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
351 	if (ret)
352 		die_errno("F2FS_IOC_GETFLAGS failed");
353 
354 	if (!strcmp(argv[1], "compression"))
355 		flag &= ~FS_COMPR_FL;
356 	else if (!strcmp(argv[1], "nocompression"))
357 		flag &= ~FS_NOCOMP_FL;
358 
359 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
360 	printf("clear a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
361 	exit(0);
362 }
363 
364 #define shutdown_desc "shutdown filesystem"
365 #define shutdown_help					\
366 "f2fs_io shutdown [level] [dir]\n\n"			\
367 "Freeze and stop all IOs given mount point\n"		\
368 "level can be\n"					\
369 "  0 : going down with full sync\n"			\
370 "  1 : going down with checkpoint only\n"		\
371 "  2 : going down with no sync\n"			\
372 "  3 : going down with metadata flush\n"		\
373 "  4 : going down with fsck mark\n"
374 
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)375 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
376 {
377 	u32 flag;
378 	int ret, fd;
379 
380 	if (argc != 3) {
381 		fputs("Excess arguments\n\n", stderr);
382 		fputs(cmd->cmd_help, stderr);
383 		exit(1);
384 	}
385 
386 	flag = atoi(argv[1]);
387 	if (flag >= F2FS_GOING_DOWN_MAX) {
388 		fputs("Wrong level\n\n", stderr);
389 		fputs(cmd->cmd_help, stderr);
390 		exit(1);
391 	}
392 	fd = xopen(argv[2], O_RDONLY, 0);
393 
394 	ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
395 	if (ret < 0)
396 		die_errno("F2FS_IOC_SHUTDOWN failed");
397 
398 	printf("Shutdown %s with level=%d\n", argv[2], flag);
399 	exit(0);
400 }
401 
402 #define fadvise_desc "fadvise"
403 #define fadvise_help						\
404 "f2fs_io fadvise [advice] [offset] [length] [file]\n\n"		\
405 "fadvice given the file\n"					\
406 "advice can be\n"						\
407 " willneed\n"							\
408 " sequential\n"							\
409 
do_fadvise(int argc,char ** argv,const struct cmd_desc * cmd)410 static void do_fadvise(int argc, char **argv, const struct cmd_desc *cmd)
411 {
412 	int fd, advice;
413 	off_t offset, length;
414 
415 	if (argc != 5) {
416 		fputs("Excess arguments\n\n", stderr);
417 		fputs(cmd->cmd_help, stderr);
418 		exit(1);
419 	}
420 
421 	fd = xopen(argv[4], O_RDWR, 0);
422 
423 	if (!strcmp(argv[1], "willneed")) {
424 		advice = POSIX_FADV_WILLNEED;
425 	} else if (!strcmp(argv[1], "sequential")) {
426 		advice = POSIX_FADV_SEQUENTIAL;
427 	} else {
428 		fputs("Wrong advice\n\n", stderr);
429 		fputs(cmd->cmd_help, stderr);
430 		exit(1);
431 	}
432 
433 	offset = atoi(argv[2]);
434 	length = atoll(argv[3]);
435 
436 	if (posix_fadvise(fd, offset, length, advice) != 0)
437 		die_errno("fadvise failed");
438 
439 	printf("fadvice %s to a file: %s\n", argv[1], argv[4]);
440 	exit(0);
441 }
442 
443 #define pinfile_desc "pin file control"
444 #define pinfile_help						\
445 "f2fs_io pinfile [get|set|unset] [file]\n\n"			\
446 "get/set pinning given the file\n"				\
447 
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)448 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
449 {
450 	u32 pin;
451 	int ret, fd;
452 
453 	if (argc != 3) {
454 		fputs("Excess arguments\n\n", stderr);
455 		fputs(cmd->cmd_help, stderr);
456 		exit(1);
457 	}
458 
459 	fd = xopen(argv[2], O_RDONLY, 0);
460 
461 	ret = -1;
462 	if (!strcmp(argv[1], "set")) {
463 		pin = 1;
464 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
465 		if (ret != 0)
466 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
467 		printf("%s pinfile: %u blocks moved in %s\n",
468 					argv[1], ret, argv[2]);
469 	} else if (!strcmp(argv[1], "unset")) {
470 		pin = 0;
471 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
472 		if (ret != 0)
473 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
474 		printf("%s pinfile in %s\n", argv[1], argv[2]);
475 	} else if (!strcmp(argv[1], "get")) {
476 		unsigned int flags;
477 
478 		ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
479 		if (ret < 0)
480 			die_errno("F2FS_IOC_GET_PIN_FILE failed");
481 
482 		ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
483 		if (ret < 0)
484 			die_errno("F2FS_IOC_GETFLAGS failed");
485 
486 		printf("get_pin_file: %s with %u blocks moved in %s\n",
487 				(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
488 				pin, argv[2]);
489 	}
490 	exit(0);
491 }
492 
493 #define fallocate_desc "fallocate"
494 #define fallocate_help						\
495 "f2fs_io fallocate [-c] [-i] [-p] [-z] [keep_size] [offset] [length] [file]\n\n"	\
496 "fallocate given the file\n"					\
497 " [keep_size] : 1 or 0\n"					\
498 " -c : collapse range\n"					\
499 " -i : insert range\n"						\
500 " -p : punch hole\n"						\
501 " -z : zero range\n"						\
502 
do_fallocate(int argc,char ** argv,const struct cmd_desc * cmd)503 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
504 {
505 	int fd;
506 	off_t offset, length;
507 	struct stat sb;
508 	int mode = 0;
509 	int c;
510 
511 	while ((c = getopt(argc, argv, "cipz")) != -1) {
512 		switch (c) {
513 		case 'c':
514 			mode |= FALLOC_FL_COLLAPSE_RANGE;
515 			break;
516 		case 'i':
517 			mode |= FALLOC_FL_INSERT_RANGE;
518 			break;
519 		case 'p':
520 			mode |= FALLOC_FL_PUNCH_HOLE;
521 			break;
522 		case 'z':
523 			mode |= FALLOC_FL_ZERO_RANGE;
524 			break;
525 		default:
526 			fputs(cmd->cmd_help, stderr);
527 			exit(2);
528 		}
529 	}
530 	argc -= optind;
531 	argv += optind;
532 
533 	if (argc != 4) {
534 		fputs("Excess arguments\n\n", stderr);
535 		fputs(cmd->cmd_help, stderr);
536 		exit(1);
537 	}
538 
539 	if (!strcmp(argv[0], "1"))
540 		mode |= FALLOC_FL_KEEP_SIZE;
541 
542 	offset = atoi(argv[1]);
543 	length = atoll(argv[2]);
544 
545 	fd = xopen(argv[3], O_RDWR, 0);
546 
547 	if (fallocate(fd, mode, offset, length) != 0)
548 		die_errno("fallocate failed");
549 
550 	if (fstat(fd, &sb) != 0)
551 		die_errno("fstat failed");
552 
553 	printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
554 	exit(0);
555 }
556 
557 #define erase_desc "erase a block device"
558 #define erase_help				\
559 "f2fs_io erase [block_device_path]\n\n"		\
560 "Send DISCARD | BLKSECDISCARD comamnd to"	\
561 "block device in block_device_path\n"		\
562 
do_erase(int argc,char ** argv,const struct cmd_desc * cmd)563 static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
564 {
565 	int fd, ret;
566 	struct stat st;
567 	u64 range[2];
568 
569 	if (argc != 2) {
570 		fputs("Excess arguments\n\n", stderr);
571 		fputs(cmd->cmd_help, stderr);
572 		exit(1);
573 	}
574 
575 	if (stat(argv[1], &st) != 0) {
576 		fputs("stat error\n", stderr);
577 		exit(1);
578 	}
579 
580 	if (!S_ISBLK(st.st_mode)) {
581 		fputs(argv[1], stderr);
582 		fputs(" is not a block device\n", stderr);
583 		exit(1);
584 	}
585 
586 	fd = xopen(argv[1], O_WRONLY, 0);
587 
588 	range[0] = 0;
589 	ret = ioctl(fd, BLKGETSIZE64, &range[1]);
590 	if (ret < 0) {
591 		fputs("get size failed\n", stderr);
592 		exit(1);
593 	}
594 
595 	ret = ioctl(fd, BLKSECDISCARD, &range);
596 	if (ret < 0) {
597 		ret = ioctl(fd, BLKDISCARD, &range);
598 		if (ret < 0) {
599 			fputs("Discard failed\n", stderr);
600 			exit(1);
601 		}
602 	}
603 
604 	exit(0);
605 }
606 
do_write_with_advice(int argc,char ** argv,const struct cmd_desc * cmd,bool with_advice)607 static void do_write_with_advice(int argc, char **argv,
608 			const struct cmd_desc *cmd, bool with_advice)
609 {
610 	u64 buf_size = 0, inc_num = 0, written = 0;
611 	u64 offset;
612 	char *buf = NULL;
613 	unsigned bs, count, i;
614 	int flags = 0;
615 	int fd;
616 	u64 total_time = 0, max_time = 0, max_time_t = 0;
617 	bool atomic_commit = false, atomic_abort = false, replace = false;
618 	int useconds = 0;
619 
620 	srand(time(0));
621 
622 	bs = atoi(argv[1]);
623 	if (bs > 1024)
624 		die("Too big chunk size - limit: 4MB");
625 
626 	buf_size = bs * 4096;
627 
628 	offset = atoi(argv[2]) * buf_size;
629 
630 	buf = aligned_xalloc(4096, buf_size);
631 	count = atoi(argv[3]);
632 
633 	if (!strcmp(argv[4], "zero"))
634 		memset(buf, 0, buf_size);
635 	else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
636 		die("Wrong pattern type");
637 
638 	if (!strcmp(argv[5], "dio")) {
639 		flags |= O_DIRECT;
640 	} else if (!strcmp(argv[5], "dsync")) {
641 		flags |= O_DIRECT | O_DSYNC;
642 	} else if (!strcmp(argv[5], "osync")) {
643 		flags |= O_SYNC;
644 	} else if (!strcmp(argv[5], "atomic_commit")) {
645 		atomic_commit = true;
646 	} else if (!strcmp(argv[5], "atomic_abort")) {
647 		atomic_abort = true;
648 	} else if (!strcmp(argv[5], "atomic_rcommit")) {
649 		atomic_commit = true;
650 		replace = true;
651 	} else if (!strcmp(argv[5], "atomic_rabort")) {
652 		atomic_abort = true;
653 		replace = true;
654 	} else if (strcmp(argv[5], "buffered")) {
655 		die("Wrong IO type");
656 	}
657 
658 	if (!with_advice) {
659 		fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
660 	} else {
661 		unsigned char advice;
662 		int ret;
663 
664 		if (!strcmp(argv[6], "hot"))
665 			advice = FADVISE_HOT_BIT;
666 		else if (!strcmp(argv[6], "cold"))
667 			advice = FADVISE_COLD_BIT;
668 		else
669 			die("Wrong Advise type");
670 
671 		fd = xopen(argv[7], O_CREAT | O_WRONLY | flags, 0755);
672 
673 		ret = fsetxattr(fd, F2FS_SYSTEM_ADVISE_NAME,
674 				    (char *)&advice, 1, XATTR_CREATE);
675 		if (ret) {
676 			fputs("fsetxattr advice failed\n", stderr);
677 			exit(1);
678 		}
679 	}
680 
681 	if (atomic_commit || atomic_abort) {
682 		int ret;
683 
684 		if (argc == 8)
685 			useconds = atoi(argv[7]) * 1000;
686 
687 		if (replace)
688 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE);
689 		else
690 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
691 
692 		if (ret < 0) {
693 			fputs("setting atomic file mode failed\n", stderr);
694 			exit(1);
695 		}
696 	}
697 
698 	total_time = get_current_us();
699 	for (i = 0; i < count; i++) {
700 		uint64_t ret;
701 
702 		if (!strcmp(argv[4], "inc_num"))
703 			*(int *)buf = inc_num++;
704 		else if (!strcmp(argv[4], "rand"))
705 			*(int *)buf = rand();
706 
707 		/* write data */
708 		max_time_t = get_current_us();
709 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
710 		max_time_t = get_current_us() - max_time_t;
711 		if (max_time < max_time_t)
712 			max_time = max_time_t;
713 		if (ret != buf_size)
714 			break;
715 		written += ret;
716 	}
717 
718 	if (useconds)
719 		usleep(useconds);
720 
721 	if (atomic_commit) {
722 		int ret;
723 
724 		ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
725 		if (ret < 0) {
726 			fputs("committing atomic write failed\n", stderr);
727 			exit(1);
728 		}
729 	} else if (atomic_abort) {
730 		int ret;
731 
732 		ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
733 		if (ret < 0) {
734 			fputs("aborting atomic write failed\n", stderr);
735 			exit(1);
736 		}
737 	}
738 
739 	printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
740 				written, argv[4],
741 				get_current_us() - total_time,
742 				max_time);
743 	exit(0);
744 }
745 
746 #define write_desc "write data into file"
747 #define write_help					\
748 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n"	\
749 "Write given patten data in file_path\n"		\
750 "pattern can be\n"					\
751 "  zero          : zeros\n"				\
752 "  inc_num       : incrementing numbers\n"		\
753 "  rand          : random numbers\n"			\
754 "IO can be\n"						\
755 "  buffered      : buffered IO\n"			\
756 "  dio           : O_DIRECT\n"				\
757 "  dsync         : O_DIRECT | O_DSYNC\n"		\
758 "  osync         : O_SYNC\n"				\
759 "  atomic_commit : atomic write & commit\n"		\
760 "  atomic_abort  : atomic write & abort\n"		\
761 "  atomic_rcommit: atomic replace & commit\n"		\
762 "  atomic_rabort : atomic replace & abort\n"		\
763 "{delay} is in ms unit and optional only for atomic operations\n"
764 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)765 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
766 {
767 	if (argc < 7 || argc > 8) {
768 		fputs("Excess arguments\n\n", stderr);
769 		fputs(cmd->cmd_help, stderr);
770 		exit(1);
771 	}
772 	do_write_with_advice(argc, argv, cmd, false);
773 }
774 
775 #define write_advice_desc "write data into file with a hint"
776 #define write_advice_help					\
777 "f2fs_io write_advice [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [advise] [file_path] {delay}\n\n"	\
778 "Write given patten data in file_path\n"		\
779 "pattern can be\n"					\
780 "  zero          : zeros\n"				\
781 "  inc_num       : incrementing numbers\n"		\
782 "  rand          : random numbers\n"			\
783 "IO can be\n"						\
784 "  buffered      : buffered IO\n"			\
785 "  dio           : O_DIRECT\n"				\
786 "  dsync         : O_DIRECT | O_DSYNC\n"		\
787 "  osync         : O_SYNC\n"				\
788 "  atomic_commit : atomic write & commit\n"		\
789 "  atomic_abort  : atomic write & abort\n"		\
790 "  atomic_rcommit: atomic replace & commit\n"		\
791 "  atomic_rabort : atomic replace & abort\n"		\
792 "advise can be\n"					\
793 "  cold : indicate a cold file\n"			\
794 "  hot  : indicate a hot file\n"			\
795 "{delay} is in ms unit and optional only for atomic operations\n"
796 
do_write_advice(int argc,char ** argv,const struct cmd_desc * cmd)797 static void do_write_advice(int argc, char **argv, const struct cmd_desc *cmd)
798 {
799 	if (argc < 8 || argc > 9) {
800 		fputs("Excess arguments\n\n", stderr);
801 		fputs(cmd->cmd_help, stderr);
802 		exit(1);
803 	}
804 	do_write_with_advice(argc, argv, cmd, true);
805 }
806 
807 #define read_desc "read data from file"
808 #define read_help					\
809 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n"	\
810 "Read data in file_path and print nbytes\n"		\
811 "IO can be\n"						\
812 "  buffered : buffered IO\n"				\
813 "  dio      : direct IO\n"				\
814 "  mmap     : mmap IO\n"				\
815 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)816 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
817 {
818 	u64 buf_size = 0, ret = 0, read_cnt = 0;
819 	u64 offset;
820 	char *buf = NULL;
821 	char *data;
822 	char *print_buf = NULL;
823 	unsigned bs, count, i, print_bytes;
824 	u64 total_time = 0;
825 	int flags = 0;
826 	int do_mmap = 0;
827 	int fd;
828 
829 	if (argc != 7) {
830 		fputs("Excess arguments\n\n", stderr);
831 		fputs(cmd->cmd_help, stderr);
832 		exit(1);
833 	}
834 
835 	bs = atoi(argv[1]);
836 	if (bs > 1024)
837 		die("Too big chunk size - limit: 4MB");
838 	buf_size = bs * 4096;
839 
840 	offset = atoi(argv[2]) * buf_size;
841 
842 	buf = aligned_xalloc(4096, buf_size);
843 
844 	count = atoi(argv[3]);
845 	if (!strcmp(argv[4], "dio"))
846 		flags |= O_DIRECT;
847 	else if (!strcmp(argv[4], "mmap"))
848 		do_mmap = 1;
849 	else if (strcmp(argv[4], "buffered"))
850 		die("Wrong IO type");
851 
852 	print_bytes = atoi(argv[5]);
853 	if (print_bytes > buf_size)
854 		die("Print_nbytes should be less then chunk_size in kb");
855 
856 	print_buf = xmalloc(print_bytes);
857 
858 	fd = xopen(argv[6], O_RDONLY | flags, 0);
859 
860 	total_time = get_current_us();
861 	if (do_mmap) {
862 		data = mmap(NULL, count * buf_size, PROT_READ,
863 						MAP_SHARED | MAP_POPULATE, fd, offset);
864 		if (data == MAP_FAILED)
865 			die("Mmap failed");
866 	}
867 	if (!do_mmap) {
868 		for (i = 0; i < count; i++) {
869 			ret = pread(fd, buf, buf_size, offset + buf_size * i);
870 			if (ret != buf_size)
871 				break;
872 
873 			read_cnt += ret;
874 			if (i == 0)
875 				memcpy(print_buf, buf, print_bytes);
876 		}
877 	} else {
878 		read_cnt = count * buf_size;
879 		memcpy(print_buf, data, print_bytes);
880 	}
881 	printf("Read %"PRIu64" bytes total_time = %"PRIu64" us, print %u bytes:\n",
882 		read_cnt, get_current_us() - total_time, print_bytes);
883 	printf("%08"PRIx64" : ", offset);
884 	for (i = 1; i <= print_bytes; i++) {
885 		printf("%02x", print_buf[i - 1]);
886 		if (i % 16 == 0)
887 			printf("\n%08"PRIx64" : ", offset + 16 * i);
888 		else if (i % 2 == 0)
889 			printf(" ");
890 	}
891 	printf("\n");
892 	exit(0);
893 }
894 
895 #define randread_desc "random read data from file"
896 #define randread_help					\
897 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n"	\
898 "Do random read data in file_path\n"		\
899 "IO can be\n"						\
900 "  buffered : buffered IO\n"				\
901 "  dio      : direct IO\n"				\
902 
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)903 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
904 {
905 	u64 buf_size = 0, ret = 0, read_cnt = 0;
906 	u64 idx, end_idx, aligned_size;
907 	char *buf = NULL;
908 	unsigned bs, count, i;
909 	int flags = 0;
910 	int fd;
911 	time_t t;
912 	struct stat stbuf;
913 
914 	if (argc != 5) {
915 		fputs("Excess arguments\n\n", stderr);
916 		fputs(cmd->cmd_help, stderr);
917 		exit(1);
918 	}
919 
920 	bs = atoi(argv[1]);
921 	if (bs > 1024)
922 		die("Too big chunk size - limit: 4MB");
923 	buf_size = bs * 4096;
924 
925 	buf = aligned_xalloc(4096, buf_size);
926 
927 	count = atoi(argv[2]);
928 	if (!strcmp(argv[3], "dio"))
929 		flags |= O_DIRECT;
930 	else if (strcmp(argv[3], "buffered"))
931 		die("Wrong IO type");
932 
933 	fd = xopen(argv[4], O_RDONLY | flags, 0);
934 
935 	if (fstat(fd, &stbuf) != 0)
936 		die_errno("fstat of source file failed");
937 
938 	aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
939 	if (aligned_size < buf_size)
940 		die("File is too small to random read");
941 	end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
942 
943 	srand((unsigned) time(&t));
944 
945 	for (i = 0; i < count; i++) {
946 		idx = rand() % end_idx;
947 
948 		ret = pread(fd, buf, buf_size, 4096 * idx);
949 		if (ret != buf_size)
950 			break;
951 
952 		read_cnt += ret;
953 	}
954 	printf("Read %"PRIu64" bytes\n", read_cnt);
955 	exit(0);
956 }
957 
958 #define fiemap_desc "get block address in file"
959 #define fiemap_help					\
960 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
961 
962 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)963 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
964 {
965 	unsigned int i;
966 	int fd, extents_mem_size;
967 	u64 start, length;
968 	u32 mapped_extents;
969 	struct fiemap *fm = xmalloc(sizeof(struct fiemap));
970 
971 	if (argc != 4) {
972 		fputs("Excess arguments\n\n", stderr);
973 		fputs(cmd->cmd_help, stderr);
974 		exit(1);
975 	}
976 
977 	memset(fm, 0, sizeof(struct fiemap));
978 	start = (u64)atoi(argv[1]) * F2FS_BLKSIZE;
979 	length = (u64)atoi(argv[2]) * F2FS_BLKSIZE;
980 	fm->fm_start = start;
981 	fm->fm_length = length;
982 
983 	fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
984 
985 	printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
986 				start / F2FS_BLKSIZE, length / F2FS_BLKSIZE);
987 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
988 		die_errno("FIEMAP failed");
989 
990 	mapped_extents = fm->fm_mapped_extents;
991 	extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
992 	free(fm);
993 	fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
994 
995 	memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
996 	fm->fm_start = start;
997 	fm->fm_length = length;
998 	fm->fm_extent_count = mapped_extents;
999 
1000 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
1001 		die_errno("FIEMAP failed");
1002 
1003 	printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
1004 	for (i = 0; i < fm->fm_mapped_extents; i++) {
1005 		printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
1006 		    fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
1007 		    fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
1008 
1009 		if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
1010 			break;
1011 	}
1012 	printf("\n");
1013 	free(fm);
1014 	exit(0);
1015 }
1016 #else
do_fiemap(int UNUSED (argc),char ** UNUSED (argv),const struct cmd_desc * UNUSED (cmd))1017 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
1018 			const struct cmd_desc *UNUSED(cmd))
1019 {
1020 	die("Not support for this platform");
1021 }
1022 #endif
1023 
1024 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
1025 #define gc_urgent_help					\
1026 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
1027 " - f2fs_io gc_urgent sda21 start\n"		\
1028 " - f2fs_io gc_urgent sda21 end\n"		\
1029 " - f2fs_io gc_urgent sda21 run 10\n"		\
1030 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)1031 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
1032 {
1033 	char command[255];
1034 
1035 	if (argc == 3 && !strcmp(argv[2], "start")) {
1036 		printf("gc_urgent: start on %s\n", argv[1]);
1037 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
1038 		if (system(command))
1039 			exit(1);
1040 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
1041 		printf("gc_urgent: end on %s\n", argv[1]);
1042 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
1043 		if (system(command))
1044 			exit(1);
1045 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
1046 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
1047 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
1048 		if (system(command))
1049 			exit(1);
1050 		sleep(atoi(argv[3]));
1051 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
1052 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
1053 		if (system(command))
1054 			exit(1);
1055 	} else {
1056 		fputs("Excess arguments\n\n", stderr);
1057 		fputs(cmd->cmd_help, stderr);
1058 		exit(1);
1059 	}
1060 }
1061 
1062 #define defrag_file_desc "do defragment on file"
1063 #define defrag_file_help						\
1064 "f2fs_io defrag_file [start] [length] [file_path]\n\n"		\
1065 "  start     : start offset of defragment region, unit: bytes\n"	\
1066 "  length    : bytes number of defragment region\n"			\
1067 
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)1068 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
1069 {
1070 	struct f2fs_defragment df;
1071 	u64 len;
1072 	int ret, fd;
1073 
1074 	if (argc != 4) {
1075 		fputs("Excess arguments\n\n", stderr);
1076 		fputs(cmd->cmd_help, stderr);
1077 		exit(1);
1078 	}
1079 
1080 	df.start = atoll(argv[1]);
1081 	df.len = len = atoll(argv[2]);
1082 
1083 	fd = xopen(argv[3], O_RDWR, 0);
1084 
1085 	ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
1086 	if (ret < 0)
1087 		die_errno("F2FS_IOC_DEFRAGMENT failed");
1088 
1089 	printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
1090 			argv[3], df.start, df.start + len);
1091 	exit(0);
1092 }
1093 
1094 #define copy_desc "copy a file"
1095 #define copy_help							\
1096 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n"			\
1097 "  src_path  : path to source file\n"					\
1098 "  dst_path  : path to destination file\n"				\
1099 "  -d        : use direct I/O\n"					\
1100 "  -m        : mmap the source file\n"					\
1101 "  -s        : use sendfile\n"						\
1102 
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)1103 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
1104 {
1105 	int c;
1106 	int src_fd;
1107 	int dst_fd;
1108 	int open_flags = 0;
1109 	bool mmap_source_file = false;
1110 	bool use_sendfile = false;
1111 	ssize_t ret;
1112 
1113 	while ((c = getopt(argc, argv, "dms")) != -1) {
1114 		switch (c) {
1115 		case 'd':
1116 			open_flags |= O_DIRECT;
1117 			break;
1118 		case 'm':
1119 			mmap_source_file = true;
1120 			break;
1121 		case 's':
1122 			use_sendfile = true;
1123 			break;
1124 		default:
1125 			fputs(cmd->cmd_help, stderr);
1126 			exit(2);
1127 		}
1128 	}
1129 	argc -= optind;
1130 	argv += optind;
1131 	if (argc != 2) {
1132 		fputs("Wrong number of arguments\n\n", stderr);
1133 		fputs(cmd->cmd_help, stderr);
1134 		exit(2);
1135 	}
1136 	if (mmap_source_file && use_sendfile)
1137 		die("-m and -s are mutually exclusive");
1138 
1139 	src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
1140 	dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
1141 
1142 	if (mmap_source_file) {
1143 		struct stat stbuf;
1144 		void *src_addr;
1145 
1146 		if (fstat(src_fd, &stbuf) != 0)
1147 			die_errno("fstat of source file failed");
1148 
1149 		if ((size_t)stbuf.st_size != stbuf.st_size)
1150 			die("Source file is too large");
1151 
1152 		src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
1153 				src_fd, 0);
1154 		if (src_addr == MAP_FAILED)
1155 			die("mmap of source file failed");
1156 
1157 		full_write(dst_fd, src_addr, stbuf.st_size);
1158 
1159 		munmap(src_addr, stbuf.st_size);
1160 	} else if (use_sendfile) {
1161 		while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
1162 			;
1163 		if (ret < 0)
1164 			die_errno("sendfile failed");
1165 	} else {
1166 		char *buf = aligned_xalloc(4096, 4096);
1167 
1168 		while ((ret = xread(src_fd, buf, 4096)) > 0)
1169 			full_write(dst_fd, buf, ret);
1170 		free(buf);
1171 	}
1172 	close(src_fd);
1173 	close(dst_fd);
1174 }
1175 
1176 #define get_cblocks_desc "get number of reserved blocks on compress inode"
1177 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
1178 
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1179 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1180 {
1181 	unsigned long long blkcnt;
1182 	int ret, fd;
1183 
1184 	if (argc != 2) {
1185 		fputs("Excess arguments\n\n", stderr);
1186 		fputs(cmd->cmd_help, stderr);
1187 		exit(1);
1188 	}
1189 
1190 	fd = xopen(argv[1], O_RDONLY, 0);
1191 
1192 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1193 	if (ret < 0)
1194 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1195 
1196 	printf("%llu\n", blkcnt);
1197 
1198 	exit(0);
1199 }
1200 
1201 #define release_cblocks_desc "release reserved blocks on compress inode"
1202 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1203 
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1204 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1205 {
1206 	unsigned long long blkcnt;
1207 	int ret, fd;
1208 
1209 	if (argc != 2) {
1210 		fputs("Excess arguments\n\n", stderr);
1211 		fputs(cmd->cmd_help, stderr);
1212 		exit(1);
1213 	}
1214 
1215 	fd = xopen(argv[1], O_RDONLY, 0);
1216 
1217 	ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1218 	if (ret < 0)
1219 		die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1220 
1221 	printf("%llu\n", blkcnt);
1222 
1223 	exit(0);
1224 }
1225 
1226 #define reserve_cblocks_desc "reserve blocks on compress inode"
1227 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1228 
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1229 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1230 {
1231 	unsigned long long blkcnt;
1232 	int ret, fd;
1233 
1234 	if (argc != 2) {
1235 		fputs("Excess arguments\n\n", stderr);
1236 		fputs(cmd->cmd_help, stderr);
1237 		exit(1);
1238 	}
1239 
1240 	fd = xopen(argv[1], O_RDONLY, 0);
1241 
1242 	ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1243 	if (ret < 0)
1244 		die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1245 
1246 	printf("%llu\n", blkcnt);
1247 
1248 	exit(0);
1249 }
1250 
1251 #define get_coption_desc "get compression option of a compressed file"
1252 #define get_coption_help						\
1253 "f2fs_io get_coption [file]\n\n"	\
1254 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1255 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1256 
do_get_coption(int argc,char ** argv,const struct cmd_desc * cmd)1257 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1258 {
1259 	struct f2fs_comp_option option;
1260 	int ret, fd;
1261 
1262 	if (argc != 2) {
1263 		fputs("Excess arguments\n\n", stderr);
1264 		fputs(cmd->cmd_help, stderr);
1265 		exit(1);
1266 	}
1267 
1268 	fd = xopen(argv[1], O_RDONLY, 0);
1269 
1270 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1271 	if (ret < 0)
1272 		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1273 
1274 	printf("compression algorithm:%u\n", option.algorithm);
1275 	printf("compression cluster log size:%u\n", option.log_cluster_size);
1276 
1277 	exit(0);
1278 }
1279 
1280 #define set_coption_desc "set compression option of a compressed file"
1281 #define set_coption_help						\
1282 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n"	\
1283 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1284 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1285 
do_set_coption(int argc,char ** argv,const struct cmd_desc * cmd)1286 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1287 {
1288 	struct f2fs_comp_option option;
1289 	int fd, ret;
1290 
1291 	if (argc != 4) {
1292 		fputs("Excess arguments\n\n", stderr);
1293 		fputs(cmd->cmd_help, stderr);
1294 		exit(1);
1295 	}
1296 
1297 	option.algorithm = atoi(argv[1]);
1298 	option.log_cluster_size = atoi(argv[2]);
1299 
1300 	fd = xopen(argv[3], O_WRONLY, 0);
1301 
1302 	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1303 	if (ret < 0)
1304 		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1305 
1306 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1307 			option.algorithm, option.log_cluster_size);
1308 	exit(0);
1309 }
1310 
1311 #define decompress_desc "decompress an already compressed file"
1312 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1313 
do_decompress(int argc,char ** argv,const struct cmd_desc * cmd)1314 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1315 {
1316 	int fd, ret;
1317 
1318 	if (argc != 2) {
1319 		fputs("Excess arguments\n\n", stderr);
1320 		fputs(cmd->cmd_help, stderr);
1321 		exit(1);
1322 	}
1323 
1324 	fd = xopen(argv[1], O_WRONLY, 0);
1325 
1326 	ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1327 	if (ret < 0)
1328 		die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1329 
1330 	exit(0);
1331 }
1332 
1333 #define compress_desc "compress a compression enabled file"
1334 #define compress_help "f2fs_io compress [file_path]\n\n"
1335 
do_compress(int argc,char ** argv,const struct cmd_desc * cmd)1336 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1337 {
1338 	int fd, ret;
1339 
1340 	if (argc != 2) {
1341 		fputs("Excess arguments\n\n", stderr);
1342 		fputs(cmd->cmd_help, stderr);
1343 		exit(1);
1344 	}
1345 
1346 	fd = xopen(argv[1], O_WRONLY, 0);
1347 
1348 	ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1349 	if (ret < 0)
1350 		die_errno("F2FS_IOC_COMPRESS_FILE failed");
1351 
1352 	exit(0);
1353 }
1354 
1355 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1356 #define get_filename_encrypt_mode_help					\
1357 "f2fs_io filename_encrypt_mode [file or directory path]\n\n"		\
1358 "Get the file name encription mode of the given file/directory.\n"	\
1359 
do_get_filename_encrypt_mode(int argc,char ** argv,const struct cmd_desc * cmd)1360 static void do_get_filename_encrypt_mode (int argc, char **argv,
1361 						const struct cmd_desc *cmd)
1362 {
1363 	static const char *enc_name[] = {
1364 		"invalid", /* FSCRYPT_MODE_INVALID (0) */
1365 		"aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */
1366 		"aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */
1367 		"aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */
1368 		"aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */
1369 		"aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */
1370 		"aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */
1371 		"speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */
1372 		"speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */
1373 		"adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */
1374 		"aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */
1375 	};
1376 	int fd, mode, ret;
1377 	struct fscrypt_get_policy_ex_arg arg;
1378 
1379 	if (argc != 2) {
1380 		fputs("Excess arguments\n\n", stderr);
1381 		fputs(cmd->cmd_help, stderr);
1382 		exit(1);
1383 	}
1384 
1385 	fd = xopen(argv[1], O_RDONLY, 0);
1386 	arg.policy_size = sizeof(arg.policy);
1387 	ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1388 	if (ret != 0 && errno == ENOTTY)
1389 		ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1390 	close(fd);
1391 
1392 	if (ret) {
1393 		perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1394 		exit(1);
1395 	}
1396 
1397 	switch (arg.policy.version) {
1398 	case FSCRYPT_POLICY_V1:
1399 		mode = arg.policy.v1.filenames_encryption_mode;
1400 		break;
1401 	case FSCRYPT_POLICY_V2:
1402 		mode = arg.policy.v2.filenames_encryption_mode;
1403 		break;
1404 	default:
1405 		printf("Do not support policy version: %d\n",
1406 							arg.policy.version);
1407 		exit(1);
1408 	}
1409 
1410 	if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1411 		printf("Do not support algorithm: %d\n", mode);
1412 		exit(1);
1413 	}
1414 	printf ("%s\n", enc_name[mode]);
1415 	exit(0);
1416 }
1417 
1418 #define rename_desc "rename source to target file with fsync option"
1419 #define rename_help							\
1420 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n"	\
1421 "e.g., f2fs_io rename source dest 1\n"					\
1422 "      1. open(source)\n"						\
1423 "      2. rename(source, dest)\n"					\
1424 "      3. fsync(source)\n"						\
1425 "      4. close(source)\n"
1426 
do_rename(int argc,char ** argv,const struct cmd_desc * cmd)1427 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1428 {
1429 	int fd = -1;
1430 	int ret;
1431 
1432 	if (argc != 4) {
1433 		fputs("Excess arguments\n\n", stderr);
1434 		fputs(cmd->cmd_help, stderr);
1435 		exit(1);
1436 	}
1437 
1438 	if (atoi(argv[3]))
1439 		fd = xopen(argv[1], O_WRONLY, 0);
1440 
1441 	ret = rename(argv[1], argv[2]);
1442 	if (ret < 0)
1443 		die_errno("rename failed");
1444 
1445 	if (fd >= 0) {
1446 		if (fsync(fd) != 0)
1447 			die_errno("fsync failed: %s", argv[1]);
1448 		close(fd);
1449 	}
1450 	exit(0);
1451 }
1452 
1453 #define gc_desc "trigger filesystem GC"
1454 #define gc_help "f2fs_io gc sync_mode [file_path]\n\n"
1455 
do_gc(int argc,char ** argv,const struct cmd_desc * cmd)1456 static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
1457 {
1458 	u32 sync;
1459 	int ret, fd;
1460 
1461 	if (argc != 3) {
1462 		fputs("Excess arguments\n\n", stderr);
1463 		fputs(cmd->cmd_help, stderr);
1464 		exit(1);
1465 	}
1466 
1467 	sync = atoi(argv[1]);
1468 
1469 	fd = xopen(argv[2], O_RDONLY, 0);
1470 
1471 	ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync);
1472 	if (ret < 0)
1473 		die_errno("F2FS_IOC_GARBAGE_COLLECT failed");
1474 
1475 	printf("trigger %s gc ret=%d\n",
1476 		sync ? "synchronous" : "asynchronous", ret);
1477 	exit(0);
1478 }
1479 
1480 #define checkpoint_desc "trigger filesystem checkpoint"
1481 #define checkpoint_help "f2fs_io checkpoint [file_path]\n\n"
1482 
do_checkpoint(int argc,char ** argv,const struct cmd_desc * cmd)1483 static void do_checkpoint(int argc, char **argv, const struct cmd_desc *cmd)
1484 {
1485 	int ret, fd;
1486 
1487 	if (argc != 2) {
1488 		fputs("Excess arguments\n\n", stderr);
1489 		fputs(cmd->cmd_help, stderr);
1490 		exit(1);
1491 	}
1492 
1493 	fd = xopen(argv[1], O_WRONLY, 0);
1494 
1495 	ret = ioctl(fd, F2FS_IOC_WRITE_CHECKPOINT);
1496 	if (ret < 0)
1497 		die_errno("F2FS_IOC_WRITE_CHECKPOINT failed");
1498 
1499 	printf("trigger filesystem checkpoint ret=%d\n", ret);
1500 	exit(0);
1501 }
1502 
1503 #define precache_extents_desc "trigger precache extents"
1504 #define precache_extents_help "f2fs_io precache_extents [file_path]\n\n"
1505 
do_precache_extents(int argc,char ** argv,const struct cmd_desc * cmd)1506 static void do_precache_extents(int argc, char **argv, const struct cmd_desc *cmd)
1507 {
1508 	int ret, fd;
1509 
1510 	if (argc != 2) {
1511 		fputs("Excess arguments\n\n", stderr);
1512 		fputs(cmd->cmd_help, stderr);
1513 		exit(1);
1514 	}
1515 
1516 	fd = xopen(argv[1], O_WRONLY, 0);
1517 
1518 	ret = ioctl(fd, F2FS_IOC_PRECACHE_EXTENTS);
1519 	if (ret < 0)
1520 		die_errno("F2FS_IOC_PRECACHE_EXTENTS failed");
1521 
1522 	printf("trigger precache extents ret=%d\n", ret);
1523 	exit(0);
1524 }
1525 
1526 #define move_range_desc "moving a range of data blocks from source file to destination file"
1527 #define move_range_help						\
1528 "f2fs_io move_range [src_path] [dst_path] [src_start] [dst_start] "	\
1529 "[length]\n\n"								\
1530 "  src_path  : path to source file\n"					\
1531 "  dst_path  : path to destination file\n"				\
1532 "  src_start : start offset of src file move region, unit: bytes\n"	\
1533 "  dst_start : start offset of dst file move region, unit: bytes\n"	\
1534 "  length    : size to move\n"						\
1535 
do_move_range(int argc,char ** argv,const struct cmd_desc * cmd)1536 static void do_move_range(int argc, char **argv, const struct cmd_desc *cmd)
1537 {
1538 	struct f2fs_move_range range;
1539 	int ret, fd;
1540 
1541 	if (argc != 6) {
1542 		fputs("Excess arguments\n\n", stderr);
1543 		fputs(cmd->cmd_help, stderr);
1544 		exit(1);
1545 	}
1546 
1547 	fd = xopen(argv[1], O_RDWR, 0);
1548 	range.dst_fd = xopen(argv[2], O_RDWR | O_CREAT, 0644);
1549 	range.pos_in = atoi(argv[3]);
1550 	range.pos_out = atoi(argv[4]);
1551 	range.len = atoi(argv[5]);
1552 
1553 	ret = ioctl(fd, F2FS_IOC_MOVE_RANGE, &range);
1554 	if (ret < 0)
1555 		die_errno("F2FS_IOC_MOVE_RANGE failed");
1556 
1557 	printf("move range ret=%d\n", ret);
1558 	exit(0);
1559 }
1560 
1561 #define gc_range_desc "trigger filesystem gc_range"
1562 #define gc_range_help "f2fs_io gc_range [sync_mode] [start] [length] [file_path]\n\n"\
1563 "  sync_mode : 0: asynchronous, 1: synchronous\n"			\
1564 "  start     : start offset of defragment region, unit: 4kb\n"	\
1565 "  length    : bytes number of defragment region, unit: 4kb\n"	\
1566 
do_gc_range(int argc,char ** argv,const struct cmd_desc * cmd)1567 static void do_gc_range(int argc, char **argv, const struct cmd_desc *cmd)
1568 {
1569 	struct f2fs_gc_range range;
1570 	int ret, fd;
1571 
1572 	if (argc != 5) {
1573 		fputs("Excess arguments\n\n", stderr);
1574 		fputs(cmd->cmd_help, stderr);
1575 		exit(1);
1576 	}
1577 
1578 	range.sync = atoi(argv[1]);
1579 	range.start = (u64)atoi(argv[2]);
1580 	range.len = (u64)atoi(argv[3]);
1581 
1582 	fd = xopen(argv[4], O_RDWR, 0);
1583 
1584 	ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT_RANGE, &range);
1585 	if (ret < 0) {
1586 		die_errno("F2FS_IOC_GARBAGE_COLLECT_RANGE failed");
1587 	}
1588 
1589 	printf("trigger %s gc_range [%"PRIu64", %"PRIu64"] ret=%d\n",
1590 		range.sync ? "synchronous" : "asynchronous",
1591 		range.start, range.len, ret);
1592 	exit(0);
1593 }
1594 
1595 #define listxattr_desc "listxattr"
1596 #define listxattr_help "f2fs_io listxattr [file_path]\n\n"
1597 
do_listxattr(int argc,char ** argv,const struct cmd_desc * cmd)1598 static void do_listxattr(int argc, char **argv, const struct cmd_desc *cmd)
1599 {
1600 	char *buf, *key, *val;
1601 	ssize_t buflen, vallen, keylen;
1602 
1603 	if (argc != 2) {
1604 		fputs("Excess arguments\n\n", stderr);
1605 		fputs(cmd->cmd_help, stderr);
1606 		exit(1);
1607 	}
1608 
1609 	buflen = listxattr(argv[1], NULL, 0);
1610 	if (buflen == -1) {
1611 		perror("listxattr");
1612 		exit(1);
1613 	}
1614 	if (buflen == 0) {
1615 		printf("%s has no attributes.\n", argv[1]);
1616 		exit(0);
1617 	}
1618 	buf = xmalloc(buflen);
1619 	buflen = listxattr(argv[1], buf, buflen);
1620 	if (buflen == -1) {
1621 		perror("listxattr");
1622 		exit(1);
1623 	}
1624 
1625 	key = buf;
1626 	while (buflen > 0) {
1627 		printf("%s: ", key);
1628 		vallen = getxattr(argv[1], key, NULL, 0);
1629 		if (vallen == -1) {
1630 			perror("getxattr");
1631 			exit(1);
1632 		}
1633 		if (vallen == 0) {
1634 			printf("<no value>");
1635 		} else {
1636 			val = xmalloc(vallen + 1);
1637 			vallen = getxattr(argv[1], key, val, vallen);
1638 			if (vallen == -1) {
1639 				perror("getxattr");
1640 				exit(1);
1641 			}
1642 			val[vallen] = 0;
1643 			printf("%s", val);
1644 			free(val);
1645 		}
1646 		printf("\n");
1647 		keylen = strlen(key) + 1;
1648 		buflen -= keylen;
1649 		key += keylen;
1650 	}
1651 	exit(0);
1652 }
1653 
1654 #define setxattr_desc "setxattr"
1655 #define setxattr_help "f2fs_io setxattr [name] [value] [file_path]\n\n"
1656 
do_setxattr(int argc,char ** argv,const struct cmd_desc * cmd)1657 static void do_setxattr(int argc, char **argv, const struct cmd_desc *cmd)
1658 {
1659 	int ret;
1660 	char *value;
1661 	unsigned char tmp;
1662 
1663 	if (argc != 4) {
1664 		fputs("Excess arguments\n\n", stderr);
1665 		fputs(cmd->cmd_help, stderr);
1666 		exit(1);
1667 	}
1668 
1669 	if (!strcmp(argv[1], F2FS_SYSTEM_ADVISE_NAME)) {
1670 		tmp = strtoul(argv[2], NULL, 0);
1671 		value = (char *)&tmp;
1672 	} else {
1673 		value = argv[2];
1674 	}
1675 
1676 	ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_CREATE);
1677 	printf("setxattr %s CREATE: name: %s, value: %s: ret=%d\n",
1678 			argv[3], argv[1], argv[2], ret);
1679 	if (ret < 0 && errno == EEXIST) {
1680 		ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_REPLACE);
1681 		printf("setxattr %s REPLACE: name: %s, value: %s: ret=%d\n",
1682 				argv[3], argv[1], argv[2], ret);
1683 	}
1684 	if (ret < 0)
1685 		perror("setxattr");
1686 	exit(0);
1687 }
1688 
1689 #define removexattr_desc "removexattr"
1690 #define removexattr_help "f2fs_io removexattr [name] [file_path]\n\n"
1691 
do_removexattr(int argc,char ** argv,const struct cmd_desc * cmd)1692 static void do_removexattr(int argc, char **argv, const struct cmd_desc *cmd)
1693 {
1694 	int ret;
1695 
1696 	if (argc != 3) {
1697 		fputs("Excess arguments\n\n", stderr);
1698 		fputs(cmd->cmd_help, stderr);
1699 		exit(1);
1700 	}
1701 
1702 	ret = removexattr(argv[2], argv[1]);
1703 	printf("removexattr %s REMOVE: name: %s: ret=%d\n", argv[1], argv[2], ret);
1704 	exit(0);
1705 }
1706 
1707 #define lseek_desc "do lseek for a file"
1708 #define lseek_help					\
1709 "f2fs_io lseek [whence] [offset] [file_path]\n\n"	\
1710 "Do lseek file data in file_path and return the adjusted file offset\n"	\
1711 "whence can be\n"					\
1712 "  set  : SEEK_SET, The file offset is set to offset bytes\n"	\
1713 "  cur  : SEEK_CUR, The file offset is set to its current location plus offset bytes\n"	\
1714 "  end  : SEEK_END, The file offset is set to the size of the file plus offset bytes\n"	\
1715 "  data : SEEK_DATA, set the file offset to the next data location from offset\n"	\
1716 "  hole : SEEK_HOLE, set the file offset to the next hole from offset\n"
1717 
do_lseek(int argc,char ** argv,const struct cmd_desc * cmd)1718 static void do_lseek(int argc, char **argv, const struct cmd_desc *cmd)
1719 {
1720 	int fd, whence;
1721 	off_t offset, ret;
1722 
1723 	if (argc != 4) {
1724 		fputs("Excess arguments\n\n", stderr);
1725 		fputs(cmd->cmd_help, stderr);
1726 		exit(1);
1727 	}
1728 
1729 	offset = atoi(argv[2]);
1730 
1731 	if (!strcmp(argv[1], "set"))
1732 		whence = SEEK_SET;
1733 	else if (!strcmp(argv[1], "cur"))
1734 		whence = SEEK_CUR;
1735 	else if (!strcmp(argv[1], "end"))
1736 		whence = SEEK_END;
1737 	else if (!strcmp(argv[1], "data"))
1738 		whence = SEEK_DATA;
1739 	else if (!strcmp(argv[1], "hole"))
1740 		whence = SEEK_HOLE;
1741 	else
1742 		die("Wrong whence type");
1743 
1744 	fd = xopen(argv[3], O_RDONLY, 0);
1745 
1746 	ret = lseek(fd, offset, whence);
1747 	if (ret < 0)
1748 		die_errno("lseek failed");
1749 	printf("returned offset=%ld\n", ret);
1750 	exit(0);
1751 }
1752 
1753 #define get_advise_desc "get_advise"
1754 #define get_advise_help "f2fs_io get_advise [file_path]\n\n"
1755 
do_get_advise(int argc,char ** argv,const struct cmd_desc * cmd)1756 static void do_get_advise(int argc, char **argv, const struct cmd_desc *cmd)
1757 {
1758 	int ret;
1759 	unsigned char value;
1760 
1761 	if (argc != 2) {
1762 		fputs("Excess arguments\n\n", stderr);
1763 		fputs(cmd->cmd_help, stderr);
1764 		exit(1);
1765 	}
1766 
1767 	ret = getxattr(argv[1], F2FS_SYSTEM_ADVISE_NAME, &value, sizeof(value));
1768 	if (ret != sizeof(value)) {
1769 		perror("getxattr");
1770 		exit(1);
1771 	}
1772 
1773 	printf("i_advise=0x%x, advise_type: ", value);
1774 	if (value & FADVISE_COLD_BIT)
1775 		printf("cold ");
1776 	if (value & FADVISE_LOST_PINO_BIT)
1777 		printf("lost_pino ");
1778 	if (value & FADVISE_ENCRYPT_BIT)
1779 		printf("encrypt ");
1780 	if (value & FADVISE_ENC_NAME_BIT)
1781 		printf("enc_name ");
1782 	if (value & FADVISE_KEEP_SIZE_BIT)
1783 		printf("keep_size ");
1784 	if (value & FADVISE_HOT_BIT)
1785 		printf("hot ");
1786 	if (value & FADVISE_VERITY_BIT)
1787 		printf("verity ");
1788 	if (value & FADVISE_TRUNC_BIT)
1789 		printf("trunc ");
1790 	printf("\n");
1791 }
1792 
1793 #define CMD_HIDDEN 	0x0001
1794 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1795 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1796 
1797 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1798 const struct cmd_desc cmd_list[] = {
1799 	_CMD(help),
1800 	CMD(fsync),
1801 	CMD(set_verity),
1802 	CMD(getflags),
1803 	CMD(setflags),
1804 	CMD(clearflags),
1805 	CMD(shutdown),
1806 	CMD(pinfile),
1807 	CMD(fadvise),
1808 	CMD(fallocate),
1809 	CMD(erase),
1810 	CMD(write),
1811 	CMD(write_advice),
1812 	CMD(read),
1813 	CMD(randread),
1814 	CMD(fiemap),
1815 	CMD(gc_urgent),
1816 	CMD(defrag_file),
1817 	CMD(copy),
1818 	CMD(get_cblocks),
1819 	CMD(release_cblocks),
1820 	CMD(reserve_cblocks),
1821 	CMD(get_coption),
1822 	CMD(set_coption),
1823 	CMD(decompress),
1824 	CMD(compress),
1825 	CMD(get_filename_encrypt_mode),
1826 	CMD(rename),
1827 	CMD(gc),
1828 	CMD(checkpoint),
1829 	CMD(precache_extents),
1830 	CMD(move_range),
1831 	CMD(gc_range),
1832 	CMD(listxattr),
1833 	CMD(setxattr),
1834 	CMD(removexattr),
1835 	CMD(lseek),
1836 	CMD(get_advise),
1837 	{ NULL, NULL, NULL, NULL, 0 }
1838 };
1839 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))1840 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1841 {
1842 	const struct cmd_desc *p;
1843 
1844 	if (argc > 1) {
1845 		for (p = cmd_list; p->cmd_name; p++) {
1846 			if (p->cmd_flags & CMD_HIDDEN)
1847 				continue;
1848 			if (strcmp(p->cmd_name, argv[1]) == 0) {
1849 				putc('\n', stdout);
1850 				fputs("USAGE:\n  ", stdout);
1851 				fputs(p->cmd_help, stdout);
1852 				exit(0);
1853 			}
1854 		}
1855 		printf("Unknown command: %s\n\n", argv[1]);
1856 	}
1857 
1858 	fputs("Available commands:\n", stdout);
1859 	for (p = cmd_list; p->cmd_name; p++) {
1860 		if (p->cmd_flags & CMD_HIDDEN)
1861 			continue;
1862 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
1863 	}
1864 	printf("\nTo get more information on a command, "
1865 	       "type 'f2fs_io help cmd'\n");
1866 	exit(0);
1867 }
1868 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))1869 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1870 				void *UNUSED(context))
1871 {
1872 	exit(-1);
1873 }
1874 
sigcatcher_setup(void)1875 static void sigcatcher_setup(void)
1876 {
1877 	struct sigaction	sa;
1878 
1879 	memset(&sa, 0, sizeof(struct sigaction));
1880 	sa.sa_sigaction = die_signal_handler;
1881 	sa.sa_flags = SA_SIGINFO;
1882 
1883 	sigaction(SIGHUP, &sa, 0);
1884 	sigaction(SIGINT, &sa, 0);
1885 	sigaction(SIGQUIT, &sa, 0);
1886 	sigaction(SIGFPE, &sa, 0);
1887 	sigaction(SIGILL, &sa, 0);
1888 	sigaction(SIGBUS, &sa, 0);
1889 	sigaction(SIGSEGV, &sa, 0);
1890 	sigaction(SIGABRT, &sa, 0);
1891 	sigaction(SIGPIPE, &sa, 0);
1892 	sigaction(SIGALRM, &sa, 0);
1893 	sigaction(SIGTERM, &sa, 0);
1894 	sigaction(SIGUSR1, &sa, 0);
1895 	sigaction(SIGUSR2, &sa, 0);
1896 	sigaction(SIGPOLL, &sa, 0);
1897 	sigaction(SIGPROF, &sa, 0);
1898 	sigaction(SIGSYS, &sa, 0);
1899 	sigaction(SIGTRAP, &sa, 0);
1900 	sigaction(SIGVTALRM, &sa, 0);
1901 	sigaction(SIGXCPU, &sa, 0);
1902 	sigaction(SIGXFSZ, &sa, 0);
1903 }
1904 
main(int argc,char ** argv)1905 int main(int argc, char **argv)
1906 {
1907 	const struct cmd_desc *cmd;
1908 
1909 	if (argc < 2)
1910 		do_help(argc, argv, cmd_list);
1911 
1912 	sigcatcher_setup();
1913 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1914 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1915 			cmd->cmd_func(argc - 1, argv + 1, cmd);
1916 			exit(0);
1917 		}
1918 	}
1919 	printf("Unknown command: %s\n\n", argv[1]);
1920 	do_help(1, argv, cmd_list);
1921 	return 0;
1922 }
1923