1/*	$NetBSD: import_vsn1.c,v 1.1.1.2 2009/12/02 00:26:30 haad Exp $	*/
2
3/*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6 *
7 * This file is part of LVM2.
8 *
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17
18#include "lib.h"
19#include "metadata.h"
20#include "import-export.h"
21#include "display.h"
22#include "toolcontext.h"
23#include "lvmcache.h"
24#include "lv_alloc.h"
25#include "pv_alloc.h"
26#include "segtype.h"
27#include "text_import.h"
28
29typedef int (*section_fn) (struct format_instance * fid, struct dm_pool * mem,
30			   struct volume_group * vg, struct config_node * pvn,
31			   struct config_node * vgn,
32			   struct dm_hash_table * pv_hash);
33
34#define _read_int32(root, path, result) \
35	get_config_uint32(root, path, (uint32_t *) result)
36
37#define _read_uint32(root, path, result) \
38	get_config_uint32(root, path, result)
39
40#define _read_int64(root, path, result) \
41	get_config_uint64(root, path, result)
42
43/*
44 * Logs an attempt to read an invalid format file.
45 */
46static void _invalid_format(const char *str)
47{
48	log_error("Can't process text format file - %s.", str);
49}
50
51/*
52 * Checks that the config file contains vg metadata, and that it
53 * we recognise the version number,
54 */
55static int _check_version(struct config_tree *cft)
56{
57	struct config_node *cn;
58	struct config_value *cv;
59
60	/*
61	 * Check the contents field.
62	 */
63	if (!(cn = find_config_node(cft->root, CONTENTS_FIELD))) {
64		_invalid_format("missing contents field");
65		return 0;
66	}
67
68	cv = cn->v;
69	if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
70		_invalid_format("unrecognised contents field");
71		return 0;
72	}
73
74	/*
75	 * Check the version number.
76	 */
77	if (!(cn = find_config_node(cft->root, FORMAT_VERSION_FIELD))) {
78		_invalid_format("missing version number");
79		return 0;
80	}
81
82	cv = cn->v;
83	if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
84		_invalid_format("unrecognised version number");
85		return 0;
86	}
87
88	return 1;
89}
90
91static int _is_converting(struct logical_volume *lv)
92{
93	struct lv_segment *seg;
94
95	if (lv->status & MIRRORED) {
96		seg = first_seg(lv);
97		/* Can't use is_temporary_mirror() because the metadata for
98		 * seg_lv may not be read in and flags may not be set yet. */
99		if (seg_type(seg, 0) == AREA_LV &&
100		    strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER))
101			return 1;
102	}
103
104	return 0;
105}
106
107static int _read_id(struct id *id, struct config_node *cn, const char *path)
108{
109	struct config_value *cv;
110
111	if (!(cn = find_config_node(cn, path))) {
112		log_error("Couldn't find uuid.");
113		return 0;
114	}
115
116	cv = cn->v;
117	if (!cv || !cv->v.str) {
118		log_error("uuid must be a string.");
119		return 0;
120	}
121
122	if (!id_read_format(id, cv->v.str)) {
123		log_error("Invalid uuid.");
124		return 0;
125	}
126
127	return 1;
128}
129
130static int _read_flag_config(struct config_node *n, uint32_t *status, int type)
131{
132	struct config_node *cn;
133	*status = 0;
134
135	if (!(cn = find_config_node(n, "status"))) {
136		log_error("Could not find status flags.");
137		return 0;
138	}
139
140	if (!(read_flags(status, type | STATUS_FLAG, cn->v))) {
141		log_error("Could not read status flags.");
142		return 0;
143	}
144
145	if ((cn = find_config_node(n, "flags"))) {
146		if (!(read_flags(status, type, cn->v))) {
147			log_error("Could not read flags.");
148			return 0;
149		}
150	}
151
152	return 1;
153}
154
155static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
156		    struct volume_group *vg, struct config_node *pvn,
157		    struct config_node *vgn __attribute((unused)),
158		    struct dm_hash_table *pv_hash)
159{
160	struct physical_volume *pv;
161	struct pv_list *pvl;
162	struct config_node *cn;
163	uint64_t size;
164
165	if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
166	    !(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv))))
167		return_0;
168
169	pv = pvl->pv;
170
171	/*
172	 * Add the pv to the pv hash for quick lookup when we read
173	 * the lv segments.
174	 */
175	if (!dm_hash_insert(pv_hash, pvn->key, pv))
176		return_0;
177
178	if (!(pvn = pvn->child)) {
179		log_error("Empty pv section.");
180		return 0;
181	}
182
183	if (!_read_id(&pv->id, pvn, "id")) {
184		log_error("Couldn't read uuid for physical volume.");
185		return 0;
186	}
187
188	/*
189	 * Convert the uuid into a device.
190	 */
191	if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
192		char buffer[64] __attribute((aligned(8)));
193
194		if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
195			log_error("Couldn't find device.");
196		else
197			log_error("Couldn't find device with uuid '%s'.",
198				  buffer);
199	}
200
201	if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
202		return_0;
203
204	memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
205
206	if (!_read_flag_config(pvn, &pv->status, PV_FLAGS)) {
207		log_error("Couldn't read status flags for physical volume.");
208		return 0;
209	}
210
211	if (!pv->dev)
212		pv->status |= MISSING_PV;
213
214	/* Late addition */
215	_read_int64(pvn, "dev_size", &pv->size);
216
217	if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
218		log_error("Couldn't read extent size for physical volume.");
219		return 0;
220	}
221
222	if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
223		log_error("Couldn't find extent count (pe_count) for "
224			  "physical volume.");
225		return 0;
226	}
227
228	dm_list_init(&pv->tags);
229	dm_list_init(&pv->segments);
230
231	/* Optional tags */
232	if ((cn = find_config_node(pvn, "tags")) &&
233	    !(read_tags(mem, &pv->tags, cn->v))) {
234		log_error("Couldn't read tags for physical volume %s in %s.",
235			  pv_dev_name(pv), vg->name);
236		return 0;
237	}
238
239	/* adjust the volume group. */
240	vg->extent_count += pv->pe_count;
241	vg->free_count += pv->pe_count;
242
243	pv->pe_size = vg->extent_size;
244
245	pv->pe_alloc_count = 0;
246	pv->pe_align = 0;
247	pv->fmt = fid->fmt;
248
249	/* Fix up pv size if missing or impossibly large */
250	if ((!pv->size || pv->size > (1ULL << 62)) && pv->dev) {
251		if (!dev_get_size(pv->dev, &pv->size)) {
252			log_error("%s: Couldn't get size.", pv_dev_name(pv));
253			return 0;
254		}
255		log_verbose("Fixing up missing size (%s) "
256			    "for PV %s", display_size(fid->fmt->cmd, pv->size),
257			    pv_dev_name(pv));
258		if (vg) {
259			size = pv->pe_count * (uint64_t) vg->extent_size +
260			       pv->pe_start;
261			if (size > pv->size)
262				log_error("WARNING: Physical Volume %s is too "
263					  "large for underlying device",
264					  pv_dev_name(pv));
265		}
266	}
267
268	if (!alloc_pv_segment_whole_pv(mem, pv))
269		return_0;
270
271	vg->pv_count++;
272	dm_list_add(&vg->pvs, &pvl->list);
273
274	return 1;
275}
276
277static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
278{
279	struct lv_segment *comp;
280
281	dm_list_iterate_items(comp, &lv->segments) {
282		if (comp->le > seg->le) {
283			dm_list_add(&comp->list, &seg->list);
284			return;
285		}
286	}
287
288	lv->le_count += seg->len;
289	dm_list_add(&lv->segments, &seg->list);
290}
291
292static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
293			 struct logical_volume *lv, struct config_node *sn,
294			 struct dm_hash_table *pv_hash)
295{
296	uint32_t area_count = 0u;
297	struct lv_segment *seg;
298	struct config_node *cn, *sn_child = sn->child;
299	struct config_value *cv;
300	uint32_t start_extent, extent_count;
301	struct segment_type *segtype;
302	const char *segtype_str;
303
304	if (!sn_child) {
305		log_error("Empty segment section.");
306		return 0;
307	}
308
309	if (!_read_int32(sn_child, "start_extent", &start_extent)) {
310		log_error("Couldn't read 'start_extent' for segment '%s' "
311			  "of logical volume %s.", sn->key, lv->name);
312		return 0;
313	}
314
315	if (!_read_int32(sn_child, "extent_count", &extent_count)) {
316		log_error("Couldn't read 'extent_count' for segment '%s' "
317			  "of logical volume %s.", sn->key, lv->name);
318		return 0;
319	}
320
321	segtype_str = "striped";
322
323	if ((cn = find_config_node(sn_child, "type"))) {
324		cv = cn->v;
325		if (!cv || !cv->v.str) {
326			log_error("Segment type must be a string.");
327			return 0;
328		}
329		segtype_str = cv->v.str;
330	}
331
332	if (!(segtype = get_segtype_from_string(vg->cmd, segtype_str)))
333		return_0;
334
335	if (segtype->ops->text_import_area_count &&
336	    !segtype->ops->text_import_area_count(sn_child, &area_count))
337		return_0;
338
339	if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
340				     extent_count, 0, 0, NULL, area_count,
341				     extent_count, 0, 0, 0))) {
342		log_error("Segment allocation failed");
343		return 0;
344	}
345
346	if (seg->segtype->ops->text_import &&
347	    !seg->segtype->ops->text_import(seg, sn_child, pv_hash))
348		return_0;
349
350	/* Optional tags */
351	if ((cn = find_config_node(sn_child, "tags")) &&
352	    !(read_tags(mem, &seg->tags, cn->v))) {
353		log_error("Couldn't read tags for a segment of %s/%s.",
354			  vg->name, lv->name);
355		return 0;
356	}
357
358	/*
359	 * Insert into correct part of segment list.
360	 */
361	_insert_segment(lv, seg);
362
363	if (seg_is_mirrored(seg))
364		lv->status |= MIRRORED;
365
366	if (seg_is_virtual(seg))
367		lv->status |= VIRTUAL;
368
369	if (_is_converting(lv))
370		lv->status |= CONVERTING;
371
372	return 1;
373}
374
375int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
376		      const struct config_node *cn, struct dm_hash_table *pv_hash,
377		      uint32_t flags)
378{
379	unsigned int s;
380	struct config_value *cv;
381	struct logical_volume *lv1;
382	struct physical_volume *pv;
383	const char *seg_name = config_parent_name(sn);
384
385	if (!seg->area_count) {
386		log_error("Zero areas not allowed for segment %s", seg_name);
387		return 0;
388	}
389
390	for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
391
392		/* first we read the pv */
393		if (cv->type != CFG_STRING) {
394			log_error("Bad volume name in areas array for segment %s.", seg_name);
395			return 0;
396		}
397
398		if (!cv->next) {
399			log_error("Missing offset in areas array for segment %s.", seg_name);
400			return 0;
401		}
402
403		if (cv->next->type != CFG_INT) {
404			log_error("Bad offset in areas array for segment %s.", seg_name);
405			return 0;
406		}
407
408		/* FIXME Cope if LV not yet read in */
409		if ((pv = dm_hash_lookup(pv_hash, cv->v.str))) {
410			if (!set_lv_segment_area_pv(seg, s, pv, (uint32_t) cv->next->v.i))
411				return_0;
412		} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
413			if (!set_lv_segment_area_lv(seg, s, lv1,
414						    (uint32_t) cv->next->v.i,
415						    flags))
416				return_0;
417		} else {
418			log_error("Couldn't find volume '%s' "
419				  "for segment '%s'.",
420				  cv->v.str ? : "NULL", seg_name);
421			return 0;
422		}
423
424		cv = cv->next;
425	}
426
427	/*
428	 * Check we read the correct number of stripes.
429	 */
430	if (cv || (s < seg->area_count)) {
431		log_error("Incorrect number of areas in area array "
432			  "for segment '%s'.", seg_name);
433		return 0;
434	}
435
436	return 1;
437}
438
439static int _read_segments(struct dm_pool *mem, struct volume_group *vg,
440			  struct logical_volume *lv, struct config_node *lvn,
441			  struct dm_hash_table *pv_hash)
442{
443	struct config_node *sn;
444	int count = 0, seg_count;
445
446	for (sn = lvn; sn; sn = sn->sib) {
447
448		/*
449		 * All sub-sections are assumed to be segments.
450		 */
451		if (!sn->v) {
452			if (!_read_segment(mem, vg, lv, sn, pv_hash))
453				return_0;
454
455			count++;
456		}
457		/* FIXME Remove this restriction */
458		if ((lv->status & SNAPSHOT) && count > 1) {
459			log_error("Only one segment permitted for snapshot");
460			return 0;
461		}
462	}
463
464	if (!_read_int32(lvn, "segment_count", &seg_count)) {
465		log_error("Couldn't read segment count for logical volume %s.",
466			  lv->name);
467		return 0;
468	}
469
470	if (seg_count != count) {
471		log_error("segment_count and actual number of segments "
472			  "disagree for logical volume %s.", lv->name);
473		return 0;
474	}
475
476	/*
477	 * Check there are no gaps or overlaps in the lv.
478	 */
479	if (!check_lv_segments(lv, 0))
480		return_0;
481
482	/*
483	 * Merge segments in case someones been editing things by hand.
484	 */
485	if (!lv_merge_segments(lv))
486		return_0;
487
488	return 1;
489}
490
491static int _read_lvnames(struct format_instance *fid __attribute((unused)),
492			 struct dm_pool *mem,
493			 struct volume_group *vg, struct config_node *lvn,
494			 struct config_node *vgn __attribute((unused)),
495			 struct dm_hash_table *pv_hash __attribute((unused)))
496{
497	struct logical_volume *lv;
498	struct config_node *cn;
499
500	if (!(lv = alloc_lv(mem)))
501		return_0;
502
503	if (!(lv->name = dm_pool_strdup(mem, lvn->key)))
504		return_0;
505
506	if (!(lvn = lvn->child)) {
507		log_error("Empty logical volume section.");
508		return 0;
509	}
510
511	if (!_read_flag_config(lvn, &lv->status, LV_FLAGS)) {
512		log_error("Couldn't read status flags for logical volume %s.",
513			  lv->name);
514		return 0;
515	}
516
517	lv->alloc = ALLOC_INHERIT;
518	if ((cn = find_config_node(lvn, "allocation_policy"))) {
519		struct config_value *cv = cn->v;
520		if (!cv || !cv->v.str) {
521			log_error("allocation_policy must be a string.");
522			return 0;
523		}
524
525		lv->alloc = get_alloc_from_string(cv->v.str);
526		if (lv->alloc == ALLOC_INVALID)
527			return_0;
528	}
529
530	if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
531		/* If not present, choice of auto or none is configurable */
532		lv->read_ahead = vg->cmd->default_settings.read_ahead;
533	else {
534		switch (lv->read_ahead) {
535		case 0:
536			lv->read_ahead = DM_READ_AHEAD_AUTO;
537			break;
538		case (uint32_t) -1:
539			lv->read_ahead = DM_READ_AHEAD_NONE;
540			break;
541		default:
542			;
543		}
544	}
545
546	/* Optional tags */
547	if ((cn = find_config_node(lvn, "tags")) &&
548	    !(read_tags(mem, &lv->tags, cn->v))) {
549		log_error("Couldn't read tags for logical volume %s/%s.",
550			  vg->name, lv->name);
551		return 0;
552	}
553
554	return link_lv_to_vg(vg, lv);
555}
556
557static int _read_lvsegs(struct format_instance *fid __attribute((unused)),
558			struct dm_pool *mem,
559			struct volume_group *vg, struct config_node *lvn,
560			struct config_node *vgn __attribute((unused)),
561			struct dm_hash_table *pv_hash)
562{
563	struct logical_volume *lv;
564	struct lv_list *lvl;
565
566	if (!(lvl = find_lv_in_vg(vg, lvn->key))) {
567		log_error("Lost logical volume reference %s", lvn->key);
568		return 0;
569	}
570
571	lv = lvl->lv;
572
573	if (!(lvn = lvn->child)) {
574		log_error("Empty logical volume section.");
575		return 0;
576	}
577
578	/* FIXME: read full lvid */
579	if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
580		log_error("Couldn't read uuid for logical volume %s.",
581			  lv->name);
582		return 0;
583	}
584
585	memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
586
587	if (!_read_segments(mem, vg, lv, lvn, pv_hash))
588		return_0;
589
590	lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
591
592	lv->minor = -1;
593	if ((lv->status & FIXED_MINOR) &&
594	    !_read_int32(lvn, "minor", &lv->minor)) {
595		log_error("Couldn't read minor number for logical "
596			  "volume %s.", lv->name);
597		return 0;
598	}
599
600	lv->major = -1;
601	if ((lv->status & FIXED_MINOR) &&
602	    !_read_int32(lvn, "major", &lv->major)) {
603		log_error("Couldn't read major number for logical "
604			  "volume %s.", lv->name);
605	}
606
607	return 1;
608}
609
610static int _read_sections(struct format_instance *fid,
611			  const char *section, section_fn fn,
612			  struct dm_pool *mem,
613			  struct volume_group *vg, struct config_node *vgn,
614			  struct dm_hash_table *pv_hash, int optional)
615{
616	struct config_node *n;
617
618	if (!(n = find_config_node(vgn, section))) {
619		if (!optional) {
620			log_error("Couldn't find section '%s'.", section);
621			return 0;
622		}
623
624		return 1;
625	}
626
627	for (n = n->child; n; n = n->sib) {
628		if (!fn(fid, mem, vg, n, vgn, pv_hash))
629			return_0;
630	}
631
632	return 1;
633}
634
635static struct volume_group *_read_vg(struct format_instance *fid,
636				     struct config_tree *cft)
637{
638	struct config_node *vgn, *cn;
639	struct volume_group *vg;
640	struct dm_hash_table *pv_hash = NULL;
641	struct dm_pool *mem = dm_pool_create("lvm2 vg_read", VG_MEMPOOL_CHUNK);
642
643	if (!mem)
644		return_NULL;
645
646	/* skip any top-level values */
647	for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
648
649	if (!vgn) {
650		log_error("Couldn't find volume group in file.");
651		goto bad;
652	}
653
654	if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
655		goto_bad;
656
657	vg->vgmem = mem;
658	vg->cmd = fid->fmt->cmd;
659
660	/* FIXME Determine format type from file contents */
661	/* eg Set to instance of fmt1 here if reading a format1 backup? */
662	vg->fid = fid;
663
664	if (!(vg->name = dm_pool_strdup(mem, vgn->key)))
665		goto_bad;
666
667	if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN)))
668		goto_bad;
669
670	vgn = vgn->child;
671
672	if ((cn = find_config_node(vgn, "system_id")) && cn->v) {
673		if (!cn->v->v.str) {
674			log_error("system_id must be a string");
675			goto bad;
676		}
677		strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
678	}
679
680	if (!_read_id(&vg->id, vgn, "id")) {
681		log_error("Couldn't read uuid for volume group %s.", vg->name);
682		goto bad;
683	}
684
685	if (!_read_int32(vgn, "seqno", &vg->seqno)) {
686		log_error("Couldn't read 'seqno' for volume group %s.",
687			  vg->name);
688		goto bad;
689	}
690
691	if (!_read_flag_config(vgn, &vg->status, VG_FLAGS)) {
692		log_error("Error reading flags of volume group %s.",
693			  vg->name);
694		goto bad;
695	}
696
697	if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
698		log_error("Couldn't read extent size for volume group %s.",
699			  vg->name);
700		goto bad;
701	}
702
703	/*
704	 * 'extent_count' and 'free_count' get filled in
705	 * implicitly when reading in the pv's and lv's.
706	 */
707
708	if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
709		log_error("Couldn't read 'max_lv' for volume group %s.",
710			  vg->name);
711		goto bad;
712	}
713
714	if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
715		log_error("Couldn't read 'max_pv' for volume group %s.",
716			  vg->name);
717		goto bad;
718	}
719
720	vg->alloc = ALLOC_NORMAL;
721	if ((cn = find_config_node(vgn, "allocation_policy"))) {
722		struct config_value *cv = cn->v;
723		if (!cv || !cv->v.str) {
724			log_error("allocation_policy must be a string.");
725			return 0;
726		}
727
728		vg->alloc = get_alloc_from_string(cv->v.str);
729		if (vg->alloc == ALLOC_INVALID)
730			return_0;
731	}
732
733	/*
734	 * The pv hash memoises the pv section names -> pv
735	 * structures.
736	 */
737	if (!(pv_hash = dm_hash_create(32))) {
738		log_error("Couldn't create hash table.");
739		goto bad;
740	}
741
742	dm_list_init(&vg->pvs);
743	if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
744			    vgn, pv_hash, 0)) {
745		log_error("Couldn't find all physical volumes for volume "
746			  "group %s.", vg->name);
747		goto bad;
748	}
749
750	dm_list_init(&vg->lvs);
751	dm_list_init(&vg->tags);
752	dm_list_init(&vg->removed_pvs);
753
754	/* Optional tags */
755	if ((cn = find_config_node(vgn, "tags")) &&
756	    !(read_tags(mem, &vg->tags, cn->v))) {
757		log_error("Couldn't read tags for volume group %s.", vg->name);
758		goto bad;
759	}
760
761	if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
762			    vgn, pv_hash, 1)) {
763		log_error("Couldn't read all logical volume names for volume "
764			  "group %s.", vg->name);
765		goto bad;
766	}
767
768	if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg,
769			    vgn, pv_hash, 1)) {
770		log_error("Couldn't read all logical volumes for "
771			  "volume group %s.", vg->name);
772		goto bad;
773	}
774
775	if (!fixup_imported_mirrors(vg)) {
776		log_error("Failed to fixup mirror pointers after import for "
777			  "volume group %s.", vg->name);
778		goto bad;
779	}
780
781	dm_hash_destroy(pv_hash);
782
783	/*
784	 * Finished.
785	 */
786	return vg;
787
788      bad:
789	if (pv_hash)
790		dm_hash_destroy(pv_hash);
791
792	dm_pool_destroy(mem);
793	return NULL;
794}
795
796static void _read_desc(struct dm_pool *mem,
797		       struct config_tree *cft, time_t *when, char **desc)
798{
799	const char *d;
800	unsigned int u = 0u;
801	int old_suppress;
802
803	old_suppress = log_suppress(1);
804	d = find_config_str(cft->root, "description", "");
805	log_suppress(old_suppress);
806	*desc = dm_pool_strdup(mem, d);
807
808	get_config_uint32(cft->root, "creation_time", &u);
809	*when = u;
810}
811
812static const char *_read_vgname(const struct format_type *fmt,
813				struct config_tree *cft, struct id *vgid,
814				uint32_t *vgstatus, char **creation_host)
815{
816	struct config_node *vgn;
817	struct dm_pool *mem = fmt->cmd->mem;
818	char *vgname;
819	int old_suppress;
820
821	old_suppress = log_suppress(2);
822	*creation_host = dm_pool_strdup(mem,
823					find_config_str(cft->root,
824							"creation_host", ""));
825	log_suppress(old_suppress);
826
827	/* skip any top-level values */
828	for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
829
830	if (!vgn) {
831		log_error("Couldn't find volume group in file.");
832		return 0;
833	}
834
835	if (!(vgname = dm_pool_strdup(mem, vgn->key)))
836		return_0;
837
838	vgn = vgn->child;
839
840	if (!_read_id(vgid, vgn, "id")) {
841		log_error("Couldn't read uuid for volume group %s.", vgname);
842		return 0;
843	}
844
845	if (!_read_flag_config(vgn, vgstatus, VG_FLAGS)) {
846		log_error("Couldn't find status flags for volume group %s.",
847			  vgname);
848		return 0;
849	}
850
851	return vgname;
852}
853
854static struct text_vg_version_ops _vsn1_ops = {
855	.check_version = _check_version,
856	.read_vg = _read_vg,
857	.read_desc = _read_desc,
858	.read_vgname = _read_vgname,
859};
860
861struct text_vg_version_ops *text_vg_vsn1_init(void)
862{
863	return &_vsn1_ops;
864}
865