1 /* $NetBSD: export.c,v 1.1.1.3 2009/12/02 00:26:29 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2009 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 "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" 26 27 #include <stdarg.h> 28 #include <time.h> 29 #include <sys/utsname.h> 30 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); 35 36 /* 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. 40 */ 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) 47 48 /* 49 * The first half of this file deals with 50 * exporting the vg, ie. writing it to a file. 51 */ 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) */ 55 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; 64 65 out_with_comment_fn out_with_comment; 66 nl_fn nl; 67 68 int indent; /* current level of indentation */ 69 int error; 70 int header; /* 1 => comments at start; 0 => end */ 71 }; 72 73 static struct utsname _utsname; 74 75 static void _init(void) 76 { 77 static int _initialised = 0; 78 79 if (_initialised) 80 return; 81 82 if (uname(&_utsname)) { 83 log_error("uname failed: %s", strerror(errno)); 84 memset(&_utsname, 0, sizeof(_utsname)); 85 } 86 87 _initialised = 1; 88 } 89 90 /* 91 * Formatting functions. 92 */ 93 94 #define MAX_INDENT 5 95 static void _inc_indent(struct formatter *f) 96 { 97 if (++f->indent > MAX_INDENT) 98 f->indent = MAX_INDENT; 99 } 100 101 static void _dec_indent(struct formatter *f) 102 { 103 if (!f->indent--) { 104 log_error("Internal error tracking indentation"); 105 f->indent = 0; 106 } 107 } 108 109 /* 110 * Newline function for prettier layout. 111 */ 112 static int _nl_file(struct formatter *f) 113 { 114 fprintf(f->data.fp, "\n"); 115 116 return 1; 117 } 118 119 static int _extend_buffer(struct formatter *f) 120 { 121 char *newbuf; 122 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; 129 } 130 f->data.buf.start = newbuf; 131 f->data.buf.size *= 2; 132 133 return 1; 134 } 135 136 static int _nl_raw(struct formatter *f) 137 { 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; 142 143 *(f->data.buf.start + f->data.buf.used) = '\n'; 144 f->data.buf.used += 1; 145 146 *(f->data.buf.start + f->data.buf.used) = '\0'; 147 148 return 1; 149 } 150 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) 154 { 155 int i; 156 char white_space[MAX_INDENT + 1]; 157 158 if (ferror(f->data.fp)) 159 return 0; 160 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); 166 167 if (comment) { 168 /* 169 * line comments up if possible. 170 */ 171 i += 8 * f->indent; 172 i /= 8; 173 i++; 174 175 do 176 fputc('\t', f->data.fp); 177 178 while (++i < COMMENT_TAB); 179 180 fputs(comment, f->data.fp); 181 } 182 fputc('\n', f->data.fp); 183 184 return 1; 185 } 186 187 static int _out_with_comment_raw(struct formatter *f, 188 const char *comment __attribute((unused)), 189 const char *fmt, va_list ap) 190 { 191 int n; 192 193 n = vsnprintf(f->data.buf.start + f->data.buf.used, 194 f->data.buf.size - f->data.buf.used, fmt, ap); 195 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 */ 201 } 202 203 f->data.buf.used += n; 204 205 outnl(f); 206 207 return 1; 208 } 209 210 /* 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. 215 */ 216 static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s) 217 { 218 static const char *_units[] = { 219 "Kilobytes", 220 "Megabytes", 221 "Gigabytes", 222 "Terabytes", 223 "Petabytes", 224 "Exabytes", 225 NULL 226 }; 227 228 int i; 229 double d = (double) sectors; 230 231 /* to convert to K */ 232 d /= 2.0; 233 234 for (i = 0; (d > 1024.0) && _units[i]; i++) 235 d /= 1024.0; 236 237 return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0; 238 } 239 240 /* increment indention level */ 241 void out_inc_indent(struct formatter *f) 242 { 243 _inc_indent(f); 244 } 245 246 /* decrement indention level */ 247 void out_dec_indent(struct formatter *f) 248 { 249 _dec_indent(f); 250 } 251 252 /* insert new line */ 253 int out_newline(struct formatter *f) 254 { 255 return f->nl(f); 256 } 257 258 /* 259 * Appends a comment giving a size in more easily 260 * readable form (eg, 4M instead of 8096). 261 */ 262 int out_size(struct formatter *f, uint64_t size, const char *fmt, ...) 263 { 264 char buffer[64]; 265 va_list ap; 266 int r; 267 268 if (!_sectors_to_units(size, buffer, sizeof(buffer))) 269 return 0; 270 271 _out_with_comment(f, buffer, fmt, ap); 272 273 return r; 274 } 275 276 /* 277 * Appends a comment indicating that the line is 278 * only a hint. 279 */ 280 int out_hint(struct formatter *f, const char *fmt, ...) 281 { 282 va_list ap; 283 int r; 284 285 _out_with_comment(f, "# Hint only", fmt, ap); 286 287 return r; 288 } 289 290 /* 291 * Appends a comment 292 */ 293 static int _out_comment(struct formatter *f, const char *comment, const char *fmt, ...) 294 { 295 va_list ap; 296 int r; 297 298 _out_with_comment(f, comment, fmt, ap); 299 300 return r; 301 } 302 303 /* 304 * The normal output function. 305 */ 306 int out_text(struct formatter *f, const char *fmt, ...) 307 { 308 va_list ap; 309 int r; 310 311 _out_with_comment(f, NULL, fmt, ap); 312 313 return r; 314 } 315 316 static int _out_line(const char *line, void *_f) { 317 struct formatter *f = (struct formatter *) _f; 318 return out_text(f, "%s", line); 319 } 320 321 int out_config_node(struct formatter *f, const struct config_node *cn) 322 { 323 return write_config_node(cn, _out_line, f); 324 } 325 326 static int _print_header(struct formatter *f, 327 const char *desc) 328 { 329 char *buf; 330 time_t t; 331 332 t = time(NULL); 333 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); 338 339 if (!(buf = alloca(escaped_len(desc)))) { 340 log_error("temporary stack allocation for description" 341 "string failed"); 342 return 0; 343 } 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)); 350 351 return 1; 352 } 353 354 static int _print_flag_config(struct formatter *f, int status, int type) 355 { 356 char buffer[4096]; 357 if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer))) 358 return_0; 359 outf(f, "status = %s", buffer); 360 361 if (!print_flags(status, type, buffer, sizeof(buffer))) 362 return_0; 363 outf(f, "flags = %s", buffer); 364 365 return 1; 366 } 367 368 static int _print_vg(struct formatter *f, struct volume_group *vg) 369 { 370 char buffer[4096]; 371 372 if (!id_write_format(&vg->id, buffer, sizeof(buffer))) 373 return_0; 374 375 outf(f, "id = \"%s\"", buffer); 376 377 outf(f, "seqno = %u", vg->seqno); 378 379 if (!_print_flag_config(f, vg->status, VG_FLAGS)) 380 return_0; 381 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); 386 } 387 388 if (vg->system_id && *vg->system_id) 389 outf(f, "system_id = \"%s\"", vg->system_id); 390 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); 396 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)); 402 } 403 404 return 1; 405 } 406 407 /* 408 * Get the pv%d name from the formatters hash 409 * table. 410 */ 411 static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid) 412 { 413 return dm_hash_lookup(f->pv_names, uuid); 414 } 415 416 static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv) 417 { 418 char uuid[64] __attribute((aligned(8))); 419 420 if (!pv || !id_write_format(&pv->id, uuid, sizeof(uuid))) 421 return_NULL; 422 423 return _get_pv_name_from_uuid(f, uuid); 424 } 425 426 static int _print_pvs(struct formatter *f, struct volume_group *vg) 427 { 428 struct pv_list *pvl; 429 struct physical_volume *pv; 430 char buffer[4096]; 431 char *buf; 432 const char *name; 433 434 outf(f, "physical_volumes {"); 435 _inc_indent(f); 436 437 dm_list_iterate_items(pvl, &vg->pvs) { 438 pv = pvl->pv; 439 440 if (!id_write_format(&pv->id, buffer, sizeof(buffer))) 441 return_0; 442 443 if (!(name = _get_pv_name_from_uuid(f, buffer))) 444 return_0; 445 446 outnl(f); 447 outf(f, "%s {", name); 448 _inc_indent(f); 449 450 outf(f, "id = \"%s\"", buffer); 451 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; 456 } 457 458 if (!out_hint(f, "device = \"%s\"", 459 escape_double_quotes(buf, pv_dev_name(pv)))) 460 return_0; 461 outnl(f); 462 463 if (!_print_flag_config(f, pv->status, PV_FLAGS)) 464 return_0; 465 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); 470 } 471 472 if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) 473 return_0; 474 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; 479 480 _dec_indent(f); 481 outf(f, "}"); 482 } 483 484 _dec_indent(f); 485 outf(f, "}"); 486 return 1; 487 } 488 489 static int _print_segment(struct formatter *f, struct volume_group *vg, 490 int count, struct lv_segment *seg) 491 { 492 char buffer[4096]; 493 494 outf(f, "segment%u {", count); 495 _inc_indent(f); 496 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; 501 502 outnl(f); 503 outf(f, "type = \"%s\"", seg->segtype->name); 504 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); 509 } 510 511 if (seg->segtype->ops->text_export && 512 !seg->segtype->ops->text_export(seg, f)) 513 return_0; 514 515 _dec_indent(f); 516 outf(f, "}"); 517 518 return 1; 519 } 520 521 int out_areas(struct formatter *f, const struct lv_segment *seg, 522 const char *type) 523 { 524 const char *name; 525 unsigned int s; 526 527 outnl(f); 528 529 outf(f, "%ss = [", type); 530 _inc_indent(f); 531 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; 537 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; 550 } 551 } 552 553 _dec_indent(f); 554 outf(f, "]"); 555 return 1; 556 } 557 558 static int _print_lv(struct formatter *f, struct logical_volume *lv) 559 { 560 struct lv_segment *seg; 561 char buffer[4096]; 562 int seg_count; 563 564 outnl(f); 565 outf(f, "%s {", lv->name); 566 _inc_indent(f); 567 568 /* FIXME: Write full lvid */ 569 if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) 570 return_0; 571 572 outf(f, "id = \"%s\"", buffer); 573 574 if (!_print_flag_config(f, lv->status, LV_FLAGS)) 575 return_0; 576 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); 581 } 582 583 if (lv->alloc != ALLOC_INHERIT) 584 outf(f, "allocation_policy = \"%s\"", 585 get_alloc_string(lv->alloc)); 586 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); 596 } 597 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); 604 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; 609 } 610 611 _dec_indent(f); 612 outf(f, "}"); 613 614 return 1; 615 } 616 617 static int _print_lvs(struct formatter *f, struct volume_group *vg) 618 { 619 struct lv_list *lvl; 620 621 /* 622 * Don't bother with an lv section if there are no lvs. 623 */ 624 if (dm_list_empty(&vg->lvs)) 625 return 1; 626 627 outf(f, "logical_volumes {"); 628 _inc_indent(f); 629 630 /* 631 * Write visible LVs first 632 */ 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; 638 } 639 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; 645 } 646 647 _dec_indent(f); 648 outf(f, "}"); 649 650 return 1; 651 } 652 653 /* 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. 657 */ 658 static int _build_pv_names(struct formatter *f, struct volume_group *vg) 659 { 660 int count = 0; 661 struct pv_list *pvl; 662 struct physical_volume *pv; 663 char buffer[32], *uuid, *name; 664 665 if (!(f->mem = dm_pool_create("text pv_names", 512))) 666 return_0; 667 668 if (!(f->pv_names = dm_hash_create(128))) 669 return_0; 670 671 dm_list_iterate_items(pvl, &vg->pvs) { 672 pv = pvl->pv; 673 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; 677 678 if (!(name = dm_pool_strdup(f->mem, buffer))) 679 return_0; 680 681 if (!(uuid = dm_pool_zalloc(f->mem, 64)) || 682 !id_write_format(&pv->id, uuid, 64)) 683 return_0; 684 685 if (!dm_hash_insert(f->pv_names, uuid, name)) 686 return_0; 687 } 688 689 return 1; 690 } 691 692 static int _text_vg_export(struct formatter *f, 693 struct volume_group *vg, const char *desc) 694 { 695 int r = 0; 696 697 if (!_build_pv_names(f, vg)) 698 goto_out; 699 700 if (f->header && !_print_header(f, desc)) 701 goto_out; 702 703 if (!out_text(f, "%s {", vg->name)) 704 goto_out; 705 706 _inc_indent(f); 707 708 if (!_print_vg(f, vg)) 709 goto_out; 710 711 outnl(f); 712 if (!_print_pvs(f, vg)) 713 goto_out; 714 715 outnl(f); 716 if (!_print_lvs(f, vg)) 717 goto_out; 718 719 _dec_indent(f); 720 if (!out_text(f, "}")) 721 goto_out; 722 723 if (!f->header && !_print_header(f, desc)) 724 goto_out; 725 726 r = 1; 727 728 out: 729 if (f->mem) 730 dm_pool_destroy(f->mem); 731 732 if (f->pv_names) 733 dm_hash_destroy(f->pv_names); 734 735 return r; 736 } 737 738 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp) 739 { 740 struct formatter *f; 741 int r; 742 743 _init(); 744 745 if (!(f = dm_malloc(sizeof(*f)))) 746 return_0; 747 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; 754 755 r = _text_vg_export(f, vg, desc); 756 if (r) 757 r = !ferror(f->data.fp); 758 dm_free(f); 759 return r; 760 } 761 762 /* Returns amount of buffer used incl. terminating NUL */ 763 int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf) 764 { 765 struct formatter *f; 766 int r = 0; 767 768 _init(); 769 770 if (!(f = dm_malloc(sizeof(*f)))) 771 return_0; 772 773 memset(f, 0, sizeof(*f)); 774 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; 779 } 780 781 f->indent = 0; 782 f->header = 0; 783 f->out_with_comment = &_out_with_comment_raw; 784 f->nl = &_nl_raw; 785 786 if (!_text_vg_export(f, vg, desc)) { 787 dm_free(f->data.buf.start); 788 goto_out; 789 } 790 791 r = f->data.buf.used + 1; 792 *buf = f->data.buf.start; 793 794 out: 795 dm_free(f); 796 return r; 797 } 798 799 int export_vg_to_buffer(struct volume_group *vg, char **buf) 800 { 801 return text_vg_export_raw(vg, "", buf); 802 } 803 804 #undef outf 805 #undef outnl 806