You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1287 lines
29 KiB
1287 lines
29 KiB
/*
|
|
* f2fs_io.c - f2fs ioctl utility
|
|
*
|
|
* Author: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
*
|
|
* Copied portion of the code from ../f2fscrypt.c
|
|
*/
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
#ifndef _LARGEFILE_SOURCE
|
|
#define _LARGEFILE_SOURCE
|
|
#endif
|
|
#ifndef _LARGEFILE64_SOURCE
|
|
#define _LARGEFILE64_SOURCE
|
|
#endif
|
|
#ifndef O_LARGEFILE
|
|
#define O_LARGEFILE 0
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <linux/fs.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/sendfile.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <termios.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <android_config.h>
|
|
|
|
#include "f2fs_io.h"
|
|
|
|
struct cmd_desc {
|
|
const char *cmd_name;
|
|
void (*cmd_func)(int, char **, const struct cmd_desc *);
|
|
const char *cmd_desc;
|
|
const char *cmd_help;
|
|
int cmd_flags;
|
|
};
|
|
|
|
static void __attribute__((noreturn))
|
|
do_die(const char *format, va_list va, int err)
|
|
{
|
|
vfprintf(stderr, format, va);
|
|
if (err)
|
|
fprintf(stderr, ": %s", strerror(err));
|
|
putc('\n', stderr);
|
|
exit(1);
|
|
}
|
|
|
|
static void __attribute__((noreturn, format(printf, 1, 2)))
|
|
die_errno(const char *format, ...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
do_die(format, va, errno);
|
|
va_end(va);
|
|
}
|
|
|
|
static void __attribute__((noreturn, format(printf, 1, 2)))
|
|
die(const char *format, ...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
do_die(format, va, 0);
|
|
va_end(va);
|
|
}
|
|
|
|
static void *xmalloc(size_t size)
|
|
{
|
|
void *p = malloc(size);
|
|
|
|
if (!p)
|
|
die("Memory alloc failed (requested %zu bytes)", size);
|
|
return p;
|
|
}
|
|
|
|
static void *aligned_xalloc(size_t alignment, size_t size)
|
|
{
|
|
void *p = aligned_alloc(alignment, size);
|
|
|
|
if (!p)
|
|
die("Memory alloc failed (requested %zu bytes)", size);
|
|
return p;
|
|
}
|
|
|
|
static int xopen(const char *pathname, int flags, mode_t mode)
|
|
{
|
|
int fd = open(pathname, flags, mode);
|
|
|
|
if (fd < 0)
|
|
die_errno("Failed to open %s", pathname);
|
|
return fd;
|
|
}
|
|
|
|
static ssize_t xread(int fd, void *buf, size_t count)
|
|
{
|
|
ssize_t ret = read(fd, buf, count);
|
|
|
|
if (ret < 0)
|
|
die_errno("read failed");
|
|
return ret;
|
|
}
|
|
|
|
static void full_write(int fd, const void *buf, size_t count)
|
|
{
|
|
while (count) {
|
|
ssize_t ret = write(fd, buf, count);
|
|
|
|
if (ret < 0)
|
|
die_errno("write failed");
|
|
buf = (char *)buf + ret;
|
|
count -= ret;
|
|
}
|
|
}
|
|
|
|
#if defined(__APPLE__)
|
|
static u64 get_current_us()
|
|
{
|
|
#ifdef HAVE_MACH_TIME_H
|
|
return mach_absolute_time() / 1000;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
#else
|
|
static u64 get_current_us()
|
|
{
|
|
struct timespec t;
|
|
t.tv_sec = t.tv_nsec = 0;
|
|
clock_gettime(CLOCK_BOOTTIME, &t);
|
|
return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
|
|
}
|
|
#endif
|
|
|
|
#define fsync_desc "fsync"
|
|
#define fsync_help \
|
|
"f2fs_io fsync [file]\n\n" \
|
|
"fsync given the file\n" \
|
|
|
|
static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_WRONLY, 0);
|
|
|
|
if (fsync(fd) != 0)
|
|
die_errno("fsync failed");
|
|
|
|
printf("fsync a file\n");
|
|
exit(0);
|
|
}
|
|
|
|
#define set_verity_desc "Set fs-verity"
|
|
#define set_verity_help \
|
|
"f2fs_io set_verity [file]\n\n" \
|
|
"Set fsverity bit given a file\n" \
|
|
|
|
static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int ret, fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = open(argv[1], O_RDWR);
|
|
|
|
ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
|
|
if (ret < 0) {
|
|
perror("FS_IOC_ENABLE_VERITY");
|
|
exit(1);
|
|
}
|
|
|
|
printf("Set fsverity bit to %s\n", argv[1]);
|
|
exit(0);
|
|
}
|
|
|
|
#define getflags_desc "getflags ioctl"
|
|
#define getflags_help \
|
|
"f2fs_io getflags [file]\n\n" \
|
|
"get a flag given the file\n" \
|
|
"flag can show \n" \
|
|
" encryption\n" \
|
|
" nocow(pinned)\n" \
|
|
" inline_data\n" \
|
|
" verity\n" \
|
|
" casefold\n" \
|
|
" compression\n" \
|
|
" nocompression\n" \
|
|
" immutable\n"
|
|
|
|
static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
long flag = 0;
|
|
int ret, fd;
|
|
int exist = 0;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
|
|
printf("get a flag on %s ret=%d, flags=", argv[1], ret);
|
|
if (flag & FS_CASEFOLD_FL) {
|
|
printf("casefold");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_COMPR_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("compression");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_NOCOMP_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("nocompression");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_ENCRYPT_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("encrypt");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_VERITY_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("verity");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_INLINE_DATA_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("inline_data");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_NOCOW_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("nocow(pinned)");
|
|
exist = 1;
|
|
}
|
|
if (flag & FS_IMMUTABLE_FL) {
|
|
if (exist)
|
|
printf(",");
|
|
printf("immutable");
|
|
exist = 1;
|
|
}
|
|
if (!exist)
|
|
printf("none");
|
|
printf("\n");
|
|
exit(0);
|
|
}
|
|
|
|
#define setflags_desc "setflags ioctl"
|
|
#define setflags_help \
|
|
"f2fs_io setflags [flag] [file]\n\n" \
|
|
"set a flag given the file\n" \
|
|
"flag can be\n" \
|
|
" casefold\n" \
|
|
" compression\n" \
|
|
" nocompression\n" \
|
|
" noimmutable\n"
|
|
|
|
static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
long flag = 0;
|
|
int ret, fd;
|
|
|
|
if (argc != 3) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[2], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
|
|
printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
|
|
if (ret)
|
|
die_errno("F2FS_IOC_GETFLAGS failed");
|
|
|
|
if (!strcmp(argv[1], "casefold"))
|
|
flag |= FS_CASEFOLD_FL;
|
|
else if (!strcmp(argv[1], "compression"))
|
|
flag |= FS_COMPR_FL;
|
|
else if (!strcmp(argv[1], "nocompression"))
|
|
flag |= FS_NOCOMP_FL;
|
|
else if (!strcmp(argv[1], "noimmutable"))
|
|
flag &= ~FS_IMMUTABLE_FL;
|
|
|
|
ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
|
|
printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
|
|
exit(0);
|
|
}
|
|
|
|
#define shutdown_desc "shutdown filesystem"
|
|
#define shutdown_help \
|
|
"f2fs_io shutdown [level] [dir]\n\n" \
|
|
"Freeze and stop all IOs given mount point\n" \
|
|
"level can be\n" \
|
|
" 0 : going down with full sync\n" \
|
|
" 1 : going down with checkpoint only\n" \
|
|
" 2 : going down with no sync\n" \
|
|
" 3 : going down with metadata flush\n" \
|
|
" 4 : going down with fsck mark\n"
|
|
|
|
static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
u32 flag;
|
|
int ret, fd;
|
|
|
|
if (argc != 3) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
flag = atoi(argv[1]);
|
|
if (flag >= F2FS_GOING_DOWN_MAX) {
|
|
fputs("Wrong level\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
fd = xopen(argv[2], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_SHUTDOWN failed");
|
|
|
|
printf("Shutdown %s with level=%d\n", argv[2], flag);
|
|
exit(0);
|
|
}
|
|
|
|
#define pinfile_desc "pin file control"
|
|
#define pinfile_help \
|
|
"f2fs_io pinfile [get|set] [file]\n\n" \
|
|
"get/set pinning given the file\n" \
|
|
|
|
static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
u32 pin;
|
|
int ret, fd;
|
|
|
|
if (argc != 3) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[2], O_RDONLY, 0);
|
|
|
|
ret = -1;
|
|
if (!strcmp(argv[1], "set")) {
|
|
pin = 1;
|
|
ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
|
|
if (ret != 0)
|
|
die_errno("F2FS_IOC_SET_PIN_FILE failed");
|
|
printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
|
|
} else if (!strcmp(argv[1], "get")) {
|
|
unsigned int flags;
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_GET_PIN_FILE failed");
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_GETFLAGS failed");
|
|
|
|
printf("get_pin_file: %s with %u blocks moved in %s\n",
|
|
(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
|
|
pin, argv[2]);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
#define fallocate_desc "fallocate"
|
|
#define fallocate_help \
|
|
"f2fs_io fallocate [keep_size] [offset] [length] [file]\n\n" \
|
|
"fallocate given the file\n" \
|
|
" [keep_size] : 1 or 0\n" \
|
|
|
|
static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int fd;
|
|
off_t offset, length;
|
|
struct stat sb;
|
|
int mode = 0;
|
|
|
|
if (argc != 5) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
if (!strcmp(argv[1], "1"))
|
|
mode |= FALLOC_FL_KEEP_SIZE;
|
|
|
|
offset = atoi(argv[2]);
|
|
length = atoll(argv[3]);
|
|
|
|
fd = xopen(argv[4], O_RDWR, 0);
|
|
|
|
if (fallocate(fd, mode, offset, length) != 0)
|
|
die_errno("fallocate failed");
|
|
|
|
if (fstat(fd, &sb) != 0)
|
|
die_errno("fstat failed");
|
|
|
|
printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
|
|
exit(0);
|
|
}
|
|
|
|
#define erase_desc "erase a block device"
|
|
#define erase_help \
|
|
"f2fs_io erase [block_device_path]\n\n" \
|
|
"Send DISCARD | BLKSECDISCARD comamnd to" \
|
|
"block device in block_device_path\n" \
|
|
|
|
static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int fd, ret;
|
|
struct stat st;
|
|
u64 range[2];
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
if (stat(argv[1], &st) != 0) {
|
|
fputs("stat error\n", stderr);
|
|
exit(1);
|
|
}
|
|
|
|
if (!S_ISBLK(st.st_mode)) {
|
|
fputs(argv[1], stderr);
|
|
fputs(" is not a block device\n", stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_WRONLY, 0);
|
|
|
|
range[0] = 0;
|
|
ret = ioctl(fd, BLKGETSIZE64, &range[1]);
|
|
if (ret < 0) {
|
|
fputs("get size failed\n", stderr);
|
|
exit(1);
|
|
}
|
|
|
|
ret = ioctl(fd, BLKSECDISCARD, &range);
|
|
if (ret < 0) {
|
|
ret = ioctl(fd, BLKDISCARD, &range);
|
|
if (ret < 0) {
|
|
fputs("Discard failed\n", stderr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define write_desc "write data into file"
|
|
#define write_help \
|
|
"f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path]\n\n" \
|
|
"Write given patten data in file_path\n" \
|
|
"pattern can be\n" \
|
|
" zero : zeros\n" \
|
|
" inc_num : incrementing numbers\n" \
|
|
" rand : random numbers\n" \
|
|
"IO can be\n" \
|
|
" buffered : buffered IO\n" \
|
|
" dio : direct IO\n" \
|
|
" osync : O_SYNC\n" \
|
|
|
|
static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
u64 buf_size = 0, inc_num = 0, ret = 0, written = 0;
|
|
u64 offset;
|
|
char *buf = NULL;
|
|
unsigned bs, count, i;
|
|
int flags = 0;
|
|
int fd;
|
|
u64 total_time = 0, max_time = 0, max_time_t = 0;
|
|
|
|
srand(time(0));
|
|
|
|
if (argc != 7) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
bs = atoi(argv[1]);
|
|
if (bs > 1024)
|
|
die("Too big chunk size - limit: 4MB");
|
|
|
|
buf_size = bs * 4096;
|
|
|
|
offset = atoi(argv[2]) * buf_size;
|
|
|
|
buf = aligned_xalloc(4096, buf_size);
|
|
count = atoi(argv[3]);
|
|
|
|
if (!strcmp(argv[4], "zero"))
|
|
memset(buf, 0, buf_size);
|
|
else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
|
|
die("Wrong pattern type");
|
|
|
|
if (!strcmp(argv[5], "dio"))
|
|
flags |= O_DIRECT;
|
|
else if (!strcmp(argv[5], "osync"))
|
|
flags |= O_SYNC;
|
|
else if (strcmp(argv[5], "buffered"))
|
|
die("Wrong IO type");
|
|
|
|
fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
|
|
|
|
total_time = get_current_us();
|
|
for (i = 0; i < count; i++) {
|
|
if (!strcmp(argv[4], "inc_num"))
|
|
*(int *)buf = inc_num++;
|
|
else if (!strcmp(argv[4], "rand"))
|
|
*(int *)buf = rand();
|
|
|
|
/* write data */
|
|
max_time_t = get_current_us();
|
|
ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
|
|
max_time_t = get_current_us() - max_time_t;
|
|
if (max_time < max_time_t)
|
|
max_time = max_time_t;
|
|
if (ret != buf_size)
|
|
break;
|
|
written += ret;
|
|
}
|
|
|
|
printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
|
|
written, argv[4],
|
|
get_current_us() - total_time,
|
|
max_time);
|
|
exit(0);
|
|
}
|
|
|
|
#define read_desc "read data from file"
|
|
#define read_help \
|
|
"f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n" \
|
|
"Read data in file_path and print nbytes\n" \
|
|
"IO can be\n" \
|
|
" buffered : buffered IO\n" \
|
|
" dio : direct IO\n" \
|
|
" mmap : mmap IO\n" \
|
|
|
|
static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
u64 buf_size = 0, ret = 0, read_cnt = 0;
|
|
u64 offset;
|
|
char *buf = NULL;
|
|
char *data;
|
|
char *print_buf = NULL;
|
|
unsigned bs, count, i, print_bytes;
|
|
int flags = 0;
|
|
int do_mmap = 0;
|
|
int fd;
|
|
|
|
if (argc != 7) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
bs = atoi(argv[1]);
|
|
if (bs > 1024)
|
|
die("Too big chunk size - limit: 4MB");
|
|
buf_size = bs * 4096;
|
|
|
|
offset = atoi(argv[2]) * buf_size;
|
|
|
|
buf = aligned_xalloc(4096, buf_size);
|
|
|
|
count = atoi(argv[3]);
|
|
if (!strcmp(argv[4], "dio"))
|
|
flags |= O_DIRECT;
|
|
else if (!strcmp(argv[4], "mmap"))
|
|
do_mmap = 1;
|
|
else if (strcmp(argv[4], "buffered"))
|
|
die("Wrong IO type");
|
|
|
|
print_bytes = atoi(argv[5]);
|
|
if (print_bytes > buf_size)
|
|
die("Print_nbytes should be less then chunk_size in kb");
|
|
|
|
print_buf = xmalloc(print_bytes);
|
|
|
|
fd = xopen(argv[6], O_RDONLY | flags, 0);
|
|
|
|
if (do_mmap) {
|
|
data = mmap(NULL, count * buf_size, PROT_READ,
|
|
MAP_SHARED, fd, offset);
|
|
if (data == MAP_FAILED)
|
|
die("Mmap failed");
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (do_mmap) {
|
|
memcpy(buf, data + offset + buf_size * i, buf_size);
|
|
ret = buf_size;
|
|
} else {
|
|
ret = pread(fd, buf, buf_size, offset + buf_size * i);
|
|
}
|
|
if (ret != buf_size)
|
|
break;
|
|
|
|
read_cnt += ret;
|
|
if (i == 0)
|
|
memcpy(print_buf, buf, print_bytes);
|
|
}
|
|
printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
|
|
printf("%08"PRIx64" : ", offset);
|
|
for (i = 1; i <= print_bytes; i++) {
|
|
printf("%02x", print_buf[i - 1]);
|
|
if (i % 16 == 0)
|
|
printf("\n%08"PRIx64" : ", offset + 16 * i);
|
|
else if (i % 2 == 0)
|
|
printf(" ");
|
|
}
|
|
printf("\n");
|
|
exit(0);
|
|
}
|
|
|
|
#define randread_desc "random read data from file"
|
|
#define randread_help \
|
|
"f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n" \
|
|
"Do random read data in file_path\n" \
|
|
"IO can be\n" \
|
|
" buffered : buffered IO\n" \
|
|
" dio : direct IO\n" \
|
|
|
|
static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
u64 buf_size = 0, ret = 0, read_cnt = 0;
|
|
u64 idx, end_idx, aligned_size;
|
|
char *buf = NULL;
|
|
unsigned bs, count, i;
|
|
int flags = 0;
|
|
int fd;
|
|
time_t t;
|
|
struct stat stbuf;
|
|
|
|
if (argc != 5) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
bs = atoi(argv[1]);
|
|
if (bs > 1024)
|
|
die("Too big chunk size - limit: 4MB");
|
|
buf_size = bs * 4096;
|
|
|
|
buf = aligned_xalloc(4096, buf_size);
|
|
|
|
count = atoi(argv[2]);
|
|
if (!strcmp(argv[3], "dio"))
|
|
flags |= O_DIRECT;
|
|
else if (strcmp(argv[3], "buffered"))
|
|
die("Wrong IO type");
|
|
|
|
fd = xopen(argv[4], O_RDONLY | flags, 0);
|
|
|
|
if (fstat(fd, &stbuf) != 0)
|
|
die_errno("fstat of source file failed");
|
|
|
|
aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
|
|
if (aligned_size < buf_size)
|
|
die("File is too small to random read");
|
|
end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
|
|
|
|
srand((unsigned) time(&t));
|
|
|
|
for (i = 0; i < count; i++) {
|
|
idx = rand() % end_idx;
|
|
|
|
ret = pread(fd, buf, buf_size, 4096 * idx);
|
|
if (ret != buf_size)
|
|
break;
|
|
|
|
read_cnt += ret;
|
|
}
|
|
printf("Read %"PRIu64" bytes\n", read_cnt);
|
|
exit(0);
|
|
}
|
|
|
|
#define fiemap_desc "get block address in file"
|
|
#define fiemap_help \
|
|
"f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
|
|
|
|
#if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
|
|
static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
unsigned count, i;
|
|
int fd;
|
|
__u64 phy_addr;
|
|
struct fiemap *fm = xmalloc(sizeof(struct fiemap) +
|
|
sizeof(struct fiemap_extent));
|
|
|
|
if (argc != 4) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fm->fm_start = atoi(argv[1]) * F2FS_BLKSIZE;
|
|
fm->fm_length = F2FS_BLKSIZE;
|
|
fm->fm_extent_count = 1;
|
|
count = atoi(argv[2]);
|
|
|
|
fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
|
|
|
|
printf("Fiemap: offset = %08"PRIx64" len = %d\n",
|
|
(u64)fm->fm_start / F2FS_BLKSIZE, count);
|
|
for (i = 0; i < count; i++) {
|
|
if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
|
|
die_errno("FIEMAP failed");
|
|
|
|
phy_addr = fm->fm_extents[0].fe_physical / F2FS_BLKSIZE;
|
|
if (phy_addr == NEW_ADDR)
|
|
printf("NEW_ADDR ");
|
|
else
|
|
printf("%llu ", phy_addr);
|
|
fm->fm_start += F2FS_BLKSIZE;
|
|
}
|
|
printf("\n");
|
|
free(fm);
|
|
exit(0);
|
|
}
|
|
#else
|
|
static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
|
|
const struct cmd_desc *UNUSED(cmd))
|
|
{
|
|
die("Not support for this platform");
|
|
}
|
|
#endif
|
|
|
|
#define gc_urgent_desc "start/end/run gc_urgent for given time period"
|
|
#define gc_urgent_help \
|
|
"f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
|
|
" - f2fs_io gc_urgent sda21 start\n" \
|
|
" - f2fs_io gc_urgent sda21 end\n" \
|
|
" - f2fs_io gc_urgent sda21 run 10\n" \
|
|
|
|
static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
char command[255];
|
|
|
|
if (argc == 3 && !strcmp(argv[2], "start")) {
|
|
printf("gc_urgent: start on %s\n", argv[1]);
|
|
sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
|
|
if (system(command))
|
|
exit(1);
|
|
} else if (argc == 3 && !strcmp(argv[2], "end")) {
|
|
printf("gc_urgent: end on %s\n", argv[1]);
|
|
sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
|
|
if (system(command))
|
|
exit(1);
|
|
} else if (argc == 4 && !strcmp(argv[2], "run")) {
|
|
printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
|
|
sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
|
|
if (system(command))
|
|
exit(1);
|
|
sleep(atoi(argv[3]));
|
|
printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
|
|
sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
|
|
if (system(command))
|
|
exit(1);
|
|
} else {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
#define defrag_file_desc "do defragment on file"
|
|
#define defrag_file_help \
|
|
"f2fs_io defrag_file [start] [length] [file_path]\n\n" \
|
|
" start : start offset of defragment region, unit: bytes\n" \
|
|
" length : bytes number of defragment region\n" \
|
|
|
|
static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
struct f2fs_defragment df;
|
|
u64 len;
|
|
int ret, fd;
|
|
|
|
if (argc != 4) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
df.start = atoll(argv[1]);
|
|
df.len = len = atoll(argv[2]);
|
|
|
|
fd = xopen(argv[3], O_RDWR, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_DEFRAGMENT failed");
|
|
|
|
printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
|
|
argv[3], df.start, df.start + len);
|
|
exit(0);
|
|
}
|
|
|
|
#define copy_desc "copy a file"
|
|
#define copy_help \
|
|
"f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n" \
|
|
" src_path : path to source file\n" \
|
|
" dst_path : path to destination file\n" \
|
|
" -d : use direct I/O\n" \
|
|
" -m : mmap the source file\n" \
|
|
" -s : use sendfile\n" \
|
|
|
|
static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int c;
|
|
int src_fd;
|
|
int dst_fd;
|
|
int open_flags = 0;
|
|
bool mmap_source_file = false;
|
|
bool use_sendfile = false;
|
|
ssize_t ret;
|
|
|
|
while ((c = getopt(argc, argv, "dms")) != -1) {
|
|
switch (c) {
|
|
case 'd':
|
|
open_flags |= O_DIRECT;
|
|
break;
|
|
case 'm':
|
|
mmap_source_file = true;
|
|
break;
|
|
case 's':
|
|
use_sendfile = true;
|
|
break;
|
|
default:
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(2);
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
if (argc != 2) {
|
|
fputs("Wrong number of arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(2);
|
|
}
|
|
if (mmap_source_file && use_sendfile)
|
|
die("-m and -s are mutually exclusive");
|
|
|
|
src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
|
|
dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
|
|
|
|
if (mmap_source_file) {
|
|
struct stat stbuf;
|
|
void *src_addr;
|
|
|
|
if (fstat(src_fd, &stbuf) != 0)
|
|
die_errno("fstat of source file failed");
|
|
|
|
if ((size_t)stbuf.st_size != stbuf.st_size)
|
|
die("Source file is too large");
|
|
|
|
src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
|
|
src_fd, 0);
|
|
if (src_addr == MAP_FAILED)
|
|
die("mmap of source file failed");
|
|
|
|
full_write(dst_fd, src_addr, stbuf.st_size);
|
|
|
|
munmap(src_addr, stbuf.st_size);
|
|
} else if (use_sendfile) {
|
|
while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
|
|
;
|
|
if (ret < 0)
|
|
die_errno("sendfile failed");
|
|
} else {
|
|
char *buf = aligned_xalloc(4096, 4096);
|
|
|
|
while ((ret = xread(src_fd, buf, 4096)) > 0)
|
|
full_write(dst_fd, buf, ret);
|
|
free(buf);
|
|
}
|
|
close(src_fd);
|
|
close(dst_fd);
|
|
}
|
|
|
|
#define get_cblocks_desc "get number of reserved blocks on compress inode"
|
|
#define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
|
|
|
|
static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
unsigned long long blkcnt;
|
|
int ret, fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
|
|
|
|
printf("%llu\n", blkcnt);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define release_cblocks_desc "release reserved blocks on compress inode"
|
|
#define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
|
|
|
|
static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
unsigned long long blkcnt;
|
|
int ret, fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
|
|
|
|
printf("%llu\n", blkcnt);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define reserve_cblocks_desc "reserve blocks on compress inode"
|
|
#define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
|
|
|
|
static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
unsigned long long blkcnt;
|
|
int ret, fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
|
|
|
|
printf("%llu\n", blkcnt);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define get_coption_desc "get compression option of a compressed file"
|
|
#define get_coption_help \
|
|
"f2fs_io get_coption [file]\n\n" \
|
|
" algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
|
|
" log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
|
|
|
|
static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
struct f2fs_comp_option option;
|
|
int ret, fd;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
|
|
|
|
printf("compression algorithm:%u\n", option.algorithm);
|
|
printf("compression cluster log size:%u\n", option.log_cluster_size);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define set_coption_desc "set compression option of a compressed file"
|
|
#define set_coption_help \
|
|
"f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n" \
|
|
" algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
|
|
" log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
|
|
|
|
static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
struct f2fs_comp_option option;
|
|
int fd, ret;
|
|
|
|
if (argc != 4) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
option.algorithm = atoi(argv[1]);
|
|
option.log_cluster_size = atoi(argv[2]);
|
|
|
|
fd = xopen(argv[3], O_WRONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
|
|
|
|
printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
|
|
option.algorithm, option.log_cluster_size);
|
|
exit(0);
|
|
}
|
|
|
|
#define decompress_desc "decompress an already compressed file"
|
|
#define decompress_help "f2fs_io decompress [file_path]\n\n"
|
|
|
|
static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int fd, ret;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_WRONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define compress_desc "compress a compression enabled file"
|
|
#define compress_help "f2fs_io compress [file_path]\n\n"
|
|
|
|
static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
|
|
{
|
|
int fd, ret;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_WRONLY, 0);
|
|
|
|
ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
|
|
if (ret < 0)
|
|
die_errno("F2FS_IOC_COMPRESS_FILE failed");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define get_filename_encrypt_mode_desc "get file name encrypt mode"
|
|
#define get_filename_encrypt_mode_help \
|
|
"f2fs_io filename_encrypt_mode [file or directory path]\n\n" \
|
|
"Get the file name encription mode of the given file/directory.\n" \
|
|
|
|
static void do_get_filename_encrypt_mode (int argc, char **argv,
|
|
const struct cmd_desc *cmd)
|
|
{
|
|
static const char *enc_name[] = {
|
|
"invalid", /* FS_ENCRYPTION_MODE_INVALID (0) */
|
|
"aes-256-xts", /* FS_ENCRYPTION_MODE_AES_256_XTS (1) */
|
|
"aes-256-gcm", /* FS_ENCRYPTION_MODE_AES_256_GCM (2) */
|
|
"aes-256-cbc", /* FS_ENCRYPTION_MODE_AES_256_CBC (3) */
|
|
"aes-256-cts", /* FS_ENCRYPTION_MODE_AES_256_CTS (4) */
|
|
"aes-128-cbc", /* FS_ENCRYPTION_MODE_AES_128_CBC (5) */
|
|
"aes-128-cts", /* FS_ENCRYPTION_MODE_AES_128_CTS (6) */
|
|
"speck128-256-xts", /* FS_ENCRYPTION_MODE_SPECK128_256_XTS (7) */
|
|
"speck128-256-cts", /* FS_ENCRYPTION_MODE_SPECK128_256_CTS (8) */
|
|
"adiantum", /* FS_ENCRYPTION_MODE_ADIANTUM (9) */
|
|
};
|
|
int fd, mode, ret;
|
|
struct fscrypt_get_policy_ex_arg arg;
|
|
|
|
if (argc != 2) {
|
|
fputs("Excess arguments\n\n", stderr);
|
|
fputs(cmd->cmd_help, stderr);
|
|
exit(1);
|
|
}
|
|
|
|
fd = xopen(argv[1], O_RDONLY, 0);
|
|
arg.policy_size = sizeof(arg.policy);
|
|
ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
|
|
if (ret != 0 && errno == ENOTTY)
|
|
ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
|
|
close(fd);
|
|
|
|
if (ret) {
|
|
perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
|
|
exit(1);
|
|
}
|
|
|
|
switch (arg.policy.version) {
|
|
case FSCRYPT_POLICY_V1:
|
|
mode = arg.policy.v1.filenames_encryption_mode;
|
|
break;
|
|
case FSCRYPT_POLICY_V2:
|
|
mode = arg.policy.v2.filenames_encryption_mode;
|
|
break;
|
|
default:
|
|
printf("Do not support policy version: %d\n",
|
|
arg.policy.version);
|
|
exit(1);
|
|
}
|
|
|
|
if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
|
|
printf("Do not support algorithm: %d\n", mode);
|
|
exit(1);
|
|
}
|
|
printf ("%s\n", enc_name[mode]);
|
|
exit(0);
|
|
}
|
|
|
|
#define CMD_HIDDEN 0x0001
|
|
#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
|
|
#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
|
|
|
|
static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
|
|
const struct cmd_desc cmd_list[] = {
|
|
_CMD(help),
|
|
CMD(fsync),
|
|
CMD(set_verity),
|
|
CMD(getflags),
|
|
CMD(setflags),
|
|
CMD(shutdown),
|
|
CMD(pinfile),
|
|
CMD(fallocate),
|
|
CMD(erase),
|
|
CMD(write),
|
|
CMD(read),
|
|
CMD(randread),
|
|
CMD(fiemap),
|
|
CMD(gc_urgent),
|
|
CMD(defrag_file),
|
|
CMD(copy),
|
|
CMD(get_cblocks),
|
|
CMD(release_cblocks),
|
|
CMD(reserve_cblocks),
|
|
CMD(get_coption),
|
|
CMD(set_coption),
|
|
CMD(decompress),
|
|
CMD(compress),
|
|
CMD(get_filename_encrypt_mode),
|
|
{ NULL, NULL, NULL, NULL, 0 }
|
|
};
|
|
|
|
static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
|
|
{
|
|
const struct cmd_desc *p;
|
|
|
|
if (argc > 1) {
|
|
for (p = cmd_list; p->cmd_name; p++) {
|
|
if (p->cmd_flags & CMD_HIDDEN)
|
|
continue;
|
|
if (strcmp(p->cmd_name, argv[1]) == 0) {
|
|
putc('\n', stdout);
|
|
fputs("USAGE:\n ", stdout);
|
|
fputs(p->cmd_help, stdout);
|
|
exit(0);
|
|
}
|
|
}
|
|
printf("Unknown command: %s\n\n", argv[1]);
|
|
}
|
|
|
|
fputs("Available commands:\n", stdout);
|
|
for (p = cmd_list; p->cmd_name; p++) {
|
|
if (p->cmd_flags & CMD_HIDDEN)
|
|
continue;
|
|
printf(" %-20s %s\n", p->cmd_name, p->cmd_desc);
|
|
}
|
|
printf("\nTo get more information on a command, "
|
|
"type 'f2fs_io help cmd'\n");
|
|
exit(0);
|
|
}
|
|
|
|
static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
|
|
void *UNUSED(context))
|
|
{
|
|
exit(-1);
|
|
}
|
|
|
|
static void sigcatcher_setup(void)
|
|
{
|
|
struct sigaction sa;
|
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
|
sa.sa_sigaction = die_signal_handler;
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGHUP, &sa, 0);
|
|
sigaction(SIGINT, &sa, 0);
|
|
sigaction(SIGQUIT, &sa, 0);
|
|
sigaction(SIGFPE, &sa, 0);
|
|
sigaction(SIGILL, &sa, 0);
|
|
sigaction(SIGBUS, &sa, 0);
|
|
sigaction(SIGSEGV, &sa, 0);
|
|
sigaction(SIGABRT, &sa, 0);
|
|
sigaction(SIGPIPE, &sa, 0);
|
|
sigaction(SIGALRM, &sa, 0);
|
|
sigaction(SIGTERM, &sa, 0);
|
|
sigaction(SIGUSR1, &sa, 0);
|
|
sigaction(SIGUSR2, &sa, 0);
|
|
sigaction(SIGPOLL, &sa, 0);
|
|
sigaction(SIGPROF, &sa, 0);
|
|
sigaction(SIGSYS, &sa, 0);
|
|
sigaction(SIGTRAP, &sa, 0);
|
|
sigaction(SIGVTALRM, &sa, 0);
|
|
sigaction(SIGXCPU, &sa, 0);
|
|
sigaction(SIGXFSZ, &sa, 0);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const struct cmd_desc *cmd;
|
|
|
|
if (argc < 2)
|
|
do_help(argc, argv, cmd_list);
|
|
|
|
sigcatcher_setup();
|
|
for (cmd = cmd_list; cmd->cmd_name; cmd++) {
|
|
if (strcmp(cmd->cmd_name, argv[1]) == 0) {
|
|
cmd->cmd_func(argc - 1, argv + 1, cmd);
|
|
exit(0);
|
|
}
|
|
}
|
|
printf("Unknown command: %s\n\n", argv[1]);
|
|
do_help(1, argv, cmd_list);
|
|
return 0;
|
|
}
|