#include "lib/mm/xlate.h"
#include "lib/misc/crc.h"
+#define PRINT_CURRENT 1
+#define PRINT_ALL 2
+
static char *_chars_to_str(void *in, void *out, int num, int max, const char *field)
{
char *i = in;
return out;
}
+static int _check_vgname_start(char *buf, int *len)
+{
+ int chars = 0;
+ int space = 0;
+ int i;
+ char c;
+
+ /*
+ * Valid metadata begins: 'vgname {'
+ */
+ for (i = 0; i <= NAME_LEN + 2; i++) {
+ c = buf[i];
+
+ if (isalnum(c) || c == '.' || c == '_' || c == '-' || c == '+') {
+ if (space)
+ return 0;
+ chars++;
+ continue;
+ }
+
+ if (c == ' ') {
+ if (!chars || space)
+ return 0;
+ space++;
+ continue;
+ }
+
+ if (c == '{') {
+ if (chars && space) {
+ *len = chars;
+ return 1;
+ }
+ return 0;
+ }
+
+ return 0;
+ }
+ return 0;
+}
+
+static void _copy_out_metadata(char *buf, uint32_t start, uint32_t first_start, uint64_t mda_size, char **meta_buf, uint64_t *meta_size, int *bad_end)
+{
+ char *new_buf;
+ uint64_t i;
+ uint64_t new_len;
+ uint64_t len_a = 0, len_b = 0;
+ uint32_t stop;
+ int found_end;
+
+ /*
+ * If we wrap around the buffer searching for the
+ * end of some metadata, either stop when we reach
+ * where we began (start), or stop where we found
+ * the first copy of metadata (first_start).
+ */
+ if (!first_start)
+ stop = start;
+ else
+ stop = first_start;
+
+ found_end = 0;
+ for (i = start; i < mda_size; i++) {
+ if (buf[i] == '\0') {
+ found_end = 1;
+ break;
+ }
+ }
+
+ if (found_end) {
+ new_len = i - start;
+ } else {
+ len_a = i - start;
+
+ found_end = 0;
+ for (i = 512; i < stop; i++) {
+ if (buf[i] == '\0') {
+ found_end = 1;
+ break;
+ }
+ }
+
+ if (!found_end)
+ return;
+
+ len_b = i - 512;
+ new_len = len_a + len_b;
+ }
+
+ if (new_len < 256) {
+ log_print("skip invalid metadata with len %llu at %llu",
+ (unsigned long long)new_len, (unsigned long long)start);
+ return;
+ }
+
+ /* terminating 0 byte */
+ new_len++;
+
+ if (!(new_buf = malloc(new_len)))
+ return;
+
+ memset(new_buf, 0, new_len);
+
+ if (len_a) {
+ memcpy(new_buf, buf+start, len_a);
+ memcpy(new_buf+len_a, buf+512, len_b);
+ } else {
+ memcpy(new_buf, buf+start, new_len);
+ }
+
+ /* \0 should be preceded by \n\n (0x0a0a) */
+ if (new_buf[new_len-1] != 0 || new_buf[new_len-2] != 0x0a || new_buf[new_len-3] != 0x0a)
+ *bad_end = 1;
+
+ *meta_buf = new_buf;
+ *meta_size = new_len;
+}
+
+static int _text_buf_parsable(char *text_buf, uint64_t text_size)
+{
+ struct dm_config_tree *cft;
+
+ if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0))) {
+ return 0;
+ }
+
+ if (!dm_config_parse(cft, text_buf, text_buf + text_size)) {
+ config_destroy(cft);
+ return 0;
+ }
+
+ config_destroy(cft);
+ return 1;
+}
+
+#define MAX_LINE_CHECK 128
+#define ID_STR_SIZE 48
+
+static void _copy_line(char *in, char *out, int *len)
+{
+ int i;
+
+ *len = 0;
+
+ for (i = 0; i < MAX_LINE_CHECK; i++) {
+ if ((in[i] == '\n') || (in[i] == '\0'))
+ break;
+ out[i] = in[i];
+ }
+ *len = i+1;
+}
+
+static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct device *dev,
+ int mda_num, uint64_t mda_offset, uint64_t mda_size, char *buf)
+{
+ FILE *fp = NULL;
+ char line[MAX_LINE_CHECK];
+ char vgname[NAME_LEN+1];
+ char id_str[ID_STR_SIZE];
+ char id_first[ID_STR_SIZE];
+ char *text_buf;
+ char *p;
+ uint32_t buf_off; /* offset with buf which begins with mda_header */
+ uint32_t buf_off_first = 0;
+ uint32_t seqno;
+ uint32_t crc;
+ uint64_t text_size;
+ uint64_t meta_size;
+ int multiple_vgs = 0;
+ int bad_end;
+ int vgnamelen;
+ int count;
+ int len;
+
+ if (tofile) {
+ if (!(fp = fopen(tofile, "wx"))) {
+ log_error("Failed to create file %s", tofile);
+ return 0;
+ }
+ }
+
+ /*
+ * If metadata has not wrapped, and the metadata area beginning
+ * has not been damaged, the text area will begin with vgname {.
+ * Wrapping or damage would mean we find no metadata starting at
+ * the start of the area.
+ *
+ * Try looking at each 512 byte offset within the area for the start
+ * of another copy of metadata. Metadata copies have begun at 512
+ * aligned offsets since very early lvm2 code in 2002.
+ *
+ * (We could also search for something definitive like
+ * "# Generated by LVM2" in the area, and then work backward to find
+ * a likely beginning.)
+ *
+ * N.B. This relies on VG metadata first having the id = "..." field
+ * followed by the "seqno = N" field.
+ */
+
+ memset(id_first, 0, sizeof(id_str));
+
+ /*
+ * A count of 512 byte chunks within the metadata area.
+ */
+ count = 0;
+
+ meta_size = mda_size - 512;
+
+ /*
+ * Search 512 byte boundaries for the start of new metadata copies.
+ */
+ while (count < (meta_size / 512)) {
+ memset(vgname, 0, sizeof(vgname));
+ memset(id_str, 0, sizeof(id_str));
+ seqno = 0;
+ vgnamelen = 0;
+ text_size = 0;
+ bad_end = 0;
+
+ /*
+ * Check for a new metadata copy at each 512 offset
+ * (after skipping 512 bytes for mda_header at the
+ * start of the buf).
+ *
+ * If a line looks like it begins with a vgname
+ * it could be a new copy of metadata, but it could
+ * also be a random bit of metadata that looks like
+ * a vgname, so confirm it's the start of metadata
+ * by looking for id and seqno lines following the
+ * possible vgname.
+ */
+ buf_off = 512 + (count * 512);
+ p = buf + buf_off;
+
+ /*
+ * copy line of possible metadata to check for vgname
+ */
+ memset(line, 0, sizeof(line));
+ _copy_line(p, line, &len);
+ p += len;
+
+ if (!_check_vgname_start(line, &vgnamelen)) {
+ count++;
+ continue;
+ }
+
+ memcpy(vgname, line, vgnamelen);
+
+ /*
+ * copy next line of metadata, which should contain id
+ */
+ memset(line, 0, sizeof(line));
+ _copy_line(p, line, &len);
+ p += len;
+
+ if (strncmp(line, "id = ", 5)) {
+ count++;
+ continue;
+ }
+
+ memcpy(id_str, line + 6, 38);
+
+ /*
+ * copy next line of metadata, which should contain seqno
+ */
+ memset(line, 0, sizeof(line));
+ _copy_line(p, line, &len);
+ p += len;
+
+ if (strncmp(line, "seqno = ", 8)) {
+ count++;
+ continue;
+ }
+
+ sscanf(line, "seqno = %u", &seqno);
+
+ /*
+ * The first three lines look like metadata with
+ * vgname/id/seqno, so copy out the full metadata.
+ *
+ * If this reaches the end of buf without reaching the
+ * end marker of metadata, it will wrap around to the
+ * start of buf and continue copying until it reaches
+ * a NL or until it reaches buf_off_first (which is
+ * where we've already taken text from.)
+ */
+ _copy_out_metadata(buf, buf_off, buf_off_first, mda_size, &text_buf, &text_size, &bad_end);
+
+ if (!text_buf) {
+ log_warn("Failed to extract full metadata text at %llu, skipping.",
+ (unsigned long long)(mda_offset + buf_off));
+ count++;
+ continue;
+ }
+
+ /*
+ * check if it's finding metadata from different vgs
+ */
+ if (!id_first[0])
+ memcpy(id_first, id_str, sizeof(id_first));
+ else if (memcmp(id_first, id_str, sizeof(id_first)))
+ multiple_vgs = 1;
+
+ crc = calc_crc(INITIAL_CRC, (uint8_t *)text_buf, text_size);
+
+ log_print("metadata at %llu length %llu crc %08x vg %s seqno %u id %s",
+ (unsigned long long)(mda_offset + buf_off),
+ (unsigned long long)text_size,
+ crc, vgname, seqno, id_str);
+
+ /*
+ * save the location of the first metadata we've found so
+ * we know where to stop after wrapping buf.
+ */
+ if (!buf_off_first)
+ buf_off_first = buf_off;
+
+ /*
+ * check if the full metadata is parsable
+ */
+
+ if (!_text_buf_parsable(text_buf, text_size))
+ log_warn("WARNING: parse error for metadata at %llu", (unsigned long long)(mda_offset + buf_off));
+ if (bad_end)
+ log_warn("WARNING: bad terminating bytes for metadata at %llu", (unsigned long long)(mda_offset + buf_off));
+
+ if (arg_is_set(cmd, verbose_ARG)) {
+ char *str1, *str2;
+ if ((str1 = strstr(text_buf, "description = "))) {
+ memset(line, 0, sizeof(line));
+ _copy_line(str1, line, &len);
+ log_print("%s", line);
+ }
+ if ((str2 = strstr(str1, "creation_time = "))) {
+ memset(line, 0, sizeof(line));
+ _copy_line(str2, line, &len);
+ log_print("%s\n", line);
+ }
+ }
+
+ if (fp) {
+ fprintf(fp, "%s", text_buf);
+ fprintf(fp, "\n--\n");
+ }
+
+ free(text_buf);
+ text_buf = NULL;
+
+ if (text_size < 512)
+ count++;
+ else if (!(text_size % 512))
+ count += (text_size / 512);
+ else
+ count += ((text_size / 512) + 1);
+ }
+
+ if (multiple_vgs)
+ log_warn("WARNING: metadata from multiple VGs was found.");
+
+ if (fp) {
+ if (fflush(fp))
+ stack;
+ if (fclose(fp))
+ stack;
+ }
+
+ return 1;
+}
+
static int _check_label_header(struct label_header *lh, uint64_t labelsector,
int *found_label)
{
* 1\23456789012345678901234567890123456789012345678
* 10 20 30 40
*/
-#define ID_STR_SIZE 48
-
-#define SEARCH_VGNAME_LEN 512
-
-static int _dump_meta_all(struct device *dev, const char *tofile,
- uint64_t mda_offset, uint64_t mda_size,
- uint64_t meta_offset, uint64_t meta_size,
- char *meta_buf)
-{
- FILE *fp = NULL;
- struct dm_config_tree *cft;
- char vgname[SEARCH_VGNAME_LEN];
- char id_str[ID_STR_SIZE];
- char *text_buf, *new_buf;
- char *p, *brace, *start, *buf_begin, *buf_end;
- uint64_t search_offset, start_offset;
- uint32_t brace_dist, new_len, len_a, len_b;
- uint32_t left_count, right_count;
- uint32_t seqno;
- int search_wrapped = 0;
- int p_wrapped;
- int save_bad;
- int i;
-
- /*
- * metadata begins:
- *
- * <vgname> {
- * id = "<uuid>"
- *
- * Search the metadata buffer for each instance
- * of the string:
- *
- * {
- * id = "<uuid>"
- *
- * Then reverse by the length of the <vgname> +1
- * to get to the start of the metadata. The
- * vgname must come from the original/current copy
- * of metadata found through the mda_header pointer.
- *
- * From the start of the metadata, find the end of
- * the metadata by searching foward until \0 is found.
- * Metadata ends with the three bytes:
- * \n\n\0 (0x0a0a00)
- */
-
- memset(vgname, 0, sizeof(vgname));
- memset(id_str, 0, sizeof(id_str));
- for (i = 0; i < SEARCH_VGNAME_LEN; i++) {
- if (meta_buf[i] == ' ')
- break;
- vgname[i] = meta_buf[i];
- }
-
- if (!(p = strchr(meta_buf, '{')))
- return_0;
-
- for (i = 0; i < ID_STR_SIZE; i++) {
- id_str[i] = *p;
- p++;
- }
-
- if (!(text_buf = malloc(mda_size)))
- return_0;
- memset(text_buf, 0, mda_size);
-
- if (!dev_read_bytes(dev, mda_offset, mda_size, text_buf)) {
- log_print("CHECK: failed to read metadata area at offset %llu size %llu",
- (unsigned long long)mda_offset, (unsigned long long)mda_size);
- free(text_buf);
- return 0;
- }
-
- search_offset = meta_offset + meta_size;
-
- search_next:
- if (search_wrapped && (search_offset >= meta_offset + meta_size))
- goto done;
-
- if (search_offset > mda_size) {
- if (search_wrapped)
- goto done;
- search_offset = 512;
- search_wrapped = 1;
- }
-
- /*
- * Search between buf_begin and buf_end for next open brace.
- */
- buf_begin = text_buf + search_offset;
- buf_end = text_buf + mda_size;
- brace = NULL;
-
- for (p = buf_begin; p < buf_end; p++) {
- if (*p != '{')
- continue;
- brace = p;
- break;
- }
-
- if (!brace && search_wrapped)
- goto done;
- if (!brace) {
- search_offset = 512;
- search_wrapped = 1;
- goto search_next;
- }
-
- /*
- * brace_dist is the distance from the last place we
- * began searching to the brace we are testing for
- * metadata. If this brace is not the start of valid
- * metadata, then advance brace_dist and search for
- * the next brace to check.
- */
- brace_dist = (uint32_t)(brace - buf_begin);
-
- /*
- * Found an open brace, check if it's the start of new metadata
- * by checking if brace is followed by id = "<uuid>".
- */
-
- if (memcmp(brace, id_str, ID_STR_SIZE)) {
- /* It's not, look for next open brace. */
- search_offset += (brace_dist + 1);
- goto search_next;
- }
-
- /*
- * This looks like a new instance of metadata, check if it's complete.
- * The start of the metadata is the vgname preceding the open brace,
- * so step backward through the text_buf to find the start of vgname.
- * There is no delimiter preceding the vgname, there can be any
- * text or data in the byte immediately before vgname (this means
- * we cannot handle extracting metadata prior to a vgrename.)
- *
- * <vgname> {
- * id = "..."
- */
- start = brace - (strlen(vgname) + 1);
-
- /* Offset from the begininng of device to the start of this metadata. */
- start_offset = (uint64_t)(start - text_buf) + mda_offset;
-
- /*
- * The end of the metadata is found by searching forward in text_buf
- * until \0, at which point open and close braces should match.
- * This forward search may wrap around to the start of text_buf.
- *
- * Metadata ends with the three bytes \n\n\0: 0a 0a 00
- */
- p = start;
- p_wrapped = 0;
- len_a = 0;
- len_b = 0;
- new_len = 0;
- new_buf = NULL;
- left_count = 0;
- right_count = 0;
- save_bad = 0;
- seqno = 0;
-
- while (1) {
- p++;
-
- if (p == (buf_end)) {
- p = text_buf + 512;
- p_wrapped = 1;
- }
-
- if (*p == '{')
- left_count++;
- else if (*p == '}')
- right_count++;
- else if (*p == '\0')
- break;
- }
-
- /* \0 should be preceded by \n\n (0x0a0a) */
- if ((*(p - 2) != 0x0a) || (*(p - 1) != 0x0a))
- log_print("Unexpected metadata end bytes.");
-
- if (p_wrapped) {
- len_a = (uint32_t)(buf_end - start);
- len_b = (uint32_t)(p - (text_buf + 512));
- new_len = len_a + len_b;
- search_wrapped = 1;
- } else {
- new_len = (uint32_t)(p - start);
- }
-
- /*
- * A couple simple tests indicate if this could be valid metadata
- * before attempting to parse it. (min length is probably greater
- * than 256, so this could be increased.)
- *
- * If this is complete but corrupt, we should save it.
- * TODO: If this is a fragment we should skip it.
- */
- if ((left_count != right_count) || (new_len < 256)) {
- /*
- * To skip this:
- * search_offset += (brace_dist + 1);
- * goto search_next;
- */
- log_print("Found incorrect metadata at %llu length %u with braces %u %u",
- (unsigned long long)start_offset, new_len, left_count, right_count);
- save_bad = 1;
- }
-
- /*
- * Copy the potential metadata into a new buffer to parse.
- */
- if (!(new_buf = malloc(new_len + 1))) {
- search_offset += (brace_dist + 1);
- log_print("No memory for metadata at %llu length %u with %u sections",
- (unsigned long long)start_offset, new_len, right_count);
- goto search_next;
- }
- memset(new_buf, 0, new_len + 1);
-
- if (p_wrapped) {
- memcpy(new_buf, start, len_a);
- memcpy(new_buf + len_a, text_buf + 512, len_b);
- } else {
- memcpy(new_buf, start, new_len);
- }
-
- if (save_bad)
- goto save;
-
- /*
- * Check the metadata is parsable.
- * If this is complete but corrupt, we should save it.
- * TODO: If this is a fragment we should skip it.
- */
- if ((cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0))) {
- if (!dm_config_parse(cft, new_buf, new_buf + new_len)) {
- /*
- * To skip this:
- * search_offset += (brace_dist + 1);
- * goto search_next;
- */
- log_print("Found unparsable metadata at %llu length %u with %u sections",
- (unsigned long long)start_offset, new_len, right_count);
- config_destroy(cft);
- goto save;
- }
-
- if (cft->root && cft->root->child)
- dm_config_get_uint32(cft->root->child, "seqno", &seqno);
- config_destroy(cft);
- }
-
- log_print("Found metadata at %llu length %u seqno %u with %u sections",
- (unsigned long long)start_offset, new_len, seqno, right_count);
-
- save:
- if (!fp && tofile) {
- if (!(fp = fopen(tofile, "a"))) {
- log_error("Failed to open file %s", tofile);
- goto out;
- }
- }
-
- if (fp) {
- fprintf(fp, "%s", new_buf);
- fprintf(fp, "\n--\n");
- }
-
- out:
- free(new_buf);
-
- /*
- * Look for another id_str instance after the metadata
- * that was just finished.
- */
-
- if (p_wrapped)
- search_offset = len_b;
- else
- search_offset += new_len;
- goto search_next;
-
- done:
- if (fp) {
- if (fflush(fp))
- stack;
- if (fclose(fp))
- stack;
- }
-
- free(text_buf);
- return 1;
-}
-
-static int _dump_meta_text(struct device *dev,
- int print_fields, int print_metadata, const char *tofile,
- int mda_num, int rlocn_index,
- uint64_t mda_offset, uint64_t mda_size,
- uint64_t meta_offset, uint64_t meta_size,
- uint32_t meta_checksum,
- char **meta_buf_out)
+static int _dump_current_text(struct device *dev,
+ int print_fields, int print_metadata, const char *tofile,
+ int mda_num, int rlocn_index,
+ uint64_t mda_offset, uint64_t mda_size,
+ uint64_t meta_offset, uint64_t meta_size,
+ uint32_t meta_checksum)
{
char *meta_buf;
struct dm_config_tree *cft;
}
out:
- *meta_buf_out = meta_buf;
-
if (bad)
return 0;
return 1;
{
char str[256];
char *buf;
- char *meta_buf = NULL;
struct mda_header *mh;
struct raw_locn *rlocn0, *rlocn1;
uint64_t rlocn0_offset, rlocn1_offset;
/*
* looking at the current copy of metadata referenced by raw_locn
*/
- if (print_metadata < 2) {
- if (!_dump_meta_text(dev, print_fields, print_metadata, tofile, mda_num, 0, mda_offset, mda_size, meta_offset, meta_size, meta_checksum, &meta_buf))
+ if (print_metadata <= PRINT_CURRENT) {
+ if (!_dump_current_text(dev, print_fields, print_metadata, tofile, mda_num, 0, mda_offset, mda_size, meta_offset, meta_size, meta_checksum))
bad++;
}
/*
* looking at all copies of the metadata in the area
*/
- if (print_metadata == 2) {
- if (!_dump_meta_text(dev, 0, 0, NULL, mda_num, 0, mda_offset, mda_size, meta_offset, meta_size, meta_checksum, &meta_buf))
- bad++;
+ if (print_metadata == PRINT_ALL) {
+ free(buf);
+
+ if (!(buf = malloc(mda_size)))
+ goto_out;
+ memset(buf, 0, mda_size);
- if (!_dump_meta_all(dev, tofile, mda_offset, mda_size, meta_offset, meta_size, meta_buf))
+ if (!dev_read_bytes(dev, mda_offset, mda_size, buf)) {
+ log_print("CHECK: failed to read metadata area at offset %llu size %llu",
+ (unsigned long long)mda_offset, (unsigned long long)mda_size);
bad++;
+ goto out;
+ }
+
+ _dump_all_text(cmd, tofile, dev, mda_num, mda_offset, mda_size, buf);
}
/* Should we also check text metadata if it exists in rlocn1? */
out:
+ if (buf)
+ free(buf);
if (bad)
return 0;
return 1;
return 1;
}
+#define ONE_MB_IN_BYTES 1048576
+
+/*
+ * Look for metadata text in common locations, without using any headers
+ * (pv_header/mda_header) to find the location, since the headers may be
+ * zeroed/damaged.
+ */
+
+static int _dump_search(struct cmd_context *cmd,
+ int argc, char **argv)
+{
+ char str[256];
+ struct device *dev;
+ const char *pv_name;
+ const char *tofile = NULL;
+ char *buf;
+ struct mda_header *mh;
+ uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0;
+ uint64_t mda_offset, mda_size;
+ int found_header = 0;
+ int mda_count = 0;
+ int mda_num = 1;
+
+ if (arg_is_set(cmd, file_ARG)) {
+ if (!(tofile = arg_str_value(cmd, file_ARG, NULL)))
+ return ECMD_FAILED;
+ }
+
+ /* 1: dump metadata from first mda, 2: dump metadata from second mda */
+ if (arg_is_set(cmd, pvmetadatacopies_ARG))
+ mda_num = arg_int_value(cmd, pvmetadatacopies_ARG, 1);
+
+ pv_name = argv[0];
+
+ if (!(dev = dev_cache_get(cmd, pv_name, cmd->filter))) {
+ log_error("No device found for %s %s.", pv_name, dev_cache_filtered_reason(pv_name));
+ return ECMD_FAILED;
+ }
+
+ label_scan_setup_bcache();
+
+ _dump_label_and_pv_header(cmd, 0, dev, NULL,
+ &mda1_offset, &mda1_size, &mda2_offset, &mda2_size, &mda_count);
+
+ /*
+ * TODO: allow mda_offset and mda_size to be specified on the
+ * command line.
+ *
+ * For mda1, mda_offset is always 4096 bytes from the start of
+ * device, and mda_size is the space between mda_offset and
+ * the first PE which is usually at 1MB.
+ *
+ * For mda2, take the dev_size, reduce that to be a 1MB
+ * multiple. The mda_offset is then 1MB prior to that,
+ * and mda_size is the amount of space between that offset
+ * and the end of the device.
+ *
+ * The second mda is generally 4K larger (at least) than the
+ * first mda because the first mda begins at a 4K offset from
+ * the start of the device and ends on a 1MB boundary.
+ * The second mda begins on a 1MB boundary (no 4K offset like
+ * mda1), then goes to the end of the device. Extra space
+ * at the end of device (mod 1MB extra) can make mda2 even
+ * larger.
+ */
+ if (mda_num == 1) {
+ mda_offset = 4096;
+ mda_size = ONE_MB_IN_BYTES - 4096;
+ } else if (mda_num == 2) {
+ uint64_t dev_sectors = 0;
+ uint64_t dev_bytes;
+ uint64_t extra_bytes;
+
+ dev_get_size(dev, &dev_sectors);
+
+ dev_bytes = dev_sectors * 512;
+ extra_bytes = dev_bytes % ONE_MB_IN_BYTES;
+
+ if (dev_bytes < (2 * ONE_MB_IN_BYTES))
+ return ECMD_FAILED;
+
+ mda_offset = dev_bytes - extra_bytes - ONE_MB_IN_BYTES;
+ mda_size = dev_bytes - mda_offset;
+ }
+
+ if ((mda_num == 1) && (mda1_offset != mda_offset)) {
+ log_print("Ignoring mda1_offset %llu mda1_size %llu from pv_header.",
+ (unsigned long long)mda1_offset,
+ (unsigned long long)mda1_size);
+ }
+
+ if ((mda_num == 2) && (mda2_offset != mda_offset)) {
+ log_print("Ignoring mda2_size %llu mda2_offset %llu from pv_header.",
+ (unsigned long long)mda2_offset,
+ (unsigned long long)mda2_size);
+ }
+
+ log_print("Searching for metadata in mda%d at offset %llu size %llu", mda_num,
+ (unsigned long long)mda_offset, (unsigned long long)mda_size);
+
+ if (!(buf = malloc(mda_size)))
+ return ECMD_FAILED;
+ memset(buf, 0, mda_size);
+
+ if (!dev_read_bytes(dev, mda_offset, mda_size, buf)) {
+ log_print("CHECK: failed to read metadata area at offset %llu size %llu",
+ (unsigned long long)mda_offset, (unsigned long long)mda_size);
+ free(buf);
+ return ECMD_FAILED;
+ }
+
+ mh = (struct mda_header *)buf;
+
+ /* Can be useful to know if there's a valid mda_header at this location. */
+ log_print("mda_header_%d at %llu # metadata area", mda_num, (unsigned long long)mda_offset);
+ log_print("mda_header_%d.checksum 0x%x", mda_num, xlate32(mh->checksum_xl));
+ log_print("mda_header_%d.magic 0x%s", mda_num, _chars_to_hexstr(mh->magic, str, 16, 256, "mda_header.magic"));
+ log_print("mda_header_%d.version %u", mda_num, xlate32(mh->version));
+ log_print("mda_header_%d.start %llu", mda_num, (unsigned long long)xlate64(mh->start));
+ log_print("mda_header_%d.size %llu", mda_num, (unsigned long long)xlate64(mh->size));
+
+ _check_mda_header(mh, mda_num, mda_offset, mda_size, &found_header);
+
+ log_print("searching for metadata text");
+
+ _dump_all_text(cmd, tofile, dev, mda_num, mda_offset, mda_size, buf);
+
+ free(buf);
+ return ECMD_PROCESSED;
+}
+
int pvck(struct cmd_context *cmd, int argc, char **argv)
{
struct device *dev;
dump = arg_str_value(cmd, dump_ARG, NULL);
if (!strcmp(dump, "metadata"))
- return _dump_metadata(cmd, argc, argv, 1, 0);
+ return _dump_metadata(cmd, argc, argv, PRINT_CURRENT, 0);
if (!strcmp(dump, "metadata_all"))
- return _dump_metadata(cmd, argc, argv, 2, 0);
+ return _dump_metadata(cmd, argc, argv, PRINT_ALL, 0);
if (!strcmp(dump, "metadata_area"))
return _dump_metadata(cmd, argc, argv, 0, 1);
+ if (!strcmp(dump, "metadata_search"))
+ return _dump_search(cmd, argc, argv);
+
if (!strcmp(dump, "headers"))
return _dump_headers(cmd, argc, argv);