/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tools.h" /* * Intial sanity checking of recovery-related command-line arguments. * These args are: --restorefile, --uuid, and --physicalvolumesize * * Output arguments: * pp: structure allocated by caller, fields written / validated here */ static int _pvcreate_restore_params_from_args(struct cmd_context *cmd, int argc, struct pvcreate_params *pp) { pp->restorefile = arg_str_value(cmd, restorefile_ARG, NULL); if (arg_is_set(cmd, restorefile_ARG) && !arg_is_set(cmd, uuidstr_ARG)) { log_error("--uuid is required with --restorefile"); return 0; } if (!arg_is_set(cmd, restorefile_ARG) && arg_is_set(cmd, uuidstr_ARG)) { if (!arg_is_set(cmd, norestorefile_ARG) && find_config_tree_bool(cmd, devices_require_restorefile_with_uuid_CFG, NULL)) { log_error("--restorefile is required with --uuid"); return 0; } } if (arg_is_set(cmd, uuidstr_ARG) && argc != 1) { log_error("Can only set uuid on one volume at once"); return 0; } if (arg_is_set(cmd, uuidstr_ARG)) { pp->uuid_str = arg_str_value(cmd, uuidstr_ARG, ""); if (!id_read_format(&pp->pva.id, pp->uuid_str)) return 0; pp->pva.idp = &pp->pva.id; } if (arg_sign_value(cmd, setphysicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical volume size may not be negative"); return 0; } pp->pva.size = arg_uint64_value(cmd, setphysicalvolumesize_ARG, UINT64_C(0)); if (arg_is_set(cmd, restorefile_ARG) || arg_is_set(cmd, uuidstr_ARG)) pp->zero = 0; return 1; } static int _pvcreate_restore_params_from_backup(struct cmd_context *cmd, struct pvcreate_params *pp) { struct volume_group *vg; struct pv_list *existing_pvl; /* * When restoring a PV, params need to be read from a backup file. */ if (!pp->restorefile) return 1; if (!(vg = backup_read_vg(cmd, NULL, pp->restorefile))) { log_error("Unable to read volume group from %s", pp->restorefile); return 0; } if (!(existing_pvl = find_pv_in_vg_by_uuid(vg, &pp->pva.id))) { release_vg(vg); log_error("Can't find uuid %s in backup file %s", pp->uuid_str, pp->restorefile); return 0; } pp->pva.ba_start = pv_ba_start(existing_pvl->pv); pp->pva.ba_size = pv_ba_size(existing_pvl->pv); pp->pva.pe_start = pv_pe_start(existing_pvl->pv); pp->pva.extent_size = pv_pe_size(existing_pvl->pv); pp->pva.extent_count = pv_pe_count(existing_pvl->pv); release_vg(vg); return 1; } int pvcreate(struct cmd_context *cmd, int argc, char **argv) { struct processing_handle *handle; struct pvcreate_params pp; int ret; /* * Five kinds of pvcreate param values: * 1. defaults * 2. recovery-related command line args * 3. recovery-related args from backup file * 4. normal command line args * (this also checks some settings from 2 & 3) * 5. argc/argv free args specifying devices */ pvcreate_params_set_defaults(&pp); if (!_pvcreate_restore_params_from_args(cmd, argc, &pp)) return EINVALID_CMD_LINE; if (!_pvcreate_restore_params_from_backup(cmd, &pp)) return EINVALID_CMD_LINE; if (!pvcreate_params_from_args(cmd, &pp)) return EINVALID_CMD_LINE; /* * If --metadatasize was not given with --restorefile, set it to pe_start. * Later code treats this as a maximum size and reduces it to fit. */ if (!arg_is_set(cmd, metadatasize_ARG) && arg_is_set(cmd, restorefile_ARG)) pp.pva.pvmetadatasize = pp.pva.pe_start; /* FIXME Also needs to check any 2nd metadata area isn't inside the data area! */ pp.pv_count = argc; pp.pv_names = argv; /* Needed to change the set of orphan PVs. */ if (!lock_global(cmd, "ex")) return_ECMD_FAILED; clear_hint_file(cmd); lvmcache_label_scan(cmd); if (!(handle = init_processing_handle(cmd, NULL))) { log_error("Failed to initialize processing handle."); return ECMD_FAILED; } if (!pvcreate_each_device(cmd, handle, &pp)) ret = ECMD_FAILED; else ret = ECMD_PROCESSED; destroy_processing_handle(cmd, handle); return ret; }