Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "import-export.h"
18 : : #include "metadata.h"
19 : : #include "display.h"
20 : : #include "lvm-string.h"
21 : : #include "segtype.h"
22 : : #include "text_export.h"
23 : : #include "lvm-version.h"
24 : :
25 : : #include <stdarg.h>
26 : : #include <time.h>
27 : : #include <sys/utsname.h>
28 : :
29 : : struct formatter;
30 : : typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
31 : : const char *fmt, va_list ap);
32 : : typedef int (*nl_fn) (struct formatter * f);
33 : :
34 : : /*
35 : : * Macro for formatted output.
36 : : * out_with_comment_fn returns -1 if data didn't fit and buffer was expanded.
37 : : * Then argument list is reset and out_with_comment_fn is called again.
38 : : */
39 : : #define _out_with_comment(f, buffer, fmt, ap) \
40 : : do { \
41 : : va_start(ap, fmt); \
42 : : r = f->out_with_comment(f, buffer, fmt, ap); \
43 : : va_end(ap); \
44 : : } while (r == -1)
45 : :
46 : : /*
47 : : * The first half of this file deals with
48 : : * exporting the vg, ie. writing it to a file.
49 : : */
50 : : struct formatter {
51 : : struct dm_pool *mem; /* pv names allocated from here */
52 : : struct dm_hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
53 : :
54 : : union {
55 : : FILE *fp; /* where we're writing to */
56 : : struct {
57 : : char *start;
58 : : uint32_t size;
59 : : uint32_t used;
60 : : } buf;
61 : : } data;
62 : :
63 : : out_with_comment_fn out_with_comment;
64 : : nl_fn nl;
65 : :
66 : : int indent; /* current level of indentation */
67 : : int error;
68 : : int header; /* 1 => comments at start; 0 => end */
69 : : };
70 : :
71 : : static struct utsname _utsname;
72 : :
73 : 0 : static void _init(void)
74 : : {
75 : : static int _initialised = 0;
76 : :
77 [ # # ]: 0 : if (_initialised)
78 : 0 : return;
79 : :
80 [ # # ]: 0 : if (uname(&_utsname)) {
81 : 0 : log_error("uname failed: %s", strerror(errno));
82 : 0 : memset(&_utsname, 0, sizeof(_utsname));
83 : : }
84 : :
85 : 0 : _initialised = 1;
86 : : }
87 : :
88 : : /*
89 : : * Formatting functions.
90 : : */
91 : :
92 : : #define MAX_INDENT 5
93 : 0 : static void _inc_indent(struct formatter *f)
94 : : {
95 [ # # ]: 0 : if (++f->indent > MAX_INDENT)
96 : 0 : f->indent = MAX_INDENT;
97 : 0 : }
98 : :
99 : 0 : static void _dec_indent(struct formatter *f)
100 : : {
101 [ # # ]: 0 : if (!f->indent--) {
102 : 0 : log_error(INTERNAL_ERROR "problem tracking indentation");
103 : 0 : f->indent = 0;
104 : : }
105 : 0 : }
106 : :
107 : : /*
108 : : * Newline function for prettier layout.
109 : : */
110 : 0 : static int _nl_file(struct formatter *f)
111 : : {
112 : 0 : fprintf(f->data.fp, "\n");
113 : :
114 : 0 : return 1;
115 : : }
116 : :
117 : 0 : static int _extend_buffer(struct formatter *f)
118 : : {
119 : : char *newbuf;
120 : :
121 : 0 : log_debug("Doubling metadata output buffer to %" PRIu32,
122 : : f->data.buf.size * 2);
123 [ # # ]: 0 : if (!(newbuf = dm_realloc(f->data.buf.start,
124 : : f->data.buf.size * 2))) {
125 : 0 : log_error("Buffer reallocation failed.");
126 : 0 : return 0;
127 : : }
128 : 0 : f->data.buf.start = newbuf;
129 : 0 : f->data.buf.size *= 2;
130 : :
131 : 0 : return 1;
132 : : }
133 : :
134 : 0 : static int _nl_raw(struct formatter *f)
135 : : {
136 : : /* If metadata doesn't fit, extend buffer */
137 [ # # # # ]: 0 : if ((f->data.buf.used + 2 > f->data.buf.size) &&
138 : 0 : (!_extend_buffer(f)))
139 : 0 : return_0;
140 : :
141 : 0 : *(f->data.buf.start + f->data.buf.used) = '\n';
142 : 0 : f->data.buf.used += 1;
143 : :
144 : 0 : *(f->data.buf.start + f->data.buf.used) = '\0';
145 : :
146 : 0 : return 1;
147 : : }
148 : :
149 : : #define COMMENT_TAB 6
150 : 0 : static int _out_with_comment_file(struct formatter *f, const char *comment,
151 : : const char *fmt, va_list ap)
152 : : {
153 : : int i;
154 : : char white_space[MAX_INDENT + 1];
155 : :
156 [ # # ]: 0 : if (ferror(f->data.fp))
157 : 0 : return 0;
158 : :
159 [ # # ]: 0 : for (i = 0; i < f->indent; i++)
160 : 0 : white_space[i] = '\t';
161 : 0 : white_space[i] = '\0';
162 : 0 : fputs(white_space, f->data.fp);
163 : 0 : i = vfprintf(f->data.fp, fmt, ap);
164 : :
165 [ # # ]: 0 : if (comment) {
166 : : /*
167 : : * line comments up if possible.
168 : : */
169 : 0 : i += 8 * f->indent;
170 : 0 : i /= 8;
171 : 0 : i++;
172 : :
173 : : do
174 : 0 : fputc('\t', f->data.fp);
175 : :
176 [ # # ]: 0 : while (++i < COMMENT_TAB);
177 : :
178 : 0 : fputs(comment, f->data.fp);
179 : : }
180 : 0 : fputc('\n', f->data.fp);
181 : :
182 : 0 : return 1;
183 : : }
184 : :
185 : 0 : static int _out_with_comment_raw(struct formatter *f,
186 : : const char *comment __attribute((unused)),
187 : : const char *fmt, va_list ap)
188 : : {
189 : : int n;
190 : :
191 : 0 : n = vsnprintf(f->data.buf.start + f->data.buf.used,
192 : : f->data.buf.size - f->data.buf.used, fmt, ap);
193 : :
194 : : /* If metadata doesn't fit, extend buffer */
195 [ # # ][ # # ]: 0 : if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
196 [ # # ]: 0 : if (!_extend_buffer(f))
197 : 0 : return_0;
198 : 0 : return -1; /* Retry */
199 : : }
200 : :
201 : 0 : f->data.buf.used += n;
202 : :
203 [ # # ]: 0 : outnl(f);
204 : :
205 : 0 : return 1;
206 : : }
207 : :
208 : : /*
209 : : * Formats a string, converting a size specified
210 : : * in 512-byte sectors to a more human readable
211 : : * form (eg, megabytes). We may want to lift this
212 : : * for other code to use.
213 : : */
214 : 0 : static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
215 : : {
216 : : static const char *_units[] = {
217 : : "Kilobytes",
218 : : "Megabytes",
219 : : "Gigabytes",
220 : : "Terabytes",
221 : : "Petabytes",
222 : : "Exabytes",
223 : : NULL
224 : : };
225 : :
226 : : int i;
227 : 0 : double d = (double) sectors;
228 : :
229 : : /* to convert to K */
230 : 0 : d /= 2.0;
231 : :
232 [ # # ][ # # ]: 0 : for (i = 0; (d > 1024.0) && _units[i]; i++)
233 : 0 : d /= 1024.0;
234 : :
235 : 0 : return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
236 : : }
237 : :
238 : : /* increment indention level */
239 : 0 : void out_inc_indent(struct formatter *f)
240 : : {
241 : 0 : _inc_indent(f);
242 : 0 : }
243 : :
244 : : /* decrement indention level */
245 : 0 : void out_dec_indent(struct formatter *f)
246 : : {
247 : 0 : _dec_indent(f);
248 : 0 : }
249 : :
250 : : /* insert new line */
251 : 0 : int out_newline(struct formatter *f)
252 : : {
253 : 0 : return f->nl(f);
254 : : }
255 : :
256 : : /*
257 : : * Appends a comment giving a size in more easily
258 : : * readable form (eg, 4M instead of 8096).
259 : : */
260 : 0 : int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
261 : : {
262 : : char buffer[64];
263 : : va_list ap;
264 : : int r;
265 : :
266 [ # # ]: 0 : if (!_sectors_to_units(size, buffer, sizeof(buffer)))
267 : 0 : return 0;
268 : :
269 [ # # ]: 0 : _out_with_comment(f, buffer, fmt, ap);
270 : :
271 : 0 : return r;
272 : : }
273 : :
274 : : /*
275 : : * Appends a comment indicating that the line is
276 : : * only a hint.
277 : : */
278 : 0 : int out_hint(struct formatter *f, const char *fmt, ...)
279 : : {
280 : : va_list ap;
281 : : int r;
282 : :
283 [ # # ]: 0 : _out_with_comment(f, "# Hint only", fmt, ap);
284 : :
285 : 0 : return r;
286 : : }
287 : :
288 : : /*
289 : : * The normal output function with comment
290 : : */
291 : 0 : int out_text_with_comment(struct formatter *f, const char *comment, const char *fmt, ...)
292 : : {
293 : : va_list ap;
294 : : int r;
295 : :
296 [ # # ]: 0 : _out_with_comment(f, comment, fmt, ap);
297 : :
298 : 0 : return r;
299 : : }
300 : :
301 : : /*
302 : : * The normal output function.
303 : : */
304 : 0 : int out_text(struct formatter *f, const char *fmt, ...)
305 : : {
306 : : va_list ap;
307 : : int r;
308 : :
309 [ # # ]: 0 : _out_with_comment(f, NULL, fmt, ap);
310 : :
311 : 0 : return r;
312 : : }
313 : :
314 : 0 : static int _out_line(const char *line, void *_f) {
315 : 0 : struct formatter *f = (struct formatter *) _f;
316 : 0 : return out_text(f, "%s", line);
317 : : }
318 : :
319 : 0 : int out_config_node(struct formatter *f, const struct config_node *cn)
320 : : {
321 : 0 : return write_config_node(cn, _out_line, f);
322 : : }
323 : :
324 : 0 : static int _print_header(struct formatter *f,
325 : : const char *desc)
326 : : {
327 : : char *buf;
328 : : time_t t;
329 : :
330 : 0 : t = time(NULL);
331 : :
332 [ # # ]: 0 : outf(f, "# Generated by LVM2 version %s: %s", LVM_VERSION, ctime(&t));
333 [ # # ]: 0 : outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
334 [ # # ]: 0 : outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
335 [ # # ]: 0 : outnl(f);
336 : :
337 : 0 : if (!(buf = alloca(escaped_len(desc)))) {
338 : : log_error("temporary stack allocation for description"
339 : : "string failed");
340 : : return 0;
341 : : }
342 [ # # ]: 0 : outf(f, "description = \"%s\"", escape_double_quotes(buf, desc));
343 [ # # ]: 0 : outnl(f);
344 [ # # ]: 0 : outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
345 : : _utsname.sysname, _utsname.nodename, _utsname.release,
346 : : _utsname.version, _utsname.machine);
347 [ # # ]: 0 : outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
348 : :
349 : 0 : return 1;
350 : : }
351 : :
352 : 0 : static int _print_flag_config(struct formatter *f, uint64_t status, int type)
353 : : {
354 : : char buffer[4096];
355 [ # # ]: 0 : if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer)))
356 : 0 : return_0;
357 [ # # ]: 0 : outf(f, "status = %s", buffer);
358 : :
359 [ # # ]: 0 : if (!print_flags(status, type, buffer, sizeof(buffer)))
360 : 0 : return_0;
361 [ # # ]: 0 : outf(f, "flags = %s", buffer);
362 : :
363 : 0 : return 1;
364 : : }
365 : :
366 : 0 : static int _print_vg(struct formatter *f, struct volume_group *vg)
367 : : {
368 : : char buffer[4096];
369 : :
370 [ # # ]: 0 : if (!id_write_format(&vg->id, buffer, sizeof(buffer)))
371 : 0 : return_0;
372 : :
373 [ # # ]: 0 : outf(f, "id = \"%s\"", buffer);
374 : :
375 [ # # ]: 0 : outf(f, "seqno = %u", vg->seqno);
376 : :
377 [ # # ]: 0 : if (!_print_flag_config(f, vg->status, VG_FLAGS))
378 : 0 : return_0;
379 : :
380 [ # # ]: 0 : if (!dm_list_empty(&vg->tags)) {
381 [ # # ]: 0 : if (!print_tags(&vg->tags, buffer, sizeof(buffer)))
382 : 0 : return_0;
383 [ # # ]: 0 : outf(f, "tags = %s", buffer);
384 : : }
385 : :
386 [ # # ][ # # ]: 0 : if (vg->system_id && *vg->system_id)
387 [ # # ]: 0 : outf(f, "system_id = \"%s\"", vg->system_id);
388 : :
389 [ # # ]: 0 : outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
390 : : vg->extent_size);
391 [ # # ]: 0 : outf(f, "max_lv = %u", vg->max_lv);
392 [ # # ]: 0 : outf(f, "max_pv = %u", vg->max_pv);
393 : :
394 : : /* Default policy is NORMAL; INHERIT is meaningless */
395 [ # # ][ # # ]: 0 : if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
396 [ # # ]: 0 : outnl(f);
397 [ # # ]: 0 : outf(f, "allocation_policy = \"%s\"",
398 : : get_alloc_string(vg->alloc));
399 : : }
400 : :
401 : 0 : return 1;
402 : : }
403 : :
404 : : /*
405 : : * Get the pv%d name from the formatters hash
406 : : * table.
407 : : */
408 : 0 : static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid)
409 : : {
410 : 0 : return dm_hash_lookup(f->pv_names, uuid);
411 : : }
412 : :
413 : 0 : static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv)
414 : : {
415 : : char uuid[64] __attribute((aligned(8)));
416 : :
417 [ # # ][ # # ]: 0 : if (!pv || !id_write_format(&pv->id, uuid, sizeof(uuid)))
418 : 0 : return_NULL;
419 : :
420 : 0 : return _get_pv_name_from_uuid(f, uuid);
421 : : }
422 : :
423 : 0 : static int _print_pvs(struct formatter *f, struct volume_group *vg)
424 : : {
425 : : struct pv_list *pvl;
426 : : struct physical_volume *pv;
427 : : char buffer[4096];
428 : : char *buf;
429 : : const char *name;
430 : :
431 [ # # ]: 0 : outf(f, "physical_volumes {");
432 : 0 : _inc_indent(f);
433 : :
434 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
435 : 0 : pv = pvl->pv;
436 : :
437 [ # # ]: 0 : if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
438 : 0 : return_0;
439 : :
440 [ # # ]: 0 : if (!(name = _get_pv_name_from_uuid(f, buffer)))
441 : 0 : return_0;
442 : :
443 [ # # ]: 0 : outnl(f);
444 [ # # ]: 0 : outf(f, "%s {", name);
445 : 0 : _inc_indent(f);
446 : :
447 [ # # ]: 0 : outf(f, "id = \"%s\"", buffer);
448 : :
449 : 0 : if (!(buf = alloca(escaped_len(pv_dev_name(pv))))) {
450 : : log_error("temporary stack allocation for device name"
451 : : "string failed");
452 : : return 0;
453 : : }
454 : :
455 [ # # ]: 0 : outhint(f, "device = \"%s\"",
456 : : escape_double_quotes(buf, pv_dev_name(pv)));
457 [ # # ]: 0 : outnl(f);
458 : :
459 [ # # ]: 0 : if (!_print_flag_config(f, pv->status, PV_FLAGS))
460 : 0 : return_0;
461 : :
462 [ # # ]: 0 : if (!dm_list_empty(&pv->tags)) {
463 [ # # ]: 0 : if (!print_tags(&pv->tags, buffer, sizeof(buffer)))
464 : 0 : return_0;
465 [ # # ]: 0 : outf(f, "tags = %s", buffer);
466 : : }
467 : :
468 [ # # ]: 0 : outsize(f, pv->size, "dev_size = %" PRIu64, pv->size);
469 : :
470 [ # # ]: 0 : outf(f, "pe_start = %" PRIu64, pv->pe_start);
471 [ # # ]: 0 : outsize(f, vg->extent_size * (uint64_t) pv->pe_count,
472 : : "pe_count = %u", pv->pe_count);
473 : :
474 : 0 : _dec_indent(f);
475 [ # # ]: 0 : outf(f, "}");
476 : : }
477 : :
478 : 0 : _dec_indent(f);
479 [ # # ]: 0 : outf(f, "}");
480 : 0 : return 1;
481 : : }
482 : :
483 : 0 : static int _print_segment(struct formatter *f, struct volume_group *vg,
484 : : int count, struct lv_segment *seg)
485 : : {
486 : : char buffer[4096];
487 : :
488 [ # # ]: 0 : outf(f, "segment%u {", count);
489 : 0 : _inc_indent(f);
490 : :
491 [ # # ]: 0 : outf(f, "start_extent = %u", seg->le);
492 [ # # ]: 0 : outsize(f, (uint64_t) seg->len * vg->extent_size,
493 : : "extent_count = %u", seg->len);
494 : :
495 [ # # ]: 0 : outnl(f);
496 [ # # ]: 0 : outf(f, "type = \"%s\"", seg->segtype->name);
497 : :
498 [ # # ]: 0 : if (!dm_list_empty(&seg->tags)) {
499 [ # # ]: 0 : if (!print_tags(&seg->tags, buffer, sizeof(buffer)))
500 : 0 : return_0;
501 [ # # ]: 0 : outf(f, "tags = %s", buffer);
502 : : }
503 : :
504 [ # # # # ]: 0 : if (seg->segtype->ops->text_export &&
505 : 0 : !seg->segtype->ops->text_export(seg, f))
506 : 0 : return_0;
507 : :
508 : 0 : _dec_indent(f);
509 [ # # ]: 0 : outf(f, "}");
510 : :
511 : 0 : return 1;
512 : : }
513 : :
514 : 0 : int out_areas(struct formatter *f, const struct lv_segment *seg,
515 : : const char *type)
516 : : {
517 : : const char *name;
518 : : unsigned int s;
519 : :
520 [ # # ]: 0 : outnl(f);
521 : :
522 [ # # ]: 0 : outf(f, "%ss = [", type);
523 : 0 : _inc_indent(f);
524 : :
525 [ # # ]: 0 : for (s = 0; s < seg->area_count; s++) {
526 [ # # # # ]: 0 : switch (seg_type(seg, s)) {
527 : : case AREA_PV:
528 [ # # ]: 0 : if (!(name = _get_pv_name(f, seg_pv(seg, s))))
529 : 0 : return_0;
530 : :
531 [ # # ][ # # ]: 0 : outf(f, "\"%s\", %u%s", name,
532 : : seg_pe(seg, s),
533 : : (s == seg->area_count - 1) ? "" : ",");
534 : 0 : break;
535 : : case AREA_LV:
536 [ # # ][ # # ]: 0 : outf(f, "\"%s\", %u%s",
537 : : seg_lv(seg, s)->name,
538 : : seg_le(seg, s),
539 : : (s == seg->area_count - 1) ? "" : ",");
540 : 0 : break;
541 : : case AREA_UNASSIGNED:
542 : 0 : return 0;
543 : : }
544 : : }
545 : :
546 : 0 : _dec_indent(f);
547 [ # # ]: 0 : outf(f, "]");
548 : 0 : return 1;
549 : : }
550 : :
551 : 0 : static int _print_lv(struct formatter *f, struct logical_volume *lv)
552 : : {
553 : : struct lv_segment *seg;
554 : : char buffer[4096];
555 : : int seg_count;
556 : :
557 [ # # ]: 0 : outnl(f);
558 [ # # ]: 0 : outf(f, "%s {", lv->name);
559 : 0 : _inc_indent(f);
560 : :
561 : : /* FIXME: Write full lvid */
562 [ # # ]: 0 : if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer)))
563 : 0 : return_0;
564 : :
565 [ # # ]: 0 : outf(f, "id = \"%s\"", buffer);
566 : :
567 [ # # ]: 0 : if (!_print_flag_config(f, lv->status, LV_FLAGS))
568 : 0 : return_0;
569 : :
570 [ # # ]: 0 : if (!dm_list_empty(&lv->tags)) {
571 [ # # ]: 0 : if (!print_tags(&lv->tags, buffer, sizeof(buffer)))
572 : 0 : return_0;
573 [ # # ]: 0 : outf(f, "tags = %s", buffer);
574 : : }
575 : :
576 [ # # ]: 0 : if (lv->alloc != ALLOC_INHERIT)
577 [ # # ]: 0 : outf(f, "allocation_policy = \"%s\"",
578 : : get_alloc_string(lv->alloc));
579 : :
580 [ # # # ]: 0 : switch (lv->read_ahead) {
581 : : case DM_READ_AHEAD_NONE:
582 [ # # ]: 0 : outfc(f, "# None", "read_ahead = -1");
583 : 0 : break;
584 : : case DM_READ_AHEAD_AUTO:
585 : : /* No output - use default */
586 : 0 : break;
587 : : default:
588 [ # # ]: 0 : outf(f, "read_ahead = %u", lv->read_ahead);
589 : : }
590 : :
591 [ # # ]: 0 : if (lv->major >= 0)
592 [ # # ]: 0 : outf(f, "major = %d", lv->major);
593 [ # # ]: 0 : if (lv->minor >= 0)
594 [ # # ]: 0 : outf(f, "minor = %d", lv->minor);
595 [ # # ]: 0 : outf(f, "segment_count = %u", dm_list_size(&lv->segments));
596 [ # # ]: 0 : outnl(f);
597 : :
598 : 0 : seg_count = 1;
599 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments) {
600 [ # # ]: 0 : if (!_print_segment(f, lv->vg, seg_count++, seg))
601 : 0 : return_0;
602 : : }
603 : :
604 : 0 : _dec_indent(f);
605 [ # # ]: 0 : outf(f, "}");
606 : :
607 : 0 : return 1;
608 : : }
609 : :
610 : 0 : static int _print_lvs(struct formatter *f, struct volume_group *vg)
611 : : {
612 : : struct lv_list *lvl;
613 : :
614 : : /*
615 : : * Don't bother with an lv section if there are no lvs.
616 : : */
617 [ # # ]: 0 : if (dm_list_empty(&vg->lvs))
618 : 0 : return 1;
619 : :
620 [ # # ]: 0 : outf(f, "logical_volumes {");
621 : 0 : _inc_indent(f);
622 : :
623 : : /*
624 : : * Write visible LVs first
625 : : */
626 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
627 [ # # ]: 0 : if (!(lv_is_visible(lvl->lv)))
628 : 0 : continue;
629 [ # # ]: 0 : if (!_print_lv(f, lvl->lv))
630 : 0 : return_0;
631 : : }
632 : :
633 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
634 [ # # ]: 0 : if ((lv_is_visible(lvl->lv)))
635 : 0 : continue;
636 [ # # ]: 0 : if (!_print_lv(f, lvl->lv))
637 : 0 : return_0;
638 : : }
639 : :
640 : 0 : _dec_indent(f);
641 [ # # ]: 0 : outf(f, "}");
642 : :
643 : 0 : return 1;
644 : : }
645 : :
646 : : /*
647 : : * In the text format we refer to pv's as 'pv1',
648 : : * 'pv2' etc. This function builds a hash table
649 : : * to enable a quick lookup from device -> name.
650 : : */
651 : 0 : static int _build_pv_names(struct formatter *f, struct volume_group *vg)
652 : : {
653 : 0 : int count = 0;
654 : : struct pv_list *pvl;
655 : : struct physical_volume *pv;
656 : : char buffer[32], *uuid, *name;
657 : :
658 [ # # ]: 0 : if (!(f->mem = dm_pool_create("text pv_names", 512)))
659 : 0 : return_0;
660 : :
661 [ # # ]: 0 : if (!(f->pv_names = dm_hash_create(128)))
662 : 0 : return_0;
663 : :
664 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
665 : 0 : pv = pvl->pv;
666 : :
667 : : /* FIXME But skip if there's already an LV called pv%d ! */
668 [ # # ]: 0 : if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
669 : 0 : return_0;
670 : :
671 [ # # ]: 0 : if (!(name = dm_pool_strdup(f->mem, buffer)))
672 : 0 : return_0;
673 : :
674 [ # # # # ]: 0 : if (!(uuid = dm_pool_zalloc(f->mem, 64)) ||
675 : 0 : !id_write_format(&pv->id, uuid, 64))
676 : 0 : return_0;
677 : :
678 [ # # ]: 0 : if (!dm_hash_insert(f->pv_names, uuid, name))
679 : 0 : return_0;
680 : : }
681 : :
682 : 0 : return 1;
683 : : }
684 : :
685 : 0 : static int _text_vg_export(struct formatter *f,
686 : : struct volume_group *vg, const char *desc)
687 : : {
688 : 0 : int r = 0;
689 : :
690 [ # # ]: 0 : if (!_build_pv_names(f, vg))
691 : 0 : goto_out;
692 : :
693 [ # # ][ # # ]: 0 : if (f->header && !_print_header(f, desc))
694 : 0 : goto_out;
695 : :
696 [ # # ]: 0 : if (!out_text(f, "%s {", vg->name))
697 : 0 : goto_out;
698 : :
699 : 0 : _inc_indent(f);
700 : :
701 [ # # ]: 0 : if (!_print_vg(f, vg))
702 : 0 : goto_out;
703 : :
704 [ # # ]: 0 : outnl(f);
705 [ # # ]: 0 : if (!_print_pvs(f, vg))
706 : 0 : goto_out;
707 : :
708 [ # # ]: 0 : outnl(f);
709 [ # # ]: 0 : if (!_print_lvs(f, vg))
710 : 0 : goto_out;
711 : :
712 : 0 : _dec_indent(f);
713 [ # # ]: 0 : if (!out_text(f, "}"))
714 : 0 : goto_out;
715 : :
716 [ # # ][ # # ]: 0 : if (!f->header && !_print_header(f, desc))
717 : 0 : goto_out;
718 : :
719 : 0 : r = 1;
720 : :
721 : : out:
722 [ # # ]: 0 : if (f->mem)
723 : 0 : dm_pool_destroy(f->mem);
724 : :
725 [ # # ]: 0 : if (f->pv_names)
726 : 0 : dm_hash_destroy(f->pv_names);
727 : :
728 : 0 : return r;
729 : : }
730 : :
731 : 0 : int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
732 : : {
733 : : struct formatter *f;
734 : : int r;
735 : :
736 : 0 : _init();
737 : :
738 [ # # ]: 0 : if (!(f = dm_malloc(sizeof(*f))))
739 : 0 : return_0;
740 : :
741 : 0 : memset(f, 0, sizeof(*f));
742 : 0 : f->data.fp = fp;
743 : 0 : f->indent = 0;
744 : 0 : f->header = 1;
745 : 0 : f->out_with_comment = &_out_with_comment_file;
746 : 0 : f->nl = &_nl_file;
747 : :
748 : 0 : r = _text_vg_export(f, vg, desc);
749 [ # # ]: 0 : if (r)
750 : 0 : r = !ferror(f->data.fp);
751 : 0 : dm_free(f);
752 : 0 : return r;
753 : : }
754 : :
755 : : /* Returns amount of buffer used incl. terminating NUL */
756 : 0 : int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
757 : : {
758 : : struct formatter *f;
759 : 0 : int r = 0;
760 : :
761 : 0 : _init();
762 : :
763 [ # # ]: 0 : if (!(f = dm_malloc(sizeof(*f))))
764 : 0 : return_0;
765 : :
766 : 0 : memset(f, 0, sizeof(*f));
767 : :
768 : 0 : f->data.buf.size = 65536; /* Initial metadata limit */
769 [ # # ]: 0 : if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) {
770 : 0 : log_error("text_export buffer allocation failed");
771 : 0 : goto out;
772 : : }
773 : :
774 : 0 : f->indent = 0;
775 : 0 : f->header = 0;
776 : 0 : f->out_with_comment = &_out_with_comment_raw;
777 : 0 : f->nl = &_nl_raw;
778 : :
779 [ # # ]: 0 : if (!_text_vg_export(f, vg, desc)) {
780 : 0 : dm_free(f->data.buf.start);
781 : 0 : goto_out;
782 : : }
783 : :
784 : 0 : r = f->data.buf.used + 1;
785 : 0 : *buf = f->data.buf.start;
786 : :
787 : : out:
788 : 0 : dm_free(f);
789 : 0 : return r;
790 : : }
791 : :
792 : 0 : int export_vg_to_buffer(struct volume_group *vg, char **buf)
793 : : {
794 : 0 : return text_vg_export_raw(vg, "", buf);
795 : : }
796 : :
797 : : #undef outf
798 : : #undef outnl
|