1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 28 */ 29 30 /* 31 * System includes 32 */ 33 34 #include <assert.h> 35 #include <stdio.h> 36 #include <strings.h> 37 #include <libzfs.h> 38 #include <locale.h> 39 #include <langinfo.h> 40 #include <stdlib.h> 41 #include <wchar.h> 42 #include <sys/types.h> 43 44 #include "libbe.h" 45 46 #ifndef lint 47 #define _(x) gettext(x) 48 #else 49 #define _(x) (x) 50 #endif 51 52 #ifndef TEXT_DOMAIN 53 #define TEXT_DOMAIN "SYS_TEST" 54 #endif 55 56 #define DT_BUF_LEN (128) 57 #define NUM_COLS (6) 58 59 static int be_do_activate(int argc, char **argv); 60 static int be_do_create(int argc, char **argv); 61 static int be_do_create_snapshot(int argc, char **argv); 62 static int be_do_destroy(int argc, char **argv); 63 static int be_do_destroy_snapshot(int argc, char **argv); 64 static int be_do_list(int argc, char **argv); 65 static int be_do_mount(int argc, char **argv); 66 static int be_do_unmount(int argc, char **argv); 67 static int be_do_rename(int argc, char **argv); 68 static int be_do_rollback(int argc, char **argv); 69 static void usage(void); 70 71 /* 72 * single column name/width output format description 73 */ 74 struct col_info { 75 const char *col_name; 76 size_t width; 77 }; 78 79 /* 80 * all columns output format 81 */ 82 struct hdr_info { 83 struct col_info cols[NUM_COLS]; 84 }; 85 86 /* 87 * type of possible output formats 88 */ 89 enum be_fmt { 90 BE_FMT_DEFAULT, 91 BE_FMT_DATASET, 92 BE_FMT_SNAPSHOT, 93 BE_FMT_ALL, 94 BE_NUM_FMTS 95 }; 96 97 /* 98 * command id 99 */ 100 enum be_cmd { 101 BE_CMD_ACTIVATE, 102 BE_CMD_CREATE, 103 BE_CMD_CREATE_SNAP, 104 BE_CMD_DESTROY, 105 BE_CMD_DESTROY_SNAP, 106 BE_CMD_LIST, 107 BE_CMD_MOUNT, 108 BE_CMD_UNMOUNT, 109 BE_CMD_RENAME, 110 BE_CMD_ROLLBACK, 111 112 BE_NUM_COMMANDS 113 }; 114 115 /* 116 * command handler description 117 */ 118 typedef struct be_command { 119 const char *name; 120 int (*func)(int argc, char **argv); 121 } be_command_t; 122 123 /* 124 * sorted list of be commands 125 */ 126 static const be_command_t be_command_tbl[BE_NUM_COMMANDS] = { 127 { "activate", be_do_activate }, 128 { "create", be_do_create }, 129 { "create_snap", be_do_create_snapshot }, 130 { "destroy", be_do_destroy }, 131 { "destroy_snap", be_do_destroy_snapshot }, 132 { "list", be_do_list }, 133 { "mount", be_do_mount }, 134 { "unmount", be_do_unmount }, 135 { "rename", be_do_rename }, 136 { "rollback", be_do_rollback }, 137 }; 138 139 static struct hdr_info hdrs[BE_NUM_FMTS] = { 0 }; 140 141 static void 142 usage(void) 143 { 144 (void) fprintf(stderr, _("usage:\n" 145 "\tbeadm subcommand cmd_options\n" 146 "\n" 147 "\tsubcommands:\n" 148 "\n" 149 "\tbeadm create [-d BE_desc]\n" 150 "\t\t[-o property=value] ... [-p zpool] \n" 151 "\t\t[-e nonActiveBe | beName@snapshot] beName\n" 152 "\tbeadm create [-d BE_desc]\n" 153 "\t\t[-o property=value] ... [-p zpool] beName@snapshot\n" 154 "\tbeadm create_snap [-p policy] beName [snapshot]\n" 155 "\tbeadm destroy [-Ffs] beName \n" 156 "\tbeadm destroy [-F] beName@snapshot \n" 157 "\tbeadm destroy_snap beName snapshot\n" 158 "\tbeadm list [[-a] | [-d] [-s]] [-H] [beName]\n" 159 "\tbeadm mount [-s ro|rw] beName [mountpoint]\n" 160 "\tbeadm unmount [-f] beName\n" 161 "\tbeadm rename origBeName newBeName\n" 162 "\tbeadm rollback beName snapshot\n" 163 "\tbeadm rollback beName@snapshot\n")); 164 } 165 166 static int 167 run_be_cmd(const char *cmdname, int argc, char **argv) 168 { 169 int cmd; 170 for (cmd = 0; cmd < BE_NUM_COMMANDS; cmd++) { 171 const be_command_t *command = &be_command_tbl[cmd]; 172 if (strcmp(command->name, cmdname) == 0) 173 return (command->func(argc, argv)); 174 } 175 176 (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname); 177 usage(); 178 return (1); 179 } 180 181 int 182 main(int argc, char **argv) 183 { 184 const char *cmdname; 185 186 (void) setlocale(LC_ALL, ""); 187 (void) textdomain(TEXT_DOMAIN); 188 189 if (argc < 2) { 190 usage(); 191 return (1); 192 } 193 194 cmdname = argv[1]; 195 196 /* Turn error printing off */ 197 libbe_print_errors(B_FALSE); 198 199 return (run_be_cmd(cmdname, --argc, ++argv)); 200 } 201 202 static void 203 print_hdr(struct hdr_info *hdr_info) 204 { 205 boolean_t first = B_TRUE; 206 size_t i; 207 for (i = 0; i < NUM_COLS; i++) { 208 struct col_info *col_info = &hdr_info->cols[i]; 209 const char *name = col_info->col_name; 210 size_t width = col_info->width; 211 if (name == NULL) 212 continue; 213 214 if (first) { 215 (void) printf("%-*s", width, name); 216 first = B_FALSE; 217 } else 218 (void) printf(" %-*s", width, name); 219 } 220 (void) putchar('\n'); 221 } 222 223 static void 224 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr) 225 { 226 struct col_info *col = hdr->cols; 227 size_t i; 228 229 col[1].col_name = _("Active"); 230 col[2].col_name = _("Mountpoint"); 231 col[3].col_name = _("Space"); 232 col[4].col_name = _("Policy"); 233 col[5].col_name = _("Created"); 234 col[6].col_name = NULL; 235 236 switch (be_fmt) { 237 case BE_FMT_ALL: 238 col[0].col_name = _("BE/Dataset/Snapshot"); 239 break; 240 case BE_FMT_DATASET: 241 col[0].col_name = _("BE/Dataset"); 242 break; 243 case BE_FMT_SNAPSHOT: 244 col[0].col_name = _("BE/Snapshot"); 245 col[1].col_name = NULL; 246 col[2].col_name = NULL; 247 break; 248 case BE_FMT_DEFAULT: 249 default: 250 col[0].col_name = _("BE"); 251 } 252 253 for (i = 0; i < NUM_COLS; i++) { 254 const char *name = col[i].col_name; 255 col[i].width = 0; 256 257 if (name != NULL) { 258 wchar_t wname[128]; 259 size_t sz = mbstowcs(wname, name, sizeof (wname) / 260 sizeof (wchar_t)); 261 if (sz > 0) 262 col[i].width = wcswidth(wname, sz); 263 } 264 } 265 } 266 267 static void 268 nicenum(uint64_t num, char *buf, size_t buflen) 269 { 270 uint64_t n = num; 271 int index = 0; 272 char u; 273 274 while (n >= 1024) { 275 n /= 1024; 276 index++; 277 } 278 279 u = " KMGTPE"[index]; 280 281 if (index == 0) { 282 (void) snprintf(buf, buflen, "%llu", n); 283 } else { 284 int i; 285 for (i = 2; i >= 0; i--) { 286 if (snprintf(buf, buflen, "%.*f%c", i, 287 (double)num / (1ULL << 10 * index), u) <= 5) 288 break; 289 } 290 } 291 } 292 293 static void 294 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes) 295 { 296 size_t len[NUM_COLS]; 297 char buf[DT_BUF_LEN]; 298 int i; 299 be_node_list_t *cur_be; 300 301 for (i = 0; i < NUM_COLS; i++) 302 len[i] = hdr->cols[i].width; 303 304 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 305 char name[ZFS_MAXNAMELEN+1]; 306 const char *be_name = cur_be->be_node_name; 307 const char *root_ds = cur_be->be_root_ds; 308 char *pos; 309 size_t node_name_len = strlen(cur_be->be_node_name); 310 size_t root_ds_len = strlen(cur_be->be_root_ds); 311 size_t mntpt_len = strlen(cur_be->be_mntpt); 312 size_t policy_len = strlen(cur_be->be_policy_type); 313 size_t used_len; 314 315 uint64_t used = cur_be->be_space_used; 316 be_snapshot_list_t *snap = NULL; 317 318 (void) strncpy(name, root_ds, sizeof (name)); 319 pos = strstr(name, be_name); 320 321 if (be_fmt == BE_FMT_DEFAULT) { 322 if (node_name_len > len[0]) 323 len[0] = node_name_len; 324 } else { 325 if (root_ds_len + 3 > len[0]) 326 len[0] = root_ds_len + 3; 327 } 328 329 if (mntpt_len > len[2]) 330 len[2] = mntpt_len; 331 if (policy_len > len[4]) 332 len[4] = policy_len; 333 334 for (snap = cur_be->be_node_snapshots; snap != NULL; 335 snap = snap->be_next_snapshot) { 336 uint64_t snap_used = snap->be_snapshot_space_used; 337 const char *snap_name = snap->be_snapshot_name; 338 (void) strcpy(pos, snap_name); 339 340 if (be_fmt == BE_FMT_DEFAULT) 341 used += snap_used; 342 else if (be_fmt & BE_FMT_SNAPSHOT) { 343 int snap_len = strlen(name) + 3; 344 if (be_fmt == BE_FMT_SNAPSHOT) 345 snap_len -= pos - name; 346 if (snap_len > len[0]) 347 len[0] = snap_len; 348 nicenum(snap_used, buf, sizeof (buf)); 349 used_len = strlen(buf); 350 if (used_len > len[3]) 351 len[3] = used_len; 352 } 353 } 354 355 if (be_fmt == BE_FMT_DEFAULT) { 356 int used_len; 357 nicenum(used, buf, sizeof (buf)); 358 used_len = strlen(buf); 359 if (used_len > len[3]) 360 len[3] = used_len; 361 } 362 363 nicenum(used, buf, sizeof (buf)); 364 } 365 366 for (i = 0; i < NUM_COLS; i++) 367 hdr->cols[i].width = len[i]; 368 } 369 370 static void 371 print_be_nodes(const char *be_name, boolean_t parsable, be_node_list_t *nodes) 372 { 373 char buf[64]; 374 char datetime[DT_BUF_LEN]; 375 struct hdr_info *hdr = NULL; 376 enum be_fmt be_fmt = BE_FMT_DEFAULT; 377 be_node_list_t *cur_be; 378 379 if (!parsable) { 380 hdr = hdrs; 381 init_hdr_cols(be_fmt, hdr); 382 count_widths(be_fmt, hdr, nodes); 383 print_hdr(hdr); 384 } 385 386 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 387 char active[3] = "-\0"; 388 int ai = 0; 389 const char *datetime_fmt = "%F %R"; 390 const char *name = cur_be->be_node_name; 391 const char *mntpt = cur_be->be_mntpt; 392 be_snapshot_list_t *snap = NULL; 393 uint64_t used = cur_be->be_space_used; 394 time_t creation = cur_be->be_node_creation; 395 struct tm *tm; 396 397 if (be_name != NULL && strcmp(be_name, name) != 0) 398 continue; 399 400 if (parsable) 401 active[0] = '\0'; 402 403 tm = localtime(&creation); 404 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 405 406 for (snap = cur_be->be_node_snapshots; snap != NULL; 407 snap = snap->be_next_snapshot) 408 used += snap->be_snapshot_space_used; 409 410 if (cur_be->be_active) 411 active[ai++] = 'N'; 412 if (cur_be->be_active_on_boot) 413 active[ai] = 'R'; 414 415 nicenum(used, buf, sizeof (buf)); 416 if (parsable) 417 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 418 name, 419 cur_be->be_uuid_str, 420 active, 421 (cur_be->be_mounted ? mntpt: ""), 422 used, 423 cur_be->be_policy_type, 424 creation); 425 else 426 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n", 427 hdr->cols[0].width, name, 428 hdr->cols[1].width, active, 429 hdr->cols[2].width, (cur_be->be_mounted ? mntpt: 430 "-"), 431 hdr->cols[3].width, buf, 432 hdr->cols[4].width, cur_be->be_policy_type, 433 hdr->cols[5].width, datetime); 434 } 435 } 436 437 static void 438 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable) 439 { 440 char buf[64]; 441 char datetime[DT_BUF_LEN]; 442 be_snapshot_list_t *snap = NULL; 443 444 for (snap = be->be_node_snapshots; snap != NULL; 445 snap = snap->be_next_snapshot) { 446 char name[ZFS_MAXNAMELEN+1]; 447 const char *datetime_fmt = "%F %R"; 448 const char *be_name = be->be_node_name; 449 const char *root_ds = be->be_root_ds; 450 const char *snap_name = snap->be_snapshot_name; 451 char *pos; 452 uint64_t used = snap->be_snapshot_space_used; 453 time_t creation = snap->be_snapshot_creation; 454 struct tm *tm = localtime(&creation); 455 456 (void) strncpy(name, root_ds, sizeof (name)); 457 pos = strstr(name, be_name); 458 (void) strcpy(pos, snap_name); 459 460 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 461 nicenum(used, buf, sizeof (buf)); 462 463 if (parsable) 464 if (hdr->cols[1].width != 0) 465 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 466 be_name, 467 snap_name, 468 "", 469 "", 470 used, 471 be->be_policy_type, 472 creation); 473 else 474 (void) printf("%s;%s;%llu;%s;%ld\n", 475 be_name, 476 snap_name, 477 used, 478 be->be_policy_type, 479 creation); 480 else 481 if (hdr->cols[1].width != 0) 482 (void) printf(" %-*s %-*s %-*s %-*s %-*s " 483 "%-*s\n", 484 hdr->cols[0].width-3, name, 485 hdr->cols[1].width, "-", 486 hdr->cols[2].width, "-", 487 hdr->cols[3].width, buf, 488 hdr->cols[4].width, be->be_policy_type, 489 hdr->cols[5].width, datetime); 490 else 491 (void) printf(" %-*s %-*s %-*s %-*s\n", 492 hdr->cols[0].width-3, snap_name, 493 hdr->cols[3].width, buf, 494 hdr->cols[4].width, be->be_policy_type, 495 hdr->cols[5].width, datetime); 496 } 497 } 498 499 static void 500 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable, 501 be_node_list_t *nodes) 502 { 503 char buf[64]; 504 char datetime[DT_BUF_LEN]; 505 struct hdr_info *hdr = NULL; 506 be_node_list_t *cur_be; 507 508 if (!parsable) { 509 hdr = hdrs + be_fmt; 510 init_hdr_cols(be_fmt, hdr); 511 count_widths(be_fmt, hdr, nodes); 512 print_hdr(hdr); 513 } 514 515 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 516 char active[3] = "-\0"; 517 int ai = 0; 518 const char *datetime_fmt = "%F %R"; 519 const char *name = cur_be->be_node_name; 520 const char *mntpt = cur_be->be_mntpt; 521 uint64_t used = cur_be->be_space_used; 522 time_t creation = cur_be->be_node_creation; 523 struct tm *tm; 524 525 if (be_name != NULL && strcmp(be_name, name) != 0) 526 continue; 527 528 if (!parsable) 529 (void) printf("%-s\n", name); 530 else 531 active[0] = '\0'; 532 533 tm = localtime(&creation); 534 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 535 536 if (cur_be->be_active) 537 active[ai++] = 'N'; 538 if (cur_be->be_active_on_boot) 539 active[ai] = 'R'; 540 541 nicenum(used, buf, sizeof (buf)); 542 if (be_fmt & BE_FMT_DATASET) 543 if (parsable) 544 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 545 cur_be->be_node_name, 546 cur_be->be_root_ds, 547 active, 548 (cur_be->be_mounted ? mntpt: ""), 549 used, 550 cur_be->be_policy_type, 551 creation); 552 else 553 (void) printf(" %-*s %-*s %-*s %-*s %-*s " 554 "%-*s\n", 555 hdr->cols[0].width-3, cur_be->be_root_ds, 556 hdr->cols[1].width, active, 557 hdr->cols[2].width, (cur_be->be_mounted ? 558 mntpt: "-"), 559 hdr->cols[3].width, buf, 560 hdr->cols[4].width, cur_be->be_policy_type, 561 hdr->cols[5].width, datetime); 562 563 if (be_fmt & BE_FMT_SNAPSHOT) 564 print_be_snapshots(cur_be, hdr, parsable); 565 } 566 } 567 568 static void 569 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps, 570 boolean_t parsable, be_node_list_t *be_nodes) 571 { 572 enum be_fmt be_fmt = BE_FMT_DEFAULT; 573 574 if (dsets) 575 be_fmt |= BE_FMT_DATASET; 576 if (snaps) 577 be_fmt |= BE_FMT_SNAPSHOT; 578 579 if (be_fmt == BE_FMT_DEFAULT) 580 print_be_nodes(be_name, parsable, be_nodes); 581 else 582 print_fmt_nodes(be_name, be_fmt, parsable, be_nodes); 583 } 584 585 static boolean_t 586 confirm_destroy(const char *name) 587 { 588 boolean_t res = B_FALSE; 589 const char *yesre = nl_langinfo(YESEXPR); 590 const char *nore = nl_langinfo(NOEXPR); 591 regex_t yes_re; 592 regex_t no_re; 593 char buf[128]; 594 char *answer; 595 int cflags = REG_EXTENDED; 596 597 if (regcomp(&yes_re, yesre, cflags) != 0) { 598 /* should not happen */ 599 (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n")); 600 return (res); 601 } 602 if (regcomp(&no_re, nore, cflags) != 0) { 603 /* should not happen */ 604 (void) fprintf(stderr, _("Failed to compile 'no' regexp\n")); 605 regfree(&yes_re); 606 return (res); 607 } 608 609 (void) printf(_("Are you sure you want to destroy %s?\n" 610 "This action cannot be undone (y/[n]): "), name); 611 612 answer = fgets(buf, sizeof (buf), stdin); 613 if (answer == NULL || *answer == '\0' || *answer == 10) 614 goto out; 615 616 if (regexec(&yes_re, answer, 0, NULL, 0) == 0) { 617 res = B_TRUE; 618 } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) { 619 (void) fprintf(stderr, _("Invalid response. " 620 "Please enter 'y' or 'n'.\n")); 621 } 622 623 out: 624 regfree(&yes_re); 625 regfree(&no_re); 626 return (res); 627 } 628 629 static int 630 be_nvl_alloc(nvlist_t **nvlp) 631 { 632 assert(nvlp != NULL); 633 634 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) { 635 (void) perror(_("nvlist_alloc failed.\n")); 636 return (1); 637 } 638 639 return (0); 640 } 641 642 static int 643 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val) 644 { 645 assert(nvl != NULL); 646 647 if (nvlist_add_string(nvl, name, val) != 0) { 648 (void) fprintf(stderr, _("nvlist_add_string failed for " 649 "%s (%s).\n"), name, val); 650 return (1); 651 } 652 653 return (0); 654 } 655 656 static int 657 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 658 { 659 assert(nvl != NULL); 660 661 if (nvlist_add_nvlist(nvl, name, val) != 0) { 662 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"), 663 name); 664 return (1); 665 } 666 667 return (0); 668 } 669 670 static int 671 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 672 { 673 assert(nvl != NULL); 674 675 if (nvlist_add_uint16(nvl, name, val) != 0) { 676 (void) fprintf(stderr, _("nvlist_add_uint16 failed for " 677 "%s (%hu).\n"), name, val); 678 return (1); 679 } 680 681 return (0); 682 } 683 684 static int 685 be_do_activate(int argc, char **argv) 686 { 687 nvlist_t *be_attrs; 688 int err = 1; 689 char *obe_name; 690 691 argc -= optind; 692 argv += optind; 693 694 if (argc != 1) { 695 usage(); 696 return (1); 697 } 698 699 obe_name = argv[0]; 700 701 if (be_nvl_alloc(&be_attrs) != 0) 702 return (1); 703 704 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 705 goto out; 706 707 err = be_activate(be_attrs); 708 709 switch (err) { 710 case BE_SUCCESS: 711 (void) printf(_("Activated successfully\n")); 712 break; 713 case BE_ERR_BE_NOENT: 714 (void) fprintf(stderr, _("%s does not exist or appear " 715 "to be a valid BE.\nPlease check that the name of " 716 "the BE provided is correct.\n"), obe_name); 717 break; 718 case BE_ERR_PERM: 719 case BE_ERR_ACCESS: 720 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); 721 (void) fprintf(stderr, _("You have insufficient privileges to " 722 "execute this command.\n")); 723 break; 724 case BE_ERR_ACTIVATE_CURR: 725 default: 726 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); 727 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 728 } 729 730 out: 731 nvlist_free(be_attrs); 732 return (err); 733 } 734 735 static int 736 be_do_create(int argc, char **argv) 737 { 738 nvlist_t *be_attrs; 739 nvlist_t *zfs_props = NULL; 740 boolean_t activate = B_FALSE; 741 boolean_t is_snap = B_FALSE; 742 int c; 743 int err = 1; 744 char *obe_name = NULL; 745 char *snap_name = NULL; 746 char *nbe_zpool = NULL; 747 char *nbe_name = NULL; 748 char *nbe_desc = NULL; 749 char *propname = NULL; 750 char *propval = NULL; 751 char *strval = NULL; 752 753 while ((c = getopt(argc, argv, "ad:e:io:p:")) != -1) { 754 switch (c) { 755 case 'a': 756 activate = B_TRUE; 757 break; 758 case 'd': 759 nbe_desc = optarg; 760 break; 761 case 'e': 762 obe_name = optarg; 763 break; 764 case 'o': 765 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0) 766 return (1); 767 768 propname = optarg; 769 if ((propval = strchr(propname, '=')) == NULL) { 770 (void) fprintf(stderr, _("missing " 771 "'=' for -o option\n")); 772 goto out2; 773 } 774 *propval = '\0'; 775 propval++; 776 if (nvlist_lookup_string(zfs_props, propname, 777 &strval) == 0) { 778 (void) fprintf(stderr, _("property '%s' " 779 "specified multiple times\n"), propname); 780 goto out2; 781 782 } 783 if (be_nvl_add_string(zfs_props, propname, propval) 784 != 0) 785 goto out2; 786 787 break; 788 case 'p': 789 nbe_zpool = optarg; 790 break; 791 default: 792 usage(); 793 goto out2; 794 } 795 } 796 797 argc -= optind; 798 argv += optind; 799 800 if (argc != 1) { 801 usage(); 802 goto out2; 803 } 804 805 nbe_name = argv[0]; 806 807 if ((snap_name = strrchr(nbe_name, '@')) != NULL) { 808 if (snap_name[1] == '\0') { 809 usage(); 810 goto out2; 811 } 812 813 snap_name[0] = '\0'; 814 snap_name++; 815 is_snap = B_TRUE; 816 } 817 818 if (obe_name) { 819 if (is_snap) { 820 usage(); 821 goto out2; 822 } 823 824 /* 825 * Check if obe_name is really a snapshot name. 826 * If so, split it out. 827 */ 828 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 829 if (snap_name[1] == '\0') { 830 usage(); 831 goto out2; 832 } 833 834 snap_name[0] = '\0'; 835 snap_name++; 836 } 837 } else if (is_snap) { 838 obe_name = nbe_name; 839 nbe_name = NULL; 840 } 841 842 if (be_nvl_alloc(&be_attrs) != 0) 843 goto out2; 844 845 846 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs, 847 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0) 848 goto out; 849 850 if (obe_name != NULL && be_nvl_add_string(be_attrs, 851 BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 852 goto out; 853 854 if (snap_name != NULL && be_nvl_add_string(be_attrs, 855 BE_ATTR_SNAP_NAME, snap_name) != 0) 856 goto out; 857 858 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs, 859 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0) 860 goto out; 861 862 if (nbe_name != NULL && be_nvl_add_string(be_attrs, 863 BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 864 goto out; 865 866 if (nbe_desc != NULL && be_nvl_add_string(be_attrs, 867 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0) 868 goto out; 869 870 if (is_snap) 871 err = be_create_snapshot(be_attrs); 872 else 873 err = be_copy(be_attrs); 874 875 switch (err) { 876 case BE_SUCCESS: 877 if (!is_snap && !nbe_name) { 878 /* 879 * We requested an auto named BE; find out the 880 * name of the BE that was created for us and 881 * the auto snapshot created from the original BE. 882 */ 883 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, 884 &nbe_name) != 0) { 885 (void) fprintf(stderr, _("failed to get %s " 886 "attribute\n"), BE_ATTR_NEW_BE_NAME); 887 break; 888 } else 889 (void) printf(_("Auto named BE: %s\n"), 890 nbe_name); 891 892 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, 893 &snap_name) != 0) { 894 (void) fprintf(stderr, _("failed to get %s " 895 "attribute\n"), BE_ATTR_SNAP_NAME); 896 break; 897 } else 898 (void) printf(_("Auto named snapshot: %s\n"), 899 snap_name); 900 } 901 902 if (!is_snap && activate) { 903 char *args[] = { "activate", "", NULL }; 904 args[1] = nbe_name; 905 optind = 1; 906 907 err = be_do_activate(2, args); 908 goto out; 909 } 910 911 (void) printf(_("Created successfully\n")); 912 break; 913 case BE_ERR_BE_EXISTS: 914 (void) fprintf(stderr, _("BE %s already exists\n." 915 "Please choose a different BE name.\n"), nbe_name); 916 break; 917 case BE_ERR_SS_EXISTS: 918 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" 919 "Please choose a different snapshot name.\n"), obe_name, 920 snap_name); 921 break; 922 case BE_ERR_PERM: 923 case BE_ERR_ACCESS: 924 if (is_snap) 925 (void) fprintf(stderr, _("Unable to create snapshot " 926 "%s.\n"), snap_name); 927 else 928 (void) fprintf(stderr, _("Unable to create %s.\n"), 929 nbe_name); 930 (void) fprintf(stderr, _("You have insufficient privileges to " 931 "execute this command.\n")); 932 break; 933 default: 934 if (is_snap) 935 (void) fprintf(stderr, _("Unable to create snapshot " 936 "%s.\n"), snap_name); 937 else 938 (void) fprintf(stderr, _("Unable to create %s.\n"), 939 nbe_name); 940 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 941 } 942 943 out: 944 nvlist_free(be_attrs); 945 out2: 946 if (zfs_props != NULL) 947 nvlist_free(zfs_props); 948 949 return (err); 950 } 951 952 static int 953 be_do_create_snapshot(int argc, char **argv) 954 { 955 nvlist_t *be_attrs; 956 int err = 1; 957 int c; 958 char *obe_name = NULL; 959 char *snap_name = NULL; 960 char *policy = NULL; 961 962 while ((c = getopt(argc, argv, "p:")) != -1) { 963 switch (c) { 964 case 'p': 965 policy = optarg; 966 break; 967 default: 968 usage(); 969 return (1); 970 } 971 } 972 973 argc -= optind; 974 argv += optind; 975 976 if (argc < 1 || argc > 2) { 977 usage(); 978 return (1); 979 } 980 981 obe_name = argv[0]; 982 983 if (argc > 1) { 984 /* Snapshot name provided */ 985 snap_name = argv[1]; 986 } 987 988 if (be_nvl_alloc(&be_attrs) != 0) 989 return (1); 990 991 992 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 993 goto out; 994 995 if (policy != NULL && be_nvl_add_string(be_attrs, 996 BE_ATTR_POLICY, policy) != 0) 997 goto out; 998 999 if (snap_name != NULL && be_nvl_add_string(be_attrs, 1000 BE_ATTR_SNAP_NAME, snap_name) != 0) 1001 goto out; 1002 1003 err = be_create_snapshot(be_attrs); 1004 1005 switch (err) { 1006 case BE_SUCCESS: 1007 if (!snap_name) { 1008 /* 1009 * We requested an auto named snapshot; find out 1010 * the snapshot name that was created for us. 1011 */ 1012 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, 1013 &snap_name) != 0) { 1014 (void) fprintf(stderr, _("failed to get %s " 1015 "attribute\n"), BE_ATTR_SNAP_NAME); 1016 err = 1; 1017 break; 1018 } 1019 1020 (void) printf(_("Auto named snapshot: %s\n"), 1021 snap_name); 1022 } 1023 (void) printf(_("Created successfully\n")); 1024 break; 1025 case BE_ERR_BE_NOENT: 1026 (void) fprintf(stderr, _("%s does not exist or appear " 1027 "to be a valid BE.\nPlease check that the name of " 1028 "the BE provided is correct.\n"), obe_name); 1029 break; 1030 case BE_ERR_SS_EXISTS: 1031 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" 1032 "Please choose a different snapshot name.\n"), obe_name, 1033 snap_name); 1034 break; 1035 case BE_ERR_PERM: 1036 case BE_ERR_ACCESS: 1037 (void) fprintf(stderr, _("Unable to create snapshot %s.\n"), 1038 snap_name); 1039 (void) fprintf(stderr, _("You have insufficient privileges to " 1040 "execute this command.\n")); 1041 break; 1042 default: 1043 (void) fprintf(stderr, _("Unable to create snapshot %s.\n"), 1044 snap_name); 1045 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1046 } 1047 1048 out: 1049 nvlist_free(be_attrs); 1050 return (err); 1051 } 1052 1053 static int 1054 be_do_destroy(int argc, char **argv) 1055 { 1056 nvlist_t *be_attrs; 1057 boolean_t is_snap = B_FALSE; 1058 boolean_t suppress_prompt = B_FALSE; 1059 int err = 1; 1060 int c; 1061 int destroy_flags = 0; 1062 char *snap_name; 1063 char *be_name; 1064 1065 while ((c = getopt(argc, argv, "fFs")) != -1) { 1066 switch (c) { 1067 case 'f': 1068 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT; 1069 break; 1070 case 's': 1071 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS; 1072 break; 1073 case 'F': 1074 suppress_prompt = B_TRUE; 1075 break; 1076 default: 1077 usage(); 1078 return (1); 1079 } 1080 } 1081 1082 argc -= optind; 1083 argv += optind; 1084 1085 if (argc != 1) { 1086 usage(); 1087 return (1); 1088 } 1089 1090 be_name = argv[0]; 1091 if (!suppress_prompt && !confirm_destroy(be_name)) { 1092 (void) printf(_("%s has not been destroyed.\n"), be_name); 1093 return (0); 1094 } 1095 1096 if ((snap_name = strrchr(be_name, '@')) != NULL) { 1097 if (snap_name[1] == '\0') { 1098 usage(); 1099 return (1); 1100 } 1101 1102 is_snap = B_TRUE; 1103 *snap_name = '\0'; 1104 snap_name++; 1105 } 1106 1107 if (be_nvl_alloc(&be_attrs) != 0) 1108 return (1); 1109 1110 1111 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0) 1112 goto out; 1113 1114 if (is_snap) { 1115 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, 1116 snap_name) != 0) 1117 goto out; 1118 1119 err = be_destroy_snapshot(be_attrs); 1120 } else { 1121 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS, 1122 destroy_flags) != 0) 1123 goto out; 1124 1125 err = be_destroy(be_attrs); 1126 } 1127 1128 switch (err) { 1129 case BE_SUCCESS: 1130 (void) printf(_("Destroyed successfully\n")); 1131 break; 1132 case BE_ERR_MOUNTED: 1133 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1134 (void) fprintf(stderr, _("It is currently mounted and must be " 1135 "unmounted before it can be destroyed.\n" "Use 'beadm " 1136 "unmount %s' to unmount the BE before destroying\nit or " 1137 "'beadm destroy -f %s'.\n"), be_name, be_name); 1138 break; 1139 case BE_ERR_DESTROY_CURR_BE: 1140 (void) fprintf(stderr, _("%s is the currently active BE and " 1141 "cannot be destroyed.\nYou must boot from another BE in " 1142 "order to destroy %s.\n"), be_name, be_name); 1143 break; 1144 case BE_ERR_ZONES_UNMOUNT: 1145 (void) fprintf(stderr, _("Unable to destroy one of " "%s's " 1146 "zone BE's.\nUse 'beadm destroy -f %s' or " 1147 "'zfs -f destroy <dataset>'.\n"), be_name, be_name); 1148 break; 1149 case BE_ERR_SS_NOENT: 1150 (void) fprintf(stderr, _("%s does not exist or appear " 1151 "to be a valid snapshot.\nPlease check that the name of " 1152 "the snapshot provided is correct.\n"), snap_name); 1153 break; 1154 case BE_ERR_PERM: 1155 case BE_ERR_ACCESS: 1156 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1157 (void) fprintf(stderr, _("You have insufficient privileges to " 1158 "execute this command.\n")); 1159 break; 1160 default: 1161 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1162 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1163 } 1164 1165 out: 1166 nvlist_free(be_attrs); 1167 return (err); 1168 } 1169 1170 static int 1171 be_do_destroy_snapshot(int argc, char **argv) 1172 { 1173 nvlist_t *be_attrs; 1174 boolean_t suppress_prompt = B_FALSE; 1175 int err = 1; 1176 char c; 1177 char *obe_name; 1178 char *snap_name; 1179 char *sn; 1180 int sz; 1181 1182 while ((c = getopt(argc, argv, "F")) != -1) { 1183 switch (c) { 1184 case 'F': 1185 suppress_prompt = B_TRUE; 1186 break; 1187 default: 1188 usage(); 1189 return (1); 1190 } 1191 } 1192 1193 argc -= optind; 1194 argv += optind; 1195 1196 if (argc != 2) { 1197 usage(); 1198 return (1); 1199 } 1200 1201 obe_name = argv[0]; 1202 snap_name = argv[1]; 1203 1204 sz = asprintf(&sn, "%s@%s", obe_name, snap_name); 1205 if (sz < 0) { 1206 (void) fprintf(stderr, _("internal error: " 1207 "out of memory\n")); 1208 return (1); 1209 } 1210 1211 if (!suppress_prompt && !confirm_destroy(sn)) { 1212 (void) printf(_("%s has not been destroyed.\n"), sn); 1213 free(sn); 1214 return (0); 1215 } 1216 1217 free(sn); 1218 1219 1220 if (be_nvl_alloc(&be_attrs) != 0) 1221 return (1); 1222 1223 1224 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1225 goto out; 1226 1227 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) 1228 goto out; 1229 1230 err = be_destroy_snapshot(be_attrs); 1231 1232 switch (err) { 1233 case BE_SUCCESS: 1234 (void) printf(_("Destroyed successfully\n")); 1235 break; 1236 case BE_ERR_BE_NOENT: 1237 (void) fprintf(stderr, _("%s does not exist or appear " 1238 "to be a valid BE.\nPlease check that the name of " 1239 "the BE provided is correct.\n"), obe_name); 1240 break; 1241 case BE_ERR_SS_NOENT: 1242 (void) fprintf(stderr, _("%s does not exist or appear " 1243 "to be a valid snapshot.\nPlease check that the name of " 1244 "the snapshot provided is correct.\n"), snap_name); 1245 break; 1246 case BE_ERR_PERM: 1247 case BE_ERR_ACCESS: 1248 (void) fprintf(stderr, _("Unable to destroy snapshot %s.\n"), 1249 snap_name); 1250 (void) fprintf(stderr, _("You have insufficient privileges to " 1251 "execute this command.\n")); 1252 break; 1253 default: 1254 (void) fprintf(stderr, _("Unable to destroy snapshot %s.\n"), 1255 snap_name); 1256 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1257 } 1258 1259 out: 1260 nvlist_free(be_attrs); 1261 return (err); 1262 } 1263 1264 static int 1265 be_do_list(int argc, char **argv) 1266 { 1267 be_node_list_t *be_nodes = NULL; 1268 boolean_t all = B_FALSE; 1269 boolean_t dsets = B_FALSE; 1270 boolean_t snaps = B_FALSE; 1271 boolean_t parsable = B_FALSE; 1272 int err = 1; 1273 int c = 0; 1274 char *be_name = NULL; 1275 1276 while ((c = getopt(argc, argv, "nadsH")) != -1) { 1277 switch (c) { 1278 case 'a': 1279 all = B_TRUE; 1280 break; 1281 case 'd': 1282 dsets = B_TRUE; 1283 break; 1284 case 's': 1285 snaps = B_TRUE; 1286 break; 1287 case 'H': 1288 parsable = B_TRUE; 1289 break; 1290 default: 1291 usage(); 1292 return (1); 1293 } 1294 } 1295 1296 if (all) { 1297 if (dsets) { 1298 (void) fprintf(stderr, _("Invalid options: -a and %s " 1299 "are mutually exclusive.\n"), "-d"); 1300 usage(); 1301 return (1); 1302 } 1303 if (snaps) { 1304 (void) fprintf(stderr, _("Invalid options: -a and %s " 1305 "are mutually exclusive.\n"), "-s"); 1306 usage(); 1307 return (1); 1308 } 1309 1310 dsets = B_TRUE; 1311 snaps = B_TRUE; 1312 } 1313 1314 argc -= optind; 1315 argv += optind; 1316 1317 1318 if (argc == 1) 1319 be_name = argv[0]; 1320 1321 err = be_list(be_name, &be_nodes); 1322 1323 switch (err) { 1324 case BE_SUCCESS: 1325 print_nodes(be_name, dsets, snaps, parsable, be_nodes); 1326 break; 1327 case BE_ERR_BE_NOENT: 1328 if (be_name == NULL) 1329 (void) fprintf(stderr, _("No boot environments found " 1330 "on this system.\n")); 1331 else { 1332 (void) fprintf(stderr, _("%s does not exist or appear " 1333 "to be a valid BE.\nPlease check that the name of " 1334 "the BE provided is correct.\n"), be_name); 1335 } 1336 break; 1337 default: 1338 (void) fprintf(stderr, _("Unable to display Boot " 1339 "Environment\n")); 1340 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1341 } 1342 1343 if (be_nodes != NULL) 1344 be_free_list(be_nodes); 1345 return (err); 1346 } 1347 1348 static int 1349 be_do_mount(int argc, char **argv) 1350 { 1351 nvlist_t *be_attrs; 1352 boolean_t shared_fs = B_FALSE; 1353 int err = 1; 1354 int c; 1355 int mount_flags = 0; 1356 char *obe_name; 1357 char *mountpoint; 1358 char *tmp_mp = NULL; 1359 1360 while ((c = getopt(argc, argv, "s:")) != -1) { 1361 switch (c) { 1362 case 's': 1363 shared_fs = B_TRUE; 1364 1365 mount_flags |= BE_MOUNT_FLAG_SHARED_FS; 1366 1367 if (strcmp(optarg, "rw") == 0) { 1368 mount_flags |= BE_MOUNT_FLAG_SHARED_RW; 1369 } else if (strcmp(optarg, "ro") != 0) { 1370 (void) fprintf(stderr, _("The -s flag " 1371 "requires an argument [ rw | ro ]\n")); 1372 usage(); 1373 return (1); 1374 } 1375 1376 break; 1377 default: 1378 usage(); 1379 return (1); 1380 } 1381 } 1382 1383 argc -= optind; 1384 argv += optind; 1385 1386 if (argc < 1 || argc > 2) { 1387 usage(); 1388 return (1); 1389 } 1390 1391 obe_name = argv[0]; 1392 1393 if (argc == 2) { 1394 mountpoint = argv[1]; 1395 if (mountpoint[0] != '/') { 1396 (void) fprintf(stderr, _("Invalid mount point %s. " 1397 "Mount point must start with a /.\n"), mountpoint); 1398 return (1); 1399 } 1400 } else { 1401 const char *tmpdir = getenv("TMPDIR"); 1402 const char *tmpname = "tmp.XXXXXX"; 1403 int sz; 1404 1405 if (tmpdir == NULL) 1406 tmpdir = "/tmp"; 1407 1408 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname); 1409 if (sz < 0) { 1410 (void) fprintf(stderr, _("internal error: " 1411 "out of memory\n")); 1412 return (1); 1413 } 1414 1415 mountpoint = mkdtemp(tmp_mp); 1416 } 1417 1418 if (be_nvl_alloc(&be_attrs) != 0) 1419 return (1); 1420 1421 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1422 goto out; 1423 1424 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0) 1425 goto out; 1426 1427 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS, 1428 mount_flags) != 0) 1429 goto out; 1430 1431 err = be_mount(be_attrs); 1432 1433 switch (err) { 1434 case BE_SUCCESS: 1435 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint); 1436 break; 1437 case BE_ERR_BE_NOENT: 1438 err = 1; 1439 (void) fprintf(stderr, _("%s does not exist or appear " 1440 "to be a valid BE.\nPlease check that the name of " 1441 "the BE provided is correct.\n"), obe_name); 1442 break; 1443 case BE_ERR_MOUNTED: 1444 (void) fprintf(stderr, _("%s is already mounted.\n" 1445 "Please unmount the BE before mounting it again.\n"), 1446 obe_name); 1447 break; 1448 case BE_ERR_PERM: 1449 case BE_ERR_ACCESS: 1450 err = 1; 1451 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1452 (void) fprintf(stderr, _("You have insufficient privileges to " 1453 "execute this command.\n")); 1454 break; 1455 default: 1456 err = 1; 1457 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1458 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1459 } 1460 1461 out: 1462 if (tmp_mp != NULL) 1463 free(tmp_mp); 1464 nvlist_free(be_attrs); 1465 return (err); 1466 } 1467 1468 static int 1469 be_do_unmount(int argc, char **argv) 1470 { 1471 nvlist_t *be_attrs; 1472 char *obe_name; 1473 int err = 1; 1474 int c; 1475 int unmount_flags = 0; 1476 1477 while ((c = getopt(argc, argv, "f")) != -1) { 1478 switch (c) { 1479 case 'f': 1480 unmount_flags |= BE_UNMOUNT_FLAG_FORCE; 1481 break; 1482 default: 1483 usage(); 1484 return (1); 1485 } 1486 } 1487 1488 argc -= optind; 1489 argv += optind; 1490 1491 if (argc != 1) { 1492 usage(); 1493 return (1); 1494 } 1495 1496 obe_name = argv[0]; 1497 1498 if (be_nvl_alloc(&be_attrs) != 0) 1499 return (1); 1500 1501 1502 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1503 goto out; 1504 1505 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, 1506 unmount_flags) != 0) 1507 goto out; 1508 1509 err = be_unmount(be_attrs); 1510 1511 switch (err) { 1512 case BE_SUCCESS: 1513 (void) printf(_("Unmounted successfully\n")); 1514 break; 1515 case BE_ERR_BE_NOENT: 1516 (void) fprintf(stderr, _("%s does not exist or appear " 1517 "to be a valid BE.\nPlease check that the name of " 1518 "the BE provided is correct.\n"), obe_name); 1519 break; 1520 case BE_ERR_UMOUNT_CURR_BE: 1521 (void) fprintf(stderr, _("%s is the currently active BE.\n" 1522 "It cannot be unmounted unless another BE is the " 1523 "currently active BE.\n"), obe_name); 1524 break; 1525 case BE_ERR_UMOUNT_SHARED: 1526 (void) fprintf(stderr, _("%s is a shared file system and it " 1527 "cannot be unmounted.\n"), obe_name); 1528 break; 1529 case BE_ERR_PERM: 1530 case BE_ERR_ACCESS: 1531 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1532 (void) fprintf(stderr, _("You have insufficient privileges to " 1533 "execute this command.\n")); 1534 break; 1535 default: 1536 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1537 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1538 } 1539 1540 out: 1541 nvlist_free(be_attrs); 1542 return (err); 1543 } 1544 1545 static int 1546 be_do_rename(int argc, char **argv) 1547 { 1548 nvlist_t *be_attrs; 1549 char *obe_name; 1550 char *nbe_name; 1551 int err = 1; 1552 1553 argc -= optind; 1554 argv += optind; 1555 1556 if (argc != 2) { 1557 usage(); 1558 return (1); 1559 } 1560 1561 obe_name = argv[0]; 1562 nbe_name = argv[1]; 1563 1564 if (be_nvl_alloc(&be_attrs) != 0) 1565 return (1); 1566 1567 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1568 goto out; 1569 1570 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 1571 goto out; 1572 1573 err = be_rename(be_attrs); 1574 1575 switch (err) { 1576 case BE_SUCCESS: 1577 (void) printf(_("Renamed successfully\n")); 1578 break; 1579 case BE_ERR_BE_NOENT: 1580 (void) fprintf(stderr, _("%s does not exist or appear " 1581 "to be a valid BE.\nPlease check that the name of " 1582 "the BE provided is correct.\n"), obe_name); 1583 break; 1584 case BE_ERR_PERM: 1585 case BE_ERR_ACCESS: 1586 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1587 obe_name); 1588 (void) fprintf(stderr, _("You have insufficient privileges to " 1589 "execute this command.\n")); 1590 break; 1591 default: 1592 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1593 obe_name); 1594 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1595 } 1596 1597 out: 1598 nvlist_free(be_attrs); 1599 return (err); 1600 } 1601 1602 static int 1603 be_do_rollback(int argc, char **argv) 1604 { 1605 nvlist_t *be_attrs; 1606 char *obe_name; 1607 char *snap_name; 1608 int err = 1; 1609 1610 argc -= optind; 1611 argv += optind; 1612 1613 if (argc < 1 || argc > 2) { 1614 usage(); 1615 return (1); 1616 } 1617 1618 obe_name = argv[0]; 1619 if (argc == 2) 1620 snap_name = argv[1]; 1621 else { /* argc == 1 */ 1622 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 1623 if (snap_name[1] == '\0') { 1624 usage(); 1625 return (1); 1626 } 1627 1628 snap_name[0] = '\0'; 1629 snap_name++; 1630 } else { 1631 usage(); 1632 return (1); 1633 } 1634 } 1635 1636 if (be_nvl_alloc(&be_attrs) != 0) 1637 return (1); 1638 1639 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1640 goto out; 1641 1642 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) 1643 goto out; 1644 1645 err = be_rollback(be_attrs); 1646 1647 switch (err) { 1648 case BE_SUCCESS: 1649 (void) printf(_("Rolled back successfully\n")); 1650 break; 1651 case BE_ERR_BE_NOENT: 1652 (void) fprintf(stderr, _("%s does not exist or appear " 1653 "to be a valid BE.\nPlease check that the name of " 1654 "the BE provided is correct.\n"), obe_name); 1655 break; 1656 case BE_ERR_SS_NOENT: 1657 (void) fprintf(stderr, _("%s does not exist or appear " 1658 "to be a valid snapshot.\nPlease check that the name of " 1659 "the snapshot provided is correct.\n"), snap_name); 1660 break; 1661 case BE_ERR_PERM: 1662 case BE_ERR_ACCESS: 1663 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1664 "failed.\n"), obe_name, snap_name); 1665 (void) fprintf(stderr, _("You have insufficient privileges to " 1666 "execute this command.\n")); 1667 break; 1668 default: 1669 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1670 "failed.\n"), obe_name, snap_name); 1671 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1672 } 1673 1674 out: 1675 nvlist_free(be_attrs); 1676 return (err); 1677 } 1678