Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / lib / format_text / export.c
blobdceea2750953fde5985ad406b58bc5d817f49981
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
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.
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
18 #include "lib.h"
19 #include "import-export.h"
20 #include "metadata.h"
21 #include "display.h"
22 #include "lvm-string.h"
23 #include "segtype.h"
24 #include "text_export.h"
25 #include "lvm-version.h"
27 #include <stdarg.h>
28 #include <time.h>
29 #include <sys/utsname.h>
31 struct formatter;
32 typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
33 const char *fmt, va_list ap);
34 typedef int (*nl_fn) (struct formatter * f);
37 * Macro for formatted output.
38 * out_with_comment_fn returns -1 if data didn't fit and buffer was expanded.
39 * Then argument list is reset and out_with_comment_fn is called again.
41 #define _out_with_comment(f, buffer, fmt, ap) \
42 do { \
43 va_start(ap, fmt); \
44 r = f->out_with_comment(f, buffer, fmt, ap); \
45 va_end(ap); \
46 } while (r == -1)
49 * The first half of this file deals with
50 * exporting the vg, ie. writing it to a file.
52 struct formatter {
53 struct dm_pool *mem; /* pv names allocated from here */
54 struct dm_hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
56 union {
57 FILE *fp; /* where we're writing to */
58 struct {
59 char *start;
60 uint32_t size;
61 uint32_t used;
62 } buf;
63 } data;
65 out_with_comment_fn out_with_comment;
66 nl_fn nl;
68 int indent; /* current level of indentation */
69 int error;
70 int header; /* 1 => comments at start; 0 => end */
73 static struct utsname _utsname;
75 static void _init(void)
77 static int _initialised = 0;
79 if (_initialised)
80 return;
82 if (uname(&_utsname)) {
83 log_error("uname failed: %s", strerror(errno));
84 memset(&_utsname, 0, sizeof(_utsname));
87 _initialised = 1;
91 * Formatting functions.
94 #define MAX_INDENT 5
95 static void _inc_indent(struct formatter *f)
97 if (++f->indent > MAX_INDENT)
98 f->indent = MAX_INDENT;
101 static void _dec_indent(struct formatter *f)
103 if (!f->indent--) {
104 log_error("Internal error tracking indentation");
105 f->indent = 0;
110 * Newline function for prettier layout.
112 static int _nl_file(struct formatter *f)
114 fprintf(f->data.fp, "\n");
116 return 1;
119 static int _extend_buffer(struct formatter *f)
121 char *newbuf;
123 log_debug("Doubling metadata output buffer to %" PRIu32,
124 f->data.buf.size * 2);
125 if (!(newbuf = dm_realloc(f->data.buf.start,
126 f->data.buf.size * 2))) {
127 log_error("Buffer reallocation failed.");
128 return 0;
130 f->data.buf.start = newbuf;
131 f->data.buf.size *= 2;
133 return 1;
136 static int _nl_raw(struct formatter *f)
138 /* If metadata doesn't fit, extend buffer */
139 if ((f->data.buf.used + 2 > f->data.buf.size) &&
140 (!_extend_buffer(f)))
141 return_0;
143 *(f->data.buf.start + f->data.buf.used) = '\n';
144 f->data.buf.used += 1;
146 *(f->data.buf.start + f->data.buf.used) = '\0';
148 return 1;
151 #define COMMENT_TAB 6
152 static int _out_with_comment_file(struct formatter *f, const char *comment,
153 const char *fmt, va_list ap)
155 int i;
156 char white_space[MAX_INDENT + 1];
158 if (ferror(f->data.fp))
159 return 0;
161 for (i = 0; i < f->indent; i++)
162 white_space[i] = '\t';
163 white_space[i] = '\0';
164 fputs(white_space, f->data.fp);
165 i = vfprintf(f->data.fp, fmt, ap);
167 if (comment) {
169 * line comments up if possible.
171 i += 8 * f->indent;
172 i /= 8;
173 i++;
176 fputc('\t', f->data.fp);
178 while (++i < COMMENT_TAB);
180 fputs(comment, f->data.fp);
182 fputc('\n', f->data.fp);
184 return 1;
187 static int _out_with_comment_raw(struct formatter *f,
188 const char *comment __attribute((unused)),
189 const char *fmt, va_list ap)
191 int n;
193 n = vsnprintf(f->data.buf.start + f->data.buf.used,
194 f->data.buf.size - f->data.buf.used, fmt, ap);
196 /* If metadata doesn't fit, extend buffer */
197 if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
198 if (!_extend_buffer(f))
199 return_0;
200 return -1; /* Retry */
203 f->data.buf.used += n;
205 outnl(f);
207 return 1;
211 * Formats a string, converting a size specified
212 * in 512-byte sectors to a more human readable
213 * form (eg, megabytes). We may want to lift this
214 * for other code to use.
216 static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
218 static const char *_units[] = {
219 "Kilobytes",
220 "Megabytes",
221 "Gigabytes",
222 "Terabytes",
223 "Petabytes",
224 "Exabytes",
225 NULL
228 int i;
229 double d = (double) sectors;
231 /* to convert to K */
232 d /= 2.0;
234 for (i = 0; (d > 1024.0) && _units[i]; i++)
235 d /= 1024.0;
237 return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
240 /* increment indention level */
241 void out_inc_indent(struct formatter *f)
243 _inc_indent(f);
246 /* decrement indention level */
247 void out_dec_indent(struct formatter *f)
249 _dec_indent(f);
252 /* insert new line */
253 int out_newline(struct formatter *f)
255 return f->nl(f);
259 * Appends a comment giving a size in more easily
260 * readable form (eg, 4M instead of 8096).
262 int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
264 char buffer[64];
265 va_list ap;
266 int r;
268 if (!_sectors_to_units(size, buffer, sizeof(buffer)))
269 return 0;
271 _out_with_comment(f, buffer, fmt, ap);
273 return r;
277 * Appends a comment indicating that the line is
278 * only a hint.
280 int out_hint(struct formatter *f, const char *fmt, ...)
282 va_list ap;
283 int r;
285 _out_with_comment(f, "# Hint only", fmt, ap);
287 return r;
291 * Appends a comment
293 static int _out_comment(struct formatter *f, const char *comment, const char *fmt, ...)
295 va_list ap;
296 int r;
298 _out_with_comment(f, comment, fmt, ap);
300 return r;
304 * The normal output function.
306 int out_text(struct formatter *f, const char *fmt, ...)
308 va_list ap;
309 int r;
311 _out_with_comment(f, NULL, fmt, ap);
313 return r;
316 static int _out_line(const char *line, void *_f) {
317 struct formatter *f = (struct formatter *) _f;
318 return out_text(f, "%s", line);
321 int out_config_node(struct formatter *f, const struct config_node *cn)
323 return write_config_node(cn, _out_line, f);
326 static int _print_header(struct formatter *f,
327 const char *desc)
329 char *buf;
330 time_t t;
332 t = time(NULL);
334 outf(f, "# Generated by LVM2 version %s: %s", LVM_VERSION, ctime(&t));
335 outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
336 outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
337 outnl(f);
339 if (!(buf = alloca(escaped_len(desc)))) {
340 log_error("temporary stack allocation for description"
341 "string failed");
342 return 0;
344 outf(f, "description = \"%s\"", escape_double_quotes(buf, desc));
345 outnl(f);
346 outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
347 _utsname.sysname, _utsname.nodename, _utsname.release,
348 _utsname.version, _utsname.machine);
349 outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
351 return 1;
354 static int _print_flag_config(struct formatter *f, int status, int type)
356 char buffer[4096];
357 if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer)))
358 return_0;
359 outf(f, "status = %s", buffer);
361 if (!print_flags(status, type, buffer, sizeof(buffer)))
362 return_0;
363 outf(f, "flags = %s", buffer);
365 return 1;
368 static int _print_vg(struct formatter *f, struct volume_group *vg)
370 char buffer[4096];
372 if (!id_write_format(&vg->id, buffer, sizeof(buffer)))
373 return_0;
375 outf(f, "id = \"%s\"", buffer);
377 outf(f, "seqno = %u", vg->seqno);
379 if (!_print_flag_config(f, vg->status, VG_FLAGS))
380 return_0;
382 if (!dm_list_empty(&vg->tags)) {
383 if (!print_tags(&vg->tags, buffer, sizeof(buffer)))
384 return_0;
385 outf(f, "tags = %s", buffer);
388 if (vg->system_id && *vg->system_id)
389 outf(f, "system_id = \"%s\"", vg->system_id);
391 if (!out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
392 vg->extent_size))
393 return_0;
394 outf(f, "max_lv = %u", vg->max_lv);
395 outf(f, "max_pv = %u", vg->max_pv);
397 /* Default policy is NORMAL; INHERIT is meaningless */
398 if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
399 outnl(f);
400 outf(f, "allocation_policy = \"%s\"",
401 get_alloc_string(vg->alloc));
404 return 1;
408 * Get the pv%d name from the formatters hash
409 * table.
411 static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid)
413 return dm_hash_lookup(f->pv_names, uuid);
416 static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv)
418 char uuid[64] __attribute((aligned(8)));
420 if (!pv || !id_write_format(&pv->id, uuid, sizeof(uuid)))
421 return_NULL;
423 return _get_pv_name_from_uuid(f, uuid);
426 static int _print_pvs(struct formatter *f, struct volume_group *vg)
428 struct pv_list *pvl;
429 struct physical_volume *pv;
430 char buffer[4096];
431 char *buf;
432 const char *name;
434 outf(f, "physical_volumes {");
435 _inc_indent(f);
437 dm_list_iterate_items(pvl, &vg->pvs) {
438 pv = pvl->pv;
440 if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
441 return_0;
443 if (!(name = _get_pv_name_from_uuid(f, buffer)))
444 return_0;
446 outnl(f);
447 outf(f, "%s {", name);
448 _inc_indent(f);
450 outf(f, "id = \"%s\"", buffer);
452 if (!(buf = alloca(escaped_len(pv_dev_name(pv))))) {
453 log_error("temporary stack allocation for device name"
454 "string failed");
455 return 0;
458 if (!out_hint(f, "device = \"%s\"",
459 escape_double_quotes(buf, pv_dev_name(pv))))
460 return_0;
461 outnl(f);
463 if (!_print_flag_config(f, pv->status, PV_FLAGS))
464 return_0;
466 if (!dm_list_empty(&pv->tags)) {
467 if (!print_tags(&pv->tags, buffer, sizeof(buffer)))
468 return_0;
469 outf(f, "tags = %s", buffer);
472 if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size))
473 return_0;
475 outf(f, "pe_start = %" PRIu64, pv->pe_start);
476 if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
477 "pe_count = %u", pv->pe_count))
478 return_0;
480 _dec_indent(f);
481 outf(f, "}");
484 _dec_indent(f);
485 outf(f, "}");
486 return 1;
489 static int _print_segment(struct formatter *f, struct volume_group *vg,
490 int count, struct lv_segment *seg)
492 char buffer[4096];
494 outf(f, "segment%u {", count);
495 _inc_indent(f);
497 outf(f, "start_extent = %u", seg->le);
498 if (!out_size(f, (uint64_t) seg->len * vg->extent_size,
499 "extent_count = %u", seg->len))
500 return_0;
502 outnl(f);
503 outf(f, "type = \"%s\"", seg->segtype->name);
505 if (!dm_list_empty(&seg->tags)) {
506 if (!print_tags(&seg->tags, buffer, sizeof(buffer)))
507 return_0;
508 outf(f, "tags = %s", buffer);
511 if (seg->segtype->ops->text_export &&
512 !seg->segtype->ops->text_export(seg, f))
513 return_0;
515 _dec_indent(f);
516 outf(f, "}");
518 return 1;
521 int out_areas(struct formatter *f, const struct lv_segment *seg,
522 const char *type)
524 const char *name;
525 unsigned int s;
527 outnl(f);
529 outf(f, "%ss = [", type);
530 _inc_indent(f);
532 for (s = 0; s < seg->area_count; s++) {
533 switch (seg_type(seg, s)) {
534 case AREA_PV:
535 if (!(name = _get_pv_name(f, seg_pv(seg, s))))
536 return_0;
538 outf(f, "\"%s\", %u%s", name,
539 seg_pe(seg, s),
540 (s == seg->area_count - 1) ? "" : ",");
541 break;
542 case AREA_LV:
543 outf(f, "\"%s\", %u%s",
544 seg_lv(seg, s)->name,
545 seg_le(seg, s),
546 (s == seg->area_count - 1) ? "" : ",");
547 break;
548 case AREA_UNASSIGNED:
549 return 0;
553 _dec_indent(f);
554 outf(f, "]");
555 return 1;
558 static int _print_lv(struct formatter *f, struct logical_volume *lv)
560 struct lv_segment *seg;
561 char buffer[4096];
562 int seg_count;
564 outnl(f);
565 outf(f, "%s {", lv->name);
566 _inc_indent(f);
568 /* FIXME: Write full lvid */
569 if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer)))
570 return_0;
572 outf(f, "id = \"%s\"", buffer);
574 if (!_print_flag_config(f, lv->status, LV_FLAGS))
575 return_0;
577 if (!dm_list_empty(&lv->tags)) {
578 if (!print_tags(&lv->tags, buffer, sizeof(buffer)))
579 return_0;
580 outf(f, "tags = %s", buffer);
583 if (lv->alloc != ALLOC_INHERIT)
584 outf(f, "allocation_policy = \"%s\"",
585 get_alloc_string(lv->alloc));
587 switch (lv->read_ahead) {
588 case DM_READ_AHEAD_NONE:
589 _out_comment(f, "# None", "read_ahead = -1");
590 break;
591 case DM_READ_AHEAD_AUTO:
592 /* No output - use default */
593 break;
594 default:
595 outf(f, "read_ahead = %u", lv->read_ahead);
598 if (lv->major >= 0)
599 outf(f, "major = %d", lv->major);
600 if (lv->minor >= 0)
601 outf(f, "minor = %d", lv->minor);
602 outf(f, "segment_count = %u", dm_list_size(&lv->segments));
603 outnl(f);
605 seg_count = 1;
606 dm_list_iterate_items(seg, &lv->segments) {
607 if (!_print_segment(f, lv->vg, seg_count++, seg))
608 return_0;
611 _dec_indent(f);
612 outf(f, "}");
614 return 1;
617 static int _print_lvs(struct formatter *f, struct volume_group *vg)
619 struct lv_list *lvl;
622 * Don't bother with an lv section if there are no lvs.
624 if (dm_list_empty(&vg->lvs))
625 return 1;
627 outf(f, "logical_volumes {");
628 _inc_indent(f);
631 * Write visible LVs first
633 dm_list_iterate_items(lvl, &vg->lvs) {
634 if (!(lv_is_visible(lvl->lv)))
635 continue;
636 if (!_print_lv(f, lvl->lv))
637 return_0;
640 dm_list_iterate_items(lvl, &vg->lvs) {
641 if ((lv_is_visible(lvl->lv)))
642 continue;
643 if (!_print_lv(f, lvl->lv))
644 return_0;
647 _dec_indent(f);
648 outf(f, "}");
650 return 1;
654 * In the text format we refer to pv's as 'pv1',
655 * 'pv2' etc. This function builds a hash table
656 * to enable a quick lookup from device -> name.
658 static int _build_pv_names(struct formatter *f, struct volume_group *vg)
660 int count = 0;
661 struct pv_list *pvl;
662 struct physical_volume *pv;
663 char buffer[32], *uuid, *name;
665 if (!(f->mem = dm_pool_create("text pv_names", 512)))
666 return_0;
668 if (!(f->pv_names = dm_hash_create(128)))
669 return_0;
671 dm_list_iterate_items(pvl, &vg->pvs) {
672 pv = pvl->pv;
674 /* FIXME But skip if there's already an LV called pv%d ! */
675 if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
676 return_0;
678 if (!(name = dm_pool_strdup(f->mem, buffer)))
679 return_0;
681 if (!(uuid = dm_pool_zalloc(f->mem, 64)) ||
682 !id_write_format(&pv->id, uuid, 64))
683 return_0;
685 if (!dm_hash_insert(f->pv_names, uuid, name))
686 return_0;
689 return 1;
692 static int _text_vg_export(struct formatter *f,
693 struct volume_group *vg, const char *desc)
695 int r = 0;
697 if (!_build_pv_names(f, vg))
698 goto_out;
700 if (f->header && !_print_header(f, desc))
701 goto_out;
703 if (!out_text(f, "%s {", vg->name))
704 goto_out;
706 _inc_indent(f);
708 if (!_print_vg(f, vg))
709 goto_out;
711 outnl(f);
712 if (!_print_pvs(f, vg))
713 goto_out;
715 outnl(f);
716 if (!_print_lvs(f, vg))
717 goto_out;
719 _dec_indent(f);
720 if (!out_text(f, "}"))
721 goto_out;
723 if (!f->header && !_print_header(f, desc))
724 goto_out;
726 r = 1;
728 out:
729 if (f->mem)
730 dm_pool_destroy(f->mem);
732 if (f->pv_names)
733 dm_hash_destroy(f->pv_names);
735 return r;
738 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
740 struct formatter *f;
741 int r;
743 _init();
745 if (!(f = dm_malloc(sizeof(*f))))
746 return_0;
748 memset(f, 0, sizeof(*f));
749 f->data.fp = fp;
750 f->indent = 0;
751 f->header = 1;
752 f->out_with_comment = &_out_with_comment_file;
753 f->nl = &_nl_file;
755 r = _text_vg_export(f, vg, desc);
756 if (r)
757 r = !ferror(f->data.fp);
758 dm_free(f);
759 return r;
762 /* Returns amount of buffer used incl. terminating NUL */
763 int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
765 struct formatter *f;
766 int r = 0;
768 _init();
770 if (!(f = dm_malloc(sizeof(*f))))
771 return_0;
773 memset(f, 0, sizeof(*f));
775 f->data.buf.size = 65536; /* Initial metadata limit */
776 if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) {
777 log_error("text_export buffer allocation failed");
778 goto out;
781 f->indent = 0;
782 f->header = 0;
783 f->out_with_comment = &_out_with_comment_raw;
784 f->nl = &_nl_raw;
786 if (!_text_vg_export(f, vg, desc)) {
787 dm_free(f->data.buf.start);
788 goto_out;
791 r = f->data.buf.used + 1;
792 *buf = f->data.buf.start;
794 out:
795 dm_free(f);
796 return r;
799 int export_vg_to_buffer(struct volume_group *vg, char **buf)
801 return text_vg_export_raw(vg, "", buf);
804 #undef outf
805 #undef outnl