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