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