1 /* $NetBSD: test.c,v 1.1.1.2 2009/12/02 00:26:03 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 #include <stdio.h> 18 #include <string.h> 19 #include <stdlib.h> 20 #include <readline/readline.h> 21 22 #include "lvm2app.h" 23 24 #define MAX_ARGS 64 25 26 static int lvm_split(char *str, int *argc, char **argv, int max) 27 { 28 char *b = str, *e; 29 *argc = 0; 30 31 while (*b) { 32 while (*b && isspace(*b)) 33 b++; 34 35 if ((!*b) || ((*argc == 0)&&(*b == '#'))) 36 break; 37 38 e = b; 39 while (*e && !isspace(*e)) 40 e++; 41 42 argv[(*argc)++] = b; 43 if (!*e) 44 break; 45 *e++ = '\0'; 46 b = e; 47 if (*argc == max) 48 break; 49 } 50 51 return *argc; 52 } 53 54 static void _show_help(void) 55 { 56 printf("'lv_activate vgname lvname: " 57 "Activate an LV\n"); 58 printf("'lv_deactivate vgname lvname: " 59 "Deactivate an LV\n"); 60 printf("'vg_remove_lv vgname lvname': " 61 "Remove a LV\n"); 62 printf("'vg_create_lv_linear vgname lvname size_in_bytes': " 63 "Create a linear LV\n"); 64 printf("'scan_vgs': " 65 "Scan the system for LVM metadata\n"); 66 printf("'list_vg_names': " 67 "List the names of the VGs that exist in the system\n"); 68 printf("'list_vg_ids': " 69 "List the uuids of the VGs that exist in the system\n"); 70 printf("'vg_list_pvs vgname': " 71 "List the PVs that exist in VG vgname\n"); 72 printf("'vg_list_lvs vgname': " 73 "List the LVs that exist in VG vgname\n"); 74 printf("'vgs_open': " 75 "List the VGs that are currently open\n"); 76 printf("'vgs': " 77 "List all VGs known to the system\n"); 78 printf("'vg_extend vgname device: " 79 "Issue a lvm_vg_extend() API call on VG 'vgname'\n"); 80 printf("'vg_reduce vgname device: " 81 "Issue a lvm_vg_reduce() API call on VG 'vgname'\n"); 82 printf("'vg_open vgname ['r' | 'w']': " 83 "Issue a lvm_vg_open() API call on VG 'vgname'\n"); 84 printf("'vg_close vgname': " 85 "Issue a lvm_vg_close() API call on VG 'vgname'\n"); 86 printf("'vg_create vgname: " 87 "Issue a lvm_vg_create() to create VG 'vgname'\n"); 88 printf("'vg_remove vgname: " 89 "Issue a lvm_vg_remove() to remove VG 'vgname'\n"); 90 printf("'config_reload': " 91 "Issue a lvm_config_reload() API to reload LVM config\n"); 92 printf("'config_override' device: " 93 "Issue a lvm_config_override() with accept device filter\n"); 94 printf("'quit': exit the program\n"); 95 } 96 97 static struct dm_hash_table *_vgid_hash = NULL; 98 static struct dm_hash_table *_vgname_hash = NULL; 99 static struct dm_hash_table *_pvname_hash = NULL; 100 static struct dm_hash_table *_lvname_hash = NULL; 101 102 static void _hash_destroy_single(struct dm_hash_table **htable) 103 { 104 if (htable && *htable) { 105 dm_hash_destroy(*htable); 106 *htable = NULL; 107 } 108 } 109 110 static void _hash_destroy(void) 111 { 112 _hash_destroy_single(&_vgname_hash); 113 _hash_destroy_single(&_vgid_hash); 114 _hash_destroy_single(&_pvname_hash); 115 _hash_destroy_single(&_lvname_hash); 116 } 117 118 static int _hash_create(void) 119 { 120 if (!(_vgname_hash = dm_hash_create(128))) 121 return 0; 122 if (!(_pvname_hash = dm_hash_create(128))) { 123 _hash_destroy_single(&_vgname_hash); 124 return 0; 125 } 126 if (!(_lvname_hash = dm_hash_create(128))) { 127 _hash_destroy_single(&_vgname_hash); 128 _hash_destroy_single(&_pvname_hash); 129 return 0; 130 } 131 if (!(_vgid_hash = dm_hash_create(128))) { 132 _hash_destroy_single(&_vgname_hash); 133 _hash_destroy_single(&_pvname_hash); 134 _hash_destroy_single(&_lvname_hash); 135 return 0; 136 } 137 return 1; 138 } 139 140 /* FIXME: this should be per vg */ 141 static lv_t _lookup_lv_by_name(const char *name) 142 { 143 lv_t lv; 144 145 if (!name) { 146 printf ("Invalid LV name\n"); 147 return NULL; 148 } 149 if (!(lv = dm_hash_lookup(_lvname_hash, name))) { 150 printf ("Can't find %s in LVs - run vg_create_lv first\n", 151 name); 152 return NULL; 153 } 154 return lv; 155 } 156 157 static vg_t _lookup_vg_by_name(char **argv, int argc) 158 { 159 vg_t vg; 160 161 if (argc < 2) { 162 printf ("Please enter vg_name\n"); 163 return NULL; 164 } 165 if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && 166 !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { 167 printf ("Can't find %s in open VGs - run vg_open first\n", 168 argv[1]); 169 return NULL; 170 } 171 return vg; 172 } 173 static void _add_lvs_to_lvname_hash(struct dm_list *lvs) 174 { 175 struct lvm_lv_list *lvl; 176 dm_list_iterate_items(lvl, lvs) { 177 /* Concatenate VG name with LV name */ 178 dm_hash_insert(_lvname_hash, lvm_lv_get_name(lvl->lv), lvl->lv); 179 } 180 } 181 182 static void _add_pvs_to_pvname_hash(struct dm_list *pvs) 183 { 184 struct lvm_pv_list *pvl; 185 dm_list_iterate_items(pvl, pvs) { 186 dm_hash_insert(_pvname_hash, lvm_pv_get_name(pvl->pv), pvl->pv); 187 } 188 } 189 190 static void _remove_device_from_pvname_hash(struct dm_list *pvs, const char *name) 191 { 192 struct lvm_pv_list *pvl; 193 dm_list_iterate_items(pvl, pvs) { 194 if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name))) 195 dm_hash_remove(_pvname_hash, name); 196 } 197 } 198 static void _add_device_to_pvname_hash(struct dm_list *pvs, const char *name) 199 { 200 struct lvm_pv_list *pvl; 201 dm_list_iterate_items(pvl, pvs) { 202 if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name))) 203 dm_hash_insert(_pvname_hash, name, pvl->pv); 204 } 205 } 206 static void _vg_reduce(char **argv, int argc, lvm_t libh) 207 { 208 vg_t vg; 209 struct dm_list *pvs; 210 211 if (argc < 2) { 212 printf ("Please enter vg_name\n"); 213 return; 214 } 215 if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && 216 !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { 217 printf ("VG not open\n"); 218 return; 219 } 220 if (lvm_vg_reduce(vg, argv[2])) { 221 printf("Error reducing %s by %s\n", argv[1], argv[2]); 222 return; 223 } 224 225 printf("Success reducing vg %s by %s\n", argv[1], argv[2]); 226 227 /* 228 * Add the device into the hashes for lookups 229 */ 230 pvs = lvm_vg_list_pvs(vg); 231 if (pvs && !dm_list_empty(pvs)) 232 _remove_device_from_pvname_hash(pvs, argv[2]); 233 } 234 235 /* Print "Error" or "Success" depending on lvm status */ 236 static int _lvm_status_to_pass_fail(int rc) 237 { 238 if (rc) 239 printf("Error "); 240 else 241 printf("Success "); 242 return rc; 243 } 244 static void _config_override(char **argv, int argc, lvm_t libh) 245 { 246 int rc; 247 char tmp[64]; 248 249 if (argc < 2) { 250 printf ("Please enter device\n"); 251 return; 252 } 253 snprintf(tmp, 63, "devices{filter=[\"a|%s|\", \"r|.*|\"]}", argv[1]); 254 rc = lvm_config_override(libh, tmp); 255 _lvm_status_to_pass_fail(rc); 256 printf("overriding LVM configuration\n"); 257 } 258 259 static void _config_reload(char **argv, int argc, lvm_t libh) 260 { 261 int rc; 262 rc = lvm_config_reload(libh); 263 _lvm_status_to_pass_fail(rc); 264 printf("reloading LVM configuration\n"); 265 } 266 267 static void _vg_extend(char **argv, int argc, lvm_t libh) 268 { 269 vg_t vg; 270 struct dm_list *pvs; 271 272 if (argc < 2) { 273 printf ("Please enter vg_name\n"); 274 return; 275 } 276 if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && 277 !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { 278 printf ("VG not open\n"); 279 return; 280 } 281 if (lvm_vg_extend(vg, argv[2])) { 282 printf("Error extending %s with %s\n", argv[1], argv[2]); 283 return; 284 } 285 286 printf("Success extending vg %s with %s\n", argv[1], argv[2]); 287 288 /* 289 * Add the device into the hashes for lookups 290 */ 291 pvs = lvm_vg_list_pvs(vg); 292 if (pvs && !dm_list_empty(pvs)) 293 _add_device_to_pvname_hash(pvs, argv[2]); 294 } 295 296 static void _vg_open(char **argv, int argc, lvm_t libh) 297 { 298 vg_t vg; 299 struct dm_list *lvs; 300 struct dm_list *pvs; 301 302 if (argc < 2) { 303 printf ("Please enter vg_name\n"); 304 return; 305 } 306 if ((vg = dm_hash_lookup(_vgid_hash, argv[1])) || 307 (vg = dm_hash_lookup(_vgname_hash, argv[1]))) { 308 printf ("VG already open\n"); 309 return; 310 } 311 if (argc < 3) 312 vg = lvm_vg_open(libh, argv[1], "r", 0); 313 else 314 vg = lvm_vg_open(libh, argv[1], argv[2], 0); 315 if (!vg || !lvm_vg_get_name(vg)) { 316 printf("Error opening %s\n", argv[1]); 317 return; 318 } 319 320 printf("Success opening vg %s\n", argv[1]); 321 dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg); 322 dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg); 323 324 /* 325 * Add the LVs and PVs into the hashes for lookups 326 */ 327 lvs = lvm_vg_list_lvs(vg); 328 if (lvs && !dm_list_empty(lvs)) 329 _add_lvs_to_lvname_hash(lvs); 330 pvs = lvm_vg_list_pvs(vg); 331 if (pvs && !dm_list_empty(pvs)) 332 _add_pvs_to_pvname_hash(pvs); 333 } 334 /* Lookup the vg and remove it from the vgname and vgid hashes */ 335 static vg_t _lookup_and_remove_vg(const char *vgname) 336 { 337 vg_t vg=NULL; 338 339 if ((vg = dm_hash_lookup(_vgname_hash, vgname))) { 340 dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg)); 341 dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg)); 342 } 343 if (!vg && (vg = dm_hash_lookup(_vgid_hash, vgname))) { 344 dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg)); 345 dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg)); 346 } 347 return vg; 348 } 349 350 static void _vg_write(char **argv, int argc) 351 { 352 vg_t vg; 353 int rc = 0; 354 355 if (argc < 2) { 356 printf ("Please enter vg_name\n"); 357 return; 358 } 359 vg = _lookup_vg_by_name(argv, argc); 360 if (!vg) { 361 printf("Can't find vg_name %s\n", argv[1]); 362 return; 363 } 364 rc = lvm_vg_write(vg); 365 _lvm_status_to_pass_fail(rc); 366 printf("writing VG %s\n", lvm_vg_get_name(vg)); 367 } 368 369 static void _vg_create(char **argv, int argc, lvm_t libh) 370 { 371 vg_t vg; 372 373 if (argc < 2) { 374 printf ("Please enter vg_name\n"); 375 return; 376 } 377 vg = lvm_vg_create(libh, argv[1]); 378 if (!vg || !lvm_vg_get_name(vg)) { 379 printf("Error creating %s\n", argv[1]); 380 return; 381 } 382 383 printf("Success creating vg %s\n", argv[1]); 384 dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg); 385 dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg); 386 } 387 388 static void _vg_remove(char **argv, int argc) 389 { 390 vg_t vg; 391 int rc = 0; 392 393 if (argc < 2) { 394 printf ("Please enter vg_name\n"); 395 return; 396 } 397 vg = _lookup_vg_by_name(argv, argc); 398 if (!vg) { 399 printf("Can't find vg_name %s\n", argv[1]); 400 return; 401 } 402 rc = lvm_vg_remove(vg); 403 _lvm_status_to_pass_fail(rc); 404 printf("removing VG\n"); 405 } 406 407 static void _vg_close(char **argv, int argc) 408 { 409 vg_t vg; 410 int rc = 0; 411 412 if (argc < 2) { 413 printf ("Please enter vg_name\n"); 414 return; 415 } 416 vg = _lookup_and_remove_vg(argv[1]); 417 if (!vg) { 418 printf("Can't find vg_name %s\n", argv[1]); 419 return; 420 } 421 rc = lvm_vg_close(vg); 422 _lvm_status_to_pass_fail(rc); 423 printf("closing VG\n"); 424 } 425 426 static void _show_one_vg(vg_t vg) 427 { 428 printf("%s (%s): sz=%"PRIu64", free=%"PRIu64", #pv=%"PRIu64 429 ", seq#=%"PRIu64"\n", 430 lvm_vg_get_name(vg), lvm_vg_get_uuid(vg), 431 lvm_vg_get_size(vg), lvm_vg_get_free_size(vg), 432 lvm_vg_get_pv_count(vg), lvm_vg_get_seqno(vg)); 433 } 434 435 static void _list_open_vgs(void) 436 { 437 dm_hash_iter(_vgid_hash, (dm_hash_iterate_fn) _show_one_vg); 438 } 439 440 static void _pvs_in_vg(char **argv, int argc) 441 { 442 struct dm_list *pvs; 443 struct lvm_pv_list *pvl; 444 vg_t vg; 445 446 if (!(vg = _lookup_vg_by_name(argv, argc))) 447 return; 448 pvs = lvm_vg_list_pvs(vg); 449 if (!pvs || dm_list_empty(pvs)) { 450 printf("No PVs in VG %s\n", lvm_vg_get_name(vg)); 451 return; 452 } 453 printf("PVs in VG %s:\n", lvm_vg_get_name(vg)); 454 dm_list_iterate_items(pvl, pvs) { 455 printf("%s (%s): mda_count=%"PRIu64"\n", 456 lvm_pv_get_name(pvl->pv), lvm_pv_get_uuid(pvl->pv), 457 lvm_pv_get_mda_count(pvl->pv)); 458 } 459 } 460 461 static void _scan_vgs(lvm_t libh) 462 { 463 lvm_scan(libh); 464 } 465 466 static void _list_vg_names(lvm_t libh) 467 { 468 struct dm_list *list; 469 struct lvm_str_list *strl; 470 const char *tmp; 471 472 list = lvm_list_vg_names(libh); 473 printf("VG names:\n"); 474 dm_list_iterate_items(strl, list) { 475 tmp = strl->str; 476 printf("%s\n", tmp); 477 } 478 } 479 480 static void _list_vg_ids(lvm_t libh) 481 { 482 struct dm_list *list; 483 struct lvm_str_list *strl; 484 const char *tmp; 485 486 list = lvm_list_vg_uuids(libh); 487 printf("VG uuids:\n"); 488 dm_list_iterate_items(strl, list) { 489 tmp = strl->str; 490 printf("%s\n", tmp); 491 } 492 } 493 494 495 static void _lvs_in_vg(char **argv, int argc) 496 { 497 struct dm_list *lvs; 498 struct lvm_lv_list *lvl; 499 vg_t vg; 500 501 if (!(vg = _lookup_vg_by_name(argv, argc))) 502 return; 503 lvs = lvm_vg_list_lvs(vg); 504 if (!lvs || dm_list_empty(lvs)) { 505 printf("No LVs in VG %s\n", lvm_vg_get_name(vg)); 506 return; 507 } 508 printf("LVs in VG %s:\n", lvm_vg_get_name(vg)); 509 dm_list_iterate_items(lvl, lvs) { 510 printf("%s/%s (%s): size=%"PRIu64", %sACTIVE / %sSUSPENDED\n", 511 lvm_vg_get_name(vg), 512 lvm_lv_get_name(lvl->lv), lvm_lv_get_uuid(lvl->lv), 513 lvm_lv_get_size(lvl->lv), 514 lvm_lv_is_active(lvl->lv) ? "" : "IN", 515 lvm_lv_is_suspended(lvl->lv) ? "" : "NOT "); 516 } 517 } 518 519 static void _lv_deactivate(char **argv, int argc) 520 { 521 lv_t lv; 522 int rc=0; 523 524 if (argc < 3) { 525 printf("Please enter vgname, lvname\n"); 526 return; 527 } 528 if (!(lv = _lookup_lv_by_name(argv[2]))) 529 return; 530 rc = lvm_lv_deactivate(lv); 531 _lvm_status_to_pass_fail(rc); 532 printf("De-activating LV %s in VG %s\n", 533 argv[2], argv[1]); 534 } 535 static void _lv_activate(char **argv, int argc) 536 { 537 lv_t lv; 538 int rc=0; 539 540 if (argc < 3) { 541 printf("Please enter vgname, lvname\n"); 542 return; 543 } 544 if (!(lv = _lookup_lv_by_name(argv[2]))) 545 return; 546 rc = lvm_lv_activate(lv); 547 _lvm_status_to_pass_fail(rc); 548 printf("activating LV %s in VG %s\n", 549 argv[2], argv[1]); 550 } 551 static void _vg_remove_lv(char **argv, int argc) 552 { 553 lv_t lv; 554 555 if (argc < 3) { 556 printf("Please enter vgname, lvname\n"); 557 return; 558 } 559 if (!(lv = _lookup_lv_by_name(argv[2]))) 560 return; 561 if (lvm_vg_remove_lv(lv)) 562 printf("Error "); 563 else { 564 printf("Success "); 565 dm_hash_remove(_lvname_hash, argv[2]); 566 } 567 printf("removing LV %s in VG %s\n", 568 argv[2], argv[1]); 569 } 570 571 static void _vg_create_lv_linear(char **argv, int argc) 572 { 573 vg_t vg; 574 lv_t lv; 575 576 if (argc < 4) { 577 printf("Please enter vgname, lvname, and size\n"); 578 return; 579 } 580 if (!(vg = _lookup_vg_by_name(argv, argc))) 581 return; 582 lv = lvm_vg_create_lv_linear(vg, argv[2], atol(argv[3])); 583 if (!lv) 584 printf("Error "); 585 else { 586 printf("Success "); 587 dm_hash_insert(_lvname_hash, argv[2], lv); 588 } 589 printf("creating LV %s in VG %s\n", 590 argv[2], argv[1]); 591 } 592 593 static int lvmapi_test_shell(lvm_t libh) 594 { 595 int argc; 596 char *input = NULL, *args[MAX_ARGS], **argv; 597 598 _hash_create(); 599 argc=0; 600 while (1) { 601 free(input); 602 input = readline("liblvm> "); 603 604 /* EOF */ 605 if (!input) { 606 printf("\n"); 607 break; 608 } 609 610 /* empty line */ 611 if (!*input) 612 continue; 613 614 argv = args; 615 616 if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { 617 printf("Too many arguments, sorry."); 618 continue; 619 } 620 621 if (!strcmp(argv[0], "lvm")) { 622 argv++; 623 argc--; 624 } 625 626 if (!argc) 627 continue; 628 629 if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) { 630 printf("Exiting.\n"); 631 break; 632 } else if (!strcmp(argv[0], "?") || !strcmp(argv[0], "help")) { 633 _show_help(); 634 } else if (!strcmp(argv[0], "config_reload")) { 635 _config_reload(argv, argc, libh); 636 } else if (!strcmp(argv[0], "config_override")) { 637 _config_override(argv, argc, libh); 638 } else if (!strcmp(argv[0], "vg_extend")) { 639 _vg_extend(argv, argc, libh); 640 } else if (!strcmp(argv[0], "vg_reduce")) { 641 _vg_reduce(argv, argc, libh); 642 } else if (!strcmp(argv[0], "vg_write")) { 643 _vg_write(argv, argc); 644 } else if (!strcmp(argv[0], "vg_open")) { 645 _vg_open(argv, argc, libh); 646 } else if (!strcmp(argv[0], "vg_close")) { 647 _vg_close(argv, argc); 648 } else if (!strcmp(argv[0], "vg_create")) { 649 _vg_create(argv, argc, libh); 650 } else if (!strcmp(argv[0], "vg_remove")) { 651 _vg_remove(argv, argc); 652 } else if (!strcmp(argv[0], "lv_activate")) { 653 _lv_activate(argv, argc); 654 } else if (!strcmp(argv[0], "lv_deactivate")) { 655 _lv_deactivate(argv, argc); 656 } else if (!strcmp(argv[0], "vg_remove_lv")) { 657 _vg_remove_lv(argv, argc); 658 } else if (!strcmp(argv[0], "vgs_open")) { 659 _list_open_vgs(); 660 } else if (!strcmp(argv[0], "vg_list_pvs")) { 661 _pvs_in_vg(argv, argc); 662 } else if (!strcmp(argv[0], "vg_list_lvs")) { 663 _lvs_in_vg(argv, argc); 664 } else if (!strcmp(argv[0], "list_vg_names")) { 665 _list_vg_names(libh); 666 } else if (!strcmp(argv[0], "list_vg_ids")) { 667 _list_vg_ids(libh); 668 } else if (!strcmp(argv[0], "scan_vgs")) { 669 _scan_vgs(libh); 670 } else if (!strcmp(argv[0], "vg_create_lv_linear")) { 671 _vg_create_lv_linear(argv, argc); 672 } else { 673 printf ("Unrecognized command %s\n", argv[0]); 674 } 675 } 676 677 dm_hash_iter(_vgname_hash, (dm_hash_iterate_fn) lvm_vg_close); 678 _hash_destroy(); 679 free(input); 680 return 0; 681 } 682 683 int main (int argc, char *argv[]) 684 { 685 lvm_t libh; 686 687 libh = lvm_init(NULL); 688 if (!libh) { 689 printf("Unable to open lvm library instance\n"); 690 return 1; 691 } 692 693 printf("Library version: %s\n", lvm_library_get_version()); 694 lvmapi_test_shell(libh); 695 696 lvm_quit(libh); 697 return 0; 698 } 699 700