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