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