diff options
Diffstat (limited to 'src/pmdk/src/tools/pmempool/dump.c')
-rw-r--r-- | src/pmdk/src/tools/pmempool/dump.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/pmdk/src/tools/pmempool/dump.c b/src/pmdk/src/tools/pmempool/dump.c new file mode 100644 index 000000000..3c7b07441 --- /dev/null +++ b/src/pmdk/src/tools/pmempool/dump.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2014-2019, Intel Corporation */ + +/* + * create.c -- pmempool create command source file + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <err.h> +#include "common.h" +#include "dump.h" +#include "output.h" +#include "os.h" +#include "libpmemblk.h" +#include "libpmemlog.h" + +#define VERBOSE_DEFAULT 1 + +/* + * pmempool_dump -- context and arguments for dump command + */ +struct pmempool_dump { + char *fname; + char *ofname; + char *range; + FILE *ofh; + int hex; + uint64_t bsize; + struct ranges ranges; + size_t chunksize; + uint64_t chunkcnt; +}; + +/* + * pmempool_dump_default -- default arguments and context values + */ +static const struct pmempool_dump pmempool_dump_default = { + .fname = NULL, + .ofname = NULL, + .range = NULL, + .ofh = NULL, + .hex = 1, + .bsize = 0, + .chunksize = 0, + .chunkcnt = 0, +}; + +/* + * long_options -- command line options + */ +static const struct option long_options[] = { + {"output", required_argument, NULL, 'o' | OPT_ALL}, + {"binary", no_argument, NULL, 'b' | OPT_ALL}, + {"range", required_argument, NULL, 'r' | OPT_ALL}, + {"chunk", required_argument, NULL, 'c' | OPT_LOG}, + {"help", no_argument, NULL, 'h' | OPT_ALL}, + {NULL, 0, NULL, 0 }, +}; + +/* + * help_str -- string for help message + */ +static const char * const help_str = +"Dump user data from pool\n" +"\n" +"Available options:\n" +" -o, --output <file> output file name\n" +" -b, --binary dump data in binary format\n" +" -r, --range <range> range of bytes/blocks/data chunks\n" +" -c, --chunk <size> size of chunk for PMEMLOG pool\n" +" -h, --help display this help and exit\n" +"\n" +"For complete documentation see %s-dump(1) manual page.\n" +; + +/* + * print_usage -- print application usage short description + */ +static void +print_usage(const char *appname) +{ + printf("Usage: %s dump [<args>] <file>\n", appname); +} + +/* + * print_version -- print version string + */ +static void +print_version(const char *appname) +{ + printf("%s %s\n", appname, SRCVERSION); +} + +/* + * pmempool_dump_help -- print help message for dump command + */ +void +pmempool_dump_help(const char *appname) +{ + print_usage(appname); + print_version(appname); + printf(help_str, appname); +} + +/* + * pmempool_dump_log_process_chunk -- callback for pmemlog_walk + */ +static int +pmempool_dump_log_process_chunk(const void *buf, size_t len, void *arg) +{ + struct pmempool_dump *pdp = (struct pmempool_dump *)arg; + + if (len == 0) + return 0; + + struct range *curp = NULL; + if (pdp->chunksize) { + PMDK_LIST_FOREACH(curp, &pdp->ranges.head, next) { + if (pdp->chunkcnt >= curp->first && + pdp->chunkcnt <= curp->last && + pdp->chunksize <= len) { + if (pdp->hex) { + outv_hexdump(VERBOSE_DEFAULT, + buf, pdp->chunksize, + pdp->chunksize * pdp->chunkcnt, + 0); + } else { + if (fwrite(buf, pdp->chunksize, + 1, pdp->ofh) != 1) + err(1, "%s", pdp->ofname); + } + } + } + pdp->chunkcnt++; + } else { + PMDK_LIST_FOREACH(curp, &pdp->ranges.head, next) { + if (curp->first >= len) + continue; + uint8_t *ptr = (uint8_t *)buf + curp->first; + if (curp->last >= len) + curp->last = len - 1; + uint64_t count = curp->last - curp->first + 1; + if (pdp->hex) { + outv_hexdump(VERBOSE_DEFAULT, ptr, + count, curp->first, 0); + } else { + if (fwrite(ptr, count, 1, pdp->ofh) != 1) + err(1, "%s", pdp->ofname); + } + } + } + + return 1; +} + +/* + * pmempool_dump_parse_range -- parse range passed by arguments + */ +static int +pmempool_dump_parse_range(struct pmempool_dump *pdp, size_t max) +{ + struct range entire; + memset(&entire, 0, sizeof(entire)); + + entire.last = max; + + if (util_parse_ranges(pdp->range, &pdp->ranges, entire)) { + outv_err("invalid range value specified" + " -- '%s'\n", pdp->range); + return -1; + } + + if (PMDK_LIST_EMPTY(&pdp->ranges.head)) + util_ranges_add(&pdp->ranges, entire); + + return 0; +} + +/* + * pmempool_dump_log -- dump data from pmem log pool + */ +static int +pmempool_dump_log(struct pmempool_dump *pdp) +{ + PMEMlogpool *plp = pmemlog_open(pdp->fname); + if (!plp) { + warn("%s", pdp->fname); + return -1; + } + + os_off_t off = pmemlog_tell(plp); + if (off < 0) { + warn("%s", pdp->fname); + pmemlog_close(plp); + return -1; + } + + if (off == 0) + goto end; + + size_t max = (size_t)off - 1; + if (pdp->chunksize) + max /= pdp->chunksize; + + if (pmempool_dump_parse_range(pdp, max)) + return -1; + + pdp->chunkcnt = 0; + pmemlog_walk(plp, pdp->chunksize, pmempool_dump_log_process_chunk, pdp); + +end: + pmemlog_close(plp); + + return 0; +} + +/* + * pmempool_dump_blk -- dump data from pmem blk pool + */ +static int +pmempool_dump_blk(struct pmempool_dump *pdp) +{ + PMEMblkpool *pbp = pmemblk_open(pdp->fname, pdp->bsize); + if (!pbp) { + warn("%s", pdp->fname); + return -1; + } + + if (pmempool_dump_parse_range(pdp, pmemblk_nblock(pbp) - 1)) + return -1; + + uint8_t *buff = malloc(pdp->bsize); + if (!buff) + err(1, "Cannot allocate memory for pmemblk block buffer"); + + int ret = 0; + + uint64_t i; + struct range *curp = NULL; + PMDK_LIST_FOREACH(curp, &pdp->ranges.head, next) { + assert((os_off_t)curp->last >= 0); + for (i = curp->first; i <= curp->last; i++) { + if (pmemblk_read(pbp, buff, (os_off_t)i)) { + ret = -1; + outv_err("reading block number %lu " + "failed\n", i); + break; + } + + if (pdp->hex) { + uint64_t offset = i * pdp->bsize; + outv_hexdump(VERBOSE_DEFAULT, buff, + pdp->bsize, offset, 0); + } else { + if (fwrite(buff, pdp->bsize, 1, + pdp->ofh) != 1) { + warn("write"); + ret = -1; + break; + } + } + } + } + + free(buff); + pmemblk_close(pbp); + + return ret; +} + +static const struct option_requirement option_requirements[] = { + { 0, 0, 0} +}; + +/* + * pmempool_dump_func -- dump command main function + */ +int +pmempool_dump_func(const char *appname, int argc, char *argv[]) +{ + struct pmempool_dump pd = pmempool_dump_default; + PMDK_LIST_INIT(&pd.ranges.head); + out_set_vlevel(VERBOSE_DEFAULT); + + struct options *opts = util_options_alloc(long_options, + sizeof(long_options) / sizeof(long_options[0]), + option_requirements); + int ret = 0; + long long chunksize; + int opt; + while ((opt = util_options_getopt(argc, argv, + "ho:br:c:", opts)) != -1) { + switch (opt) { + case 'o': + pd.ofname = optarg; + break; + case 'b': + pd.hex = 0; + break; + case 'r': + pd.range = optarg; + break; + case 'c': + chunksize = atoll(optarg); + if (chunksize <= 0) { + outv_err("invalid chunk size specified '%s'\n", + optarg); + exit(EXIT_FAILURE); + } + pd.chunksize = (size_t)chunksize; + break; + case 'h': + pmempool_dump_help(appname); + exit(EXIT_SUCCESS); + default: + print_usage(appname); + exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + pd.fname = argv[optind]; + } else { + print_usage(appname); + exit(EXIT_FAILURE); + } + + if (pd.ofname == NULL) { + /* use standard output by default */ + pd.ofh = stdout; + } else { + pd.ofh = os_fopen(pd.ofname, "wb"); + if (!pd.ofh) { + warn("%s", pd.ofname); + exit(EXIT_FAILURE); + } + } + + /* set output stream - stdout or file passed by -o option */ + out_set_stream(pd.ofh); + + struct pmem_pool_params params; + /* parse pool type and block size for pmem blk pool */ + pmem_pool_parse_params(pd.fname, ¶ms, 1); + + ret = util_options_verify(opts, params.type); + if (ret) + goto out; + + switch (params.type) { + case PMEM_POOL_TYPE_LOG: + ret = pmempool_dump_log(&pd); + break; + case PMEM_POOL_TYPE_BLK: + pd.bsize = params.blk.bsize; + ret = pmempool_dump_blk(&pd); + break; + case PMEM_POOL_TYPE_OBJ: + outv_err("%s: PMEMOBJ pool not supported\n", pd.fname); + ret = -1; + goto out; + case PMEM_POOL_TYPE_UNKNOWN: + outv_err("%s: unknown pool type -- '%s'\n", pd.fname, + params.signature); + ret = -1; + goto out; + default: + outv_err("%s: cannot determine type of pool\n", pd.fname); + ret = -1; + goto out; + } + + if (ret) + outv_err("%s: dumping pool file failed\n", pd.fname); + +out: + if (pd.ofh != stdout) + fclose(pd.ofh); + + util_ranges_clear(&pd.ranges); + + util_options_free(opts); + + return ret; +} |