/* * pmempool_info_part -- (internal) print info about poolset part */ static int pmempool_info_part(struct pmem_info *pip, unsigned repn, unsigned partn, int v) { /* get path of the part file */ const char *path = NULL; if (repn != UNDEF_REPLICA && partn != UNDEF_PART) { outv(v, "part %u:\n", partn); struct pool_set_part *part = &pip->pfile->poolset->replica[repn]->part[partn]; path = part->path; } else { outv(v, "Part file:\n"); path = pip->file_name; } outv_field(v, "path", "%s", path); /* get type of the part file */ int is_dev_dax = util_file_is_device_dax(path); const char *type_str = is_dev_dax ? "device dax" : "regular file"; outv_field(v, "type", "%s", type_str); /* get size of the part file */ ssize_t size = util_file_get_size(path); if (size < 0) { outv_err("couldn't get size of %s", path); return -1; } outv_field(v, "size", "%s", out_get_size_str((size_t)size, pip->args.human)); return 0; }
/* * rm_poolset -- remove files parsed from poolset file */ static void rm_poolset(const char *file) { int ret = util_poolset_foreach_part(file, rm_poolset_cb, NULL); if (ret) { if (ret == -1) { outv_err("parsing poolset failed: %s\n", out_get_errormsg()); exit(1); } if (!force) { outv_err("removing '%s' failed\n", file); exit(1); } return; } }
/* * rm_poolset -- remove files parsed from poolset file */ static void rm_poolset(const char *file) { int ret = util_poolset_foreach_part(file, rm_poolset_cb, NULL); if (ret) { if (!force) { outv_err("cannot parse poolset file '%s'\n", file); exit(1); } return; } }
/* * pmempool_info_pool_hdr -- print pool header information */ static int pmempool_info_pool_hdr(struct pmem_info *pip, int v) { int ret = 0; struct pool_hdr *hdr = malloc(sizeof (struct pool_hdr)); if (!hdr) err(1, "Cannot allocate memory for pool_hdr"); if (pmempool_info_read(pip, hdr, sizeof (*hdr), 0)) { outv_err("cannot read pool header\n"); free(hdr); return -1; } outv(v, "POOL Header:\n"); outv_hexdump(pip->args.vhdrdump, hdr, sizeof (*hdr), 0, 1); util_convert2h_pool_hdr(hdr); outv_field(v, "Signature", "%.*s%s", POOL_HDR_SIG_LEN, hdr->signature, pip->params.is_part ? " [part file]" : ""); outv_field(v, "Major", "%d", hdr->major); outv_field(v, "Mandatory features", "0x%x", hdr->incompat_features); outv_field(v, "Not mandatory features", "0x%x", hdr->compat_features); outv_field(v, "Forced RO", "0x%x", hdr->ro_compat_features); outv_field(v, "Pool set UUID", "%s", out_get_uuid_str(hdr->poolset_uuid)); outv_field(v, "UUID", "%s", out_get_uuid_str(hdr->uuid)); outv_field(v, "Previous part UUID", "%s", out_get_uuid_str(hdr->prev_part_uuid)); outv_field(v, "Next part UUID", "%s", out_get_uuid_str(hdr->next_part_uuid)); outv_field(v, "Previous replica UUID", "%s", out_get_uuid_str(hdr->prev_repl_uuid)); outv_field(v, "Next replica UUID", "%s", out_get_uuid_str(hdr->next_repl_uuid)); outv_field(v, "Creation Time", "%s", out_get_time_str((time_t)hdr->crtime)); outv_field(v, "Checksum", "%s", out_get_checksum(hdr, sizeof (*hdr), &hdr->checksum)); free(hdr); return ret; }
/* * help_func -- prints help message for specified command */ static int help_func(char *appname, int argc, char *argv[]) { if (argc > 1) { char *cmd_str = argv[1]; struct command *cmdp = get_command(cmd_str); if (cmdp && cmdp->help) { cmdp->help(appname); return 0; } else { outv_err("No help text for '%s' command\n", cmd_str); return -1; } } else { print_help(appname); return -1; } }
/* * pmempool_info_get_pool_type -- get pool type to parse * * Return pool type to parse based on headers data and command line arguments. */ static pmem_pool_type_t pmempool_info_get_pool_type(struct pmem_info *pip) { int ret = 0; int is_poolset = !pmem_pool_check_pool_set(pip->file_name); struct pool_hdr hdr; pip->fd = util_file_open(pip->file_name, NULL, 0, O_RDONLY); if (pip->fd < 0) { warn("%s", pip->file_name); return PMEM_POOL_TYPE_UNKNOWN; } if (is_poolset) { if (pmempool_setup_poolset(pip)) goto err; } if (pmempool_info_read(pip, &hdr, sizeof (hdr), 0)) { outv_err("cannot read pool header\n"); goto err; } /* * If force flag is set 'types' fields _must_ hold * single pool type - this is validated when processing * command line arguments. */ if (pip->args.force) return pip->args.type; /* parse pool type from pool header */ ret = pmem_pool_type_parse_hdr(&hdr); return ret; err: close(pip->fd); pip->fd = -1; return PMEM_POOL_TYPE_UNKNOWN; }
int main(int argc, char *argv[]) { int opt; int option_index; util_init(); if (argc < 2) { print_usage(APPNAME); return 0; } while ((opt = getopt_long(2, argv, "Vh", long_options, &option_index)) != -1) { switch (opt) { case 'V': print_version(APPNAME); return 0; case 'h': print_help(APPNAME); return 0; default: print_usage(APPNAME); return -1; } } char *cmd_str = argv[optind]; struct command *cmdp = get_command(cmd_str); if (cmdp) return cmdp->func(APPNAME, argc - 1, argv + 1); outv_err("'%s' -- unknown command\n", cmd_str); return -1; }
/* * pmempool_info_file -- print info about single file */ static int pmempool_info_file(struct pmem_info *pip, const char *file_name) { int ret = 0; pip->file_name = file_name; /* * If force flag is set 'types' fields _must_ hold * single pool type - this is validated when processing * command line arguments. */ if (pip->args.force) { pip->type = pip->args.type; } else { if (pmem_pool_parse_params(file_name, &pip->params, 1)) { if (errno) perror(file_name); else outv_err("%s: cannot determine type of pool\n", file_name); return -1; } pip->type = pip->params.type; } if (PMEM_POOL_TYPE_UNKNOWN == pip->type) { ret = -1; outv_err("%s: unknown pool type -- '%s'\n", file_name, pip->params.signature); } else { if (util_options_verify(pip->opts, pip->type)) return -1; pip->pfile = pool_set_file_open(file_name, 1, 1); if (!pip->pfile) { perror(file_name); return -1; } if (pip->args.obj.replica && pool_set_file_set_replica(pip->pfile, pip->args.obj.replica)) { outv_err("invalid replica number '%lu'", pip->args.obj.replica); } /* hdr info is not present in btt device */ if (pip->type != PMEM_POOL_TYPE_BTT) { if (pmempool_info_pool_hdr(pip, VERBOSE_DEFAULT)) { ret = -1; goto out_close; } } if (pip->params.is_part) { ret = 0; goto out_close; } switch (pip->type) { case PMEM_POOL_TYPE_LOG: ret = pmempool_info_log(pip); break; case PMEM_POOL_TYPE_BLK: ret = pmempool_info_blk(pip); break; case PMEM_POOL_TYPE_OBJ: ret = pmempool_info_obj(pip); break; case PMEM_POOL_TYPE_BTT: ret = pmempool_info_btt(pip); break; case PMEM_POOL_TYPE_UNKNOWN: default: ret = -1; break; } out_close: pool_set_file_close(pip->pfile); } return ret; }
/* * pmempool_info_pool_hdr -- print pool header information */ static int pmempool_info_pool_hdr(struct pmem_info *pip, int v) { static const char *alignment_desc_str[] = { " char", " short", " int", " long", " long long", " size_t", " off_t", " float", " double", " long double", " void *", }; static const size_t alignment_desc_n = sizeof(alignment_desc_str) / sizeof(alignment_desc_str[0]); int ret = 0; struct pool_hdr *hdr = malloc(sizeof(struct pool_hdr)); if (!hdr) err(1, "Cannot allocate memory for pool_hdr"); if (pmempool_info_read(pip, hdr, sizeof(*hdr), 0)) { outv_err("cannot read pool header\n"); free(hdr); return -1; } struct arch_flags arch_flags; if (util_get_arch_flags(&arch_flags)) { outv_err("cannot read architecture flags\n"); free(hdr); return -1; } outv(v, "POOL Header:\n"); outv_hexdump(pip->args.vhdrdump, hdr, sizeof(*hdr), 0, 1); util_convert2h_pool_hdr(hdr); outv_field(v, "Signature", "%.*s%s", POOL_HDR_SIG_LEN, hdr->signature, pip->params.is_part ? " [part file]" : ""); outv_field(v, "Major", "%d", hdr->major); outv_field(v, "Mandatory features", "0x%x", hdr->incompat_features); outv_field(v, "Not mandatory features", "0x%x", hdr->compat_features); outv_field(v, "Forced RO", "0x%x", hdr->ro_compat_features); outv_field(v, "Pool set UUID", "%s", out_get_uuid_str(hdr->poolset_uuid)); outv_field(v, "UUID", "%s", out_get_uuid_str(hdr->uuid)); outv_field(v, "Previous part UUID", "%s", out_get_uuid_str(hdr->prev_part_uuid)); outv_field(v, "Next part UUID", "%s", out_get_uuid_str(hdr->next_part_uuid)); outv_field(v, "Previous replica UUID", "%s", out_get_uuid_str(hdr->prev_repl_uuid)); outv_field(v, "Next replica UUID", "%s", out_get_uuid_str(hdr->next_repl_uuid)); outv_field(v, "Creation Time", "%s", out_get_time_str((time_t)hdr->crtime)); uint64_t ad = hdr->arch_flags.alignment_desc; uint64_t cur_ad = arch_flags.alignment_desc; outv_field(v, "Alignment Descriptor", "%s", out_get_alignment_desc_str(ad, cur_ad)); for (size_t i = 0; i < alignment_desc_n; i++) { uint64_t a = GET_ALIGNMENT(ad, i); if (ad == cur_ad) { outv_field(v + 1, alignment_desc_str[i], "%2d", a); } else { uint64_t av = GET_ALIGNMENT(cur_ad, i); if (a == av) { outv_field(v + 1, alignment_desc_str[i], "%2d [OK]", a); } else { outv_field(v + 1, alignment_desc_str[i], "%2d [wrong! should be %2d]", a, av); } } } outv_field(v, "Class", "%s", out_get_ei_class_str(hdr->arch_flags.ei_class)); outv_field(v, "Data", "%s", out_get_ei_data_str(hdr->arch_flags.ei_data)); outv_field(v, "Machine", "%s", out_get_e_machine_str(hdr->arch_flags.e_machine)); outv_field(v, "Checksum", "%s", out_get_checksum(hdr, sizeof(*hdr), &hdr->checksum)); free(hdr); return ret; }
/* * parse_args -- parse command line arguments * * Parse command line arguments and store them in pmempool_info_args * structure. * Terminates process if invalid arguments passed. */ static int parse_args(char *appname, int argc, char *argv[], struct pmempool_info_args *argsp, struct options *opts) { int opt; if (argc == 1) { print_usage(appname); return -1; } struct ranges *rangesp = &argsp->ranges; while ((opt = util_options_getopt(argc, argv, "vhnf:ezuF:L:c:dmxVw:gBsr:lRS:OECZHT:bot:aAp:", opts)) != -1) { switch (opt) { case 'v': argsp->vlevel = VERBOSE_MAX; break; case 'V': print_version(appname); exit(EXIT_SUCCESS); case 'h': pmempool_info_help(appname); exit(EXIT_SUCCESS); case 'n': argsp->human = true; break; case 'f': argsp->type = pmem_pool_type_parse_str(optarg); if (argsp->type == PMEM_POOL_TYPE_UNKNOWN) { outv_err("'%s' -- unknown pool type\n", optarg); return -1; } argsp->force = true; break; case 'e': argsp->blk.skip_error = true; break; case 'z': argsp->blk.skip_zeros = true; break; case 'u': argsp->blk.skip_no_flag = true; break; case 'r': if (util_parse_ranges(optarg, rangesp, ENTIRE_UINT64)) { outv_err("'%s' -- cannot parse range(s)\n", optarg); return -1; } if (rangesp == &argsp->ranges) argsp->use_range = 1; break; case 'd': argsp->vdata = VERBOSE_DEFAULT; break; case 'm': argsp->blk.vmap = VERBOSE_DEFAULT; break; case 'g': argsp->blk.vflog = VERBOSE_DEFAULT; break; case 'B': argsp->blk.vbackup = VERBOSE_DEFAULT; break; case 'x': argsp->vhdrdump = VERBOSE_DEFAULT; break; case 's': argsp->vstats = VERBOSE_DEFAULT; break; case 'w': argsp->log.walk = (size_t)atoll(optarg); if (argsp->log.walk == 0) { outv_err("'%s' -- invalid chunk size\n", optarg); return -1; } break; case 'l': argsp->obj.vlanes = VERBOSE_DEFAULT; rangesp = &argsp->obj.lane_ranges; break; case 'R': argsp->obj.lanes_recovery = true; break; case 'S': argsp->obj.lane_sections = 0; if (util_parse_lane_sections(optarg, &argsp->obj.lane_sections)) { outv_err("'%s' -- cannot parse" " lane section(s)\n", optarg); return -1; } break; case 'O': argsp->obj.vobjects = VERBOSE_DEFAULT; rangesp = &argsp->ranges; break; case 'a': argsp->obj.voobhdr = VERBOSE_DEFAULT; break; case 'A': argsp->obj.valloc = VERBOSE_DEFAULT; break; case 'E': argsp->obj.ignore_empty_obj = true; break; case 'Z': argsp->obj.vzonehdr = VERBOSE_DEFAULT; rangesp = &argsp->obj.zone_ranges; break; case 'C': argsp->obj.vchunkhdr = VERBOSE_DEFAULT; rangesp = &argsp->obj.chunk_ranges; break; case 'H': argsp->obj.vheap = VERBOSE_DEFAULT; break; case 'T': argsp->obj.chunk_types = 0; if (util_parse_chunk_types(optarg, &argsp->obj.chunk_types) || (argsp->obj.chunk_types & (1 << CHUNK_TYPE_UNKNOWN))) { outv_err("'%s' -- cannot parse chunk type(s)\n", optarg); return -1; } break; case 'o': argsp->obj.vroot = VERBOSE_DEFAULT; break; case 't': if (util_parse_ranges(optarg, &argsp->obj.type_ranges, ENTIRE_UINT64)) { outv_err("'%s' -- cannot parse range(s)\n", optarg); return -1; } break; case 'b': argsp->obj.vbitmap = VERBOSE_DEFAULT; break; case 'p': { long long ll = atoll(optarg); if (ll < 0) { outv_err("'%s' -- replica cannot be negative\n", optarg); return -1; } argsp->obj.replica = (size_t)ll; break; } default: print_usage(appname); return -1; } } if (optind < argc) { argsp->file = argv[optind]; } else { print_usage(appname); return -1; } if (!argsp->use_range) util_ranges_add(&argsp->ranges, ENTIRE_UINT64); if (util_ranges_empty(&argsp->obj.type_ranges)) util_ranges_add(&argsp->obj.type_ranges, ENTIRE_UINT64); if (util_ranges_empty(&argsp->obj.lane_ranges)) util_ranges_add(&argsp->obj.lane_ranges, ENTIRE_UINT64); if (util_ranges_empty(&argsp->obj.zone_ranges)) util_ranges_add(&argsp->obj.zone_ranges, ENTIRE_UINT64); if (util_ranges_empty(&argsp->obj.chunk_ranges)) util_ranges_add(&argsp->obj.chunk_ranges, ENTIRE_UINT64); return 0; }
/* * pmempool_info_file -- print info about single file */ static int pmempool_info_file(struct pmem_info *pip, const char *file_name) { int ret = 0; pip->file_name = file_name; /* * If force flag is set 'types' fields _must_ hold * single pool type - this is validated when processing * command line arguments. */ if (pip->args.force) { pip->type = pip->args.type; } else { if (pmem_pool_parse_params(file_name, &pip->params, 1)) { if (errno) perror(file_name); else outv_err("%s: cannot determine type of pool\n", file_name); return -1; } pip->type = pip->params.type; } if (PMEM_POOL_TYPE_UNKNOWN == pip->type) { outv_err("%s: unknown pool type -- '%s'\n", file_name, pip->params.signature); return -1; } else if (!pip->args.force && !pip->params.is_checksum_ok) { outv_err("%s: invalid checksum\n", file_name); return -1; } else { if (util_options_verify(pip->opts, pip->type)) return -1; pip->pfile = pool_set_file_open(file_name, 0, !pip->args.force); if (!pip->pfile) { perror(file_name); return -1; } if (pip->type != PMEM_POOL_TYPE_BTT) { struct pool_set *ps = pip->pfile->poolset; for (unsigned r = 0; r < ps->nreplicas; ++r) { if (ps->replica[r]->remote == NULL && mprotect(ps->replica[r]->part[0].addr, ps->replica[r]->repsize, PROT_READ) < 0) { outv_err( "%s: failed to change pool protection", pip->pfile->fname); ret = -1; goto out_close; } } } if (pip->args.obj.replica) { size_t nreplicas = pool_set_file_nreplicas(pip->pfile); if (nreplicas == 1) { outv_err("only master replica available"); ret = -1; goto out_close; } if (pip->args.obj.replica >= nreplicas) { outv_err("replica number out of range" " (valid range is: 0-%" PRIu64 ")", nreplicas - 1); ret = -1; goto out_close; } if (pool_set_file_set_replica(pip->pfile, pip->args.obj.replica)) { outv_err("setting replica number failed"); ret = -1; goto out_close; } } /* hdr info is not present in btt device */ if (pip->type != PMEM_POOL_TYPE_BTT) { if (pip->params.is_poolset && pmempool_info_poolset(pip, VERBOSE_DEFAULT)) { ret = -1; goto out_close; } if (!pip->params.is_poolset && pmempool_info_part(pip, UNDEF_REPLICA, UNDEF_PART, VERBOSE_DEFAULT)) { ret = -1; goto out_close; } if (pmempool_info_pool_hdr(pip, VERBOSE_DEFAULT)) { ret = -1; goto out_close; } } if (pip->params.is_part) { ret = 0; goto out_close; } switch (pip->type) { case PMEM_POOL_TYPE_LOG: ret = pmempool_info_log(pip); break; case PMEM_POOL_TYPE_BLK: ret = pmempool_info_blk(pip); break; case PMEM_POOL_TYPE_OBJ: ret = pmempool_info_obj(pip); break; case PMEM_POOL_TYPE_BTT: ret = pmempool_info_btt(pip); break; case PMEM_POOL_TYPE_UNKNOWN: default: ret = -1; break; } out_close: pool_set_file_close(pip->pfile); } return ret; }
/* * remove_remote -- (internal) remove remote pool */ static int remove_remote(const char *target, const char *pool_set) { #ifdef USE_RPMEM char cask = 'y'; switch (ask_mode) { case ASK_ALWAYS: cask = '?'; break; case ASK_NEVER: case ASK_SOMETIMES: cask = 'y'; break; } if (ask_Yn(cask, "remove remote pool '%s' on '%s'?", pool_set, target) != 'y') return 0; struct rpmem_target_info *info = rpmem_target_parse(target); if (!info) goto err_parse; struct rpmem_ssh *ssh; if (force) { ssh = rpmem_ssh_exec(info, "--remove", pool_set, "--force", NULL); } else { ssh = rpmem_ssh_exec(info, "--remove", pool_set, NULL); } if (!ssh) goto err_ssh_exec; int ret = 0; if (rpmem_ssh_monitor(ssh, 0)) ret = 1; if (rpmem_ssh_close(ssh)) ret = 1; if (ret) goto err_ssh_exec; rpmem_target_free(info); outv(1, "removed '%s' on '%s'\n", pool_set, target); return ret; err_ssh_exec: rpmem_target_free(info); err_parse: if (!force) outv_err("cannot remove '%s' on '%s'", pool_set, target); return 1; #else outv_err("remote replication not supported"); return 1; #endif }
/* * pmempool_info_file -- print info about single file */ static int pmempool_info_file(struct pmem_info *pip, const char *file_name) { int ret = 0; pip->file_name = file_name; /* * Get pool type to parse based on headers * and command line flags. */ pip->type = pmempool_info_get_pool_type(pip); if (PMEM_POOL_TYPE_UNKNOWN == pip->type) { /* * This means don't know what pool type should be parsed * this happens when can't determine pool type of file * by parsing signature and force flag is not set. */ ret = -1; outv_err("%s: cannot determine type of pool\n", file_name); } else { if (util_options_verify(pip->opts, pip->type)) { ret = -1; goto err; } if (pip->poolset) { if (pip->args.obj.replica >= pip->poolset->nreplicas) { outv_err("invalid replica -- maximum is %lu\n", pip->poolset->nreplicas); ret = -1; goto err; } } if (pmempool_info_pool_hdr(pip, VERBOSE_DEFAULT)) { ret = -1; goto err; } switch (pip->type) { case PMEM_POOL_TYPE_LOG: ret = pmempool_info_log(pip); break; case PMEM_POOL_TYPE_BLK: ret = pmempool_info_blk(pip); break; case PMEM_POOL_TYPE_OBJ: ret = pmempool_info_obj(pip); break; case PMEM_POOL_TYPE_UNKNOWN: default: ret = -1; break; } } err: close(pip->fd); pip->fd = -1; return ret; }
/* * pmempool_setup_poolset -- parse poolset file and setup reading from it */ static int pmempool_setup_poolset(struct pmem_info *pip) { struct pool_set *set = NULL; int fd = -1; struct pool_hdr hdr; /* parse poolset file */ if (util_poolset_parse(pip->file_name, pip->fd, &set)) { outv_err("parsing poolset file failed\n"); return -1; } close(pip->fd); pip->fd = -1; /* open the first part set file to read the pool header values */ int ret = 0; fd = util_file_open(set->replica[0]->part[0].path, NULL, 0, O_RDONLY); if (fd < 0) { outv_err("cannot open poolset part file\n"); ret = -1; goto err_pool_set; } /* read the pool header from first pool set file */ if (pread(fd, &hdr, sizeof (hdr), 0) != sizeof (hdr)) { outv_err("cannot read pool header from poolset\n"); ret = -1; goto err_close; } close(fd); fd = -1; util_convert2h_pool_hdr(&hdr); /* parse pool type from first pool set file */ pmem_pool_type_t type = pmem_pool_type_parse_hdr(&hdr); if (type == PMEM_POOL_TYPE_UNKNOWN) { outv_err("cannot determine pool type from poolset\n"); ret = -1; goto err_close; } /* get minimum size based on pool type for util_pool_open */ size_t minsize = pmem_pool_get_min_size(type); /* * Open the poolset, the values passed to util_pool_open are read * from the first poolset file, these values are then compared with * the values from all headers of poolset files. */ if (util_pool_open(&pip->poolset, pip->file_name, 1, minsize, sizeof (struct pool_hdr), hdr.signature, hdr.major, hdr.compat_features, hdr.incompat_features, hdr.ro_compat_features)) { outv_err("openning poolset failed\n"); ret = -1; } err_close: if (fd != -1) close(fd); err_pool_set: util_poolset_free(set); return ret; }