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 */ 30 31 /* 32 * System includes 33 */ 34 35 #include <assert.h> 36 #include <stdio.h> 37 #include <strings.h> 38 #include <libzfs.h> 39 #include <locale.h> 40 #include <langinfo.h> 41 #include <stdlib.h> 42 #include <wchar.h> 43 #include <sys/types.h> 44 45 #include "libbe.h" 46 47 #ifndef lint 48 #define _(x) gettext(x) 49 #else 50 #define _(x) (x) 51 #endif 52 53 #ifndef TEXT_DOMAIN 54 #define TEXT_DOMAIN "SYS_TEST" 55 #endif 56 57 #define DT_BUF_LEN (128) 58 #define NUM_COLS (6) 59 60 static int be_do_activate(int argc, char **argv); 61 static int be_do_create(int argc, char **argv); 62 static int be_do_destroy(int argc, char **argv); 63 static int be_do_list(int argc, char **argv); 64 static int be_do_mount(int argc, char **argv); 65 static int be_do_unmount(int argc, char **argv); 66 static int be_do_rename(int argc, char **argv); 67 static int be_do_rollback(int argc, char **argv); 68 static void usage(void); 69 70 /* 71 * single column name/width output format description 72 */ 73 struct col_info { 74 const char *col_name; 75 size_t width; 76 }; 77 78 /* 79 * all columns output format 80 */ 81 struct hdr_info { 82 struct col_info cols[NUM_COLS]; 83 }; 84 85 /* 86 * type of possible output formats 87 */ 88 enum be_fmt { 89 BE_FMT_DEFAULT, 90 BE_FMT_DATASET, 91 BE_FMT_SNAPSHOT, 92 BE_FMT_ALL 93 }; 94 95 /* 96 * command handler description 97 */ 98 typedef struct be_command { 99 const char *name; 100 int (*func)(int argc, char **argv); 101 } be_command_t; 102 103 /* 104 * sorted list of be commands 105 */ 106 static const be_command_t be_command_tbl[] = { 107 { "activate", be_do_activate }, 108 { "create", be_do_create }, 109 { "destroy", be_do_destroy }, 110 { "list", be_do_list }, 111 { "mount", be_do_mount }, 112 { "unmount", be_do_unmount }, 113 { "umount", be_do_unmount }, /* unmount alias */ 114 { "rename", be_do_rename }, 115 { "rollback", be_do_rollback }, 116 { NULL, NULL }, 117 }; 118 119 static void 120 usage(void) 121 { 122 (void) fprintf(stderr, _("usage:\n" 123 "\tbeadm subcommand cmd_options\n" 124 "\n" 125 "\tsubcommands:\n" 126 "\n" 127 "\tbeadm activate [-v] beName\n" 128 "\tbeadm create [-a] [-d BE_desc]\n" 129 "\t\t[-o property=value] ... [-p zpool] \n" 130 "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n" 131 "\tbeadm create [-d BE_desc]\n" 132 "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n" 133 "\tbeadm destroy [-Ffsv] beName \n" 134 "\tbeadm destroy [-Fv] beName@snapshot \n" 135 "\tbeadm list [[-a] | [-d] [-s]] [-H]\n" 136 "\t\t[-k|-K date | name | space] [-v] [beName]\n" 137 "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n" 138 "\tbeadm unmount [-fv] beName | mountpoint\n" 139 "\tbeadm umount [-fv] beName | mountpoint\n" 140 "\tbeadm rename [-v] origBeName newBeName\n" 141 "\tbeadm rollback [-v] beName snapshot\n" 142 "\tbeadm rollback [-v] beName@snapshot\n")); 143 } 144 145 static int 146 run_be_cmd(const char *cmdname, int argc, char **argv) 147 { 148 const be_command_t *command; 149 150 for (command = &be_command_tbl[0]; command->name != NULL; command++) 151 if (strcmp(command->name, cmdname) == 0) 152 return (command->func(argc, argv)); 153 154 (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname); 155 usage(); 156 return (1); 157 } 158 159 int 160 main(int argc, char **argv) 161 { 162 const char *cmdname; 163 164 (void) setlocale(LC_ALL, ""); 165 (void) textdomain(TEXT_DOMAIN); 166 167 if (argc < 2) { 168 usage(); 169 return (1); 170 } 171 172 cmdname = argv[1]; 173 174 /* Turn error printing off */ 175 libbe_print_errors(B_FALSE); 176 177 return (run_be_cmd(cmdname, --argc, ++argv)); 178 } 179 180 static void 181 print_hdr(struct hdr_info *hdr_info) 182 { 183 boolean_t first = B_TRUE; 184 size_t i; 185 for (i = 0; i < NUM_COLS; i++) { 186 struct col_info *col_info = &hdr_info->cols[i]; 187 const char *name = col_info->col_name; 188 size_t width = col_info->width; 189 if (name == NULL) 190 continue; 191 192 if (first) { 193 (void) printf("%-*s", width, name); 194 first = B_FALSE; 195 } else 196 (void) printf(" %-*s", width, name); 197 } 198 (void) putchar('\n'); 199 } 200 201 static void 202 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr) 203 { 204 struct col_info *col = hdr->cols; 205 size_t i; 206 207 col[1].col_name = _("Active"); 208 col[2].col_name = _("Mountpoint"); 209 col[3].col_name = _("Space"); 210 col[4].col_name = _("Policy"); 211 col[5].col_name = _("Created"); 212 col[6].col_name = NULL; 213 214 switch (be_fmt) { 215 case BE_FMT_ALL: 216 col[0].col_name = _("BE/Dataset/Snapshot"); 217 break; 218 case BE_FMT_DATASET: 219 col[0].col_name = _("BE/Dataset"); 220 break; 221 case BE_FMT_SNAPSHOT: 222 col[0].col_name = _("BE/Snapshot"); 223 col[1].col_name = NULL; 224 col[2].col_name = NULL; 225 break; 226 case BE_FMT_DEFAULT: 227 default: 228 col[0].col_name = _("BE"); 229 } 230 231 for (i = 0; i < NUM_COLS; i++) { 232 const char *name = col[i].col_name; 233 col[i].width = 0; 234 235 if (name != NULL) { 236 wchar_t wname[128]; 237 size_t sz = mbstowcs(wname, name, sizeof (wname) / 238 sizeof (wchar_t)); 239 if (sz > 0) { 240 int wcsw = wcswidth(wname, sz); 241 if (wcsw > 0) 242 col[i].width = wcsw; 243 else 244 col[i].width = sz; 245 } else { 246 col[i].width = strlen(name); 247 } 248 } 249 } 250 } 251 252 static void 253 nicenum(uint64_t num, char *buf, size_t buflen) 254 { 255 uint64_t n = num; 256 int index = 0; 257 char u; 258 259 while (n >= 1024) { 260 n /= 1024; 261 index++; 262 } 263 264 u = " KMGTPE"[index]; 265 266 if (index == 0) { 267 (void) snprintf(buf, buflen, "%llu", n); 268 } else { 269 int i; 270 for (i = 2; i >= 0; i--) { 271 if (snprintf(buf, buflen, "%.*f%c", i, 272 (double)num / (1ULL << 10 * index), u) <= 5) 273 break; 274 } 275 } 276 } 277 278 static void 279 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes) 280 { 281 size_t len[NUM_COLS]; 282 char buf[DT_BUF_LEN]; 283 int i; 284 be_node_list_t *cur_be; 285 286 for (i = 0; i < NUM_COLS; i++) 287 len[i] = hdr->cols[i].width; 288 289 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 290 char name[ZFS_MAXNAMELEN+1]; 291 const char *be_name = cur_be->be_node_name; 292 const char *root_ds = cur_be->be_root_ds; 293 char *pos; 294 size_t node_name_len = strlen(cur_be->be_node_name); 295 size_t root_ds_len = strlen(cur_be->be_root_ds); 296 size_t mntpt_len = 0; 297 size_t policy_len = 0; 298 size_t used_len; 299 uint64_t used = cur_be->be_space_used; 300 be_snapshot_list_t *snap = NULL; 301 302 if (cur_be->be_mntpt != NULL) 303 mntpt_len = strlen(cur_be->be_mntpt); 304 if (cur_be->be_policy_type != NULL) 305 policy_len = strlen(cur_be->be_policy_type); 306 307 (void) strlcpy(name, root_ds, sizeof (name)); 308 pos = strstr(name, be_name); 309 310 if (be_fmt == BE_FMT_DEFAULT) { 311 if (node_name_len > len[0]) 312 len[0] = node_name_len; 313 } else { 314 if (root_ds_len + 3 > len[0]) 315 len[0] = root_ds_len + 3; 316 } 317 318 if (mntpt_len > len[2]) 319 len[2] = mntpt_len; 320 if (policy_len > len[4]) 321 len[4] = policy_len; 322 323 for (snap = cur_be->be_node_snapshots; snap != NULL; 324 snap = snap->be_next_snapshot) { 325 uint64_t snap_used = snap->be_snapshot_space_used; 326 const char *snap_name = snap->be_snapshot_name; 327 (void) strcpy(pos, snap_name); 328 329 if (be_fmt == BE_FMT_DEFAULT) 330 used += snap_used; 331 else if (be_fmt & BE_FMT_SNAPSHOT) { 332 int snap_len = strlen(name) + 3; 333 if (be_fmt == BE_FMT_SNAPSHOT) 334 snap_len -= pos - name; 335 if (snap_len > len[0]) 336 len[0] = snap_len; 337 nicenum(snap_used, buf, sizeof (buf)); 338 used_len = strlen(buf); 339 if (used_len > len[3]) 340 len[3] = used_len; 341 } 342 } 343 344 if (be_fmt == BE_FMT_DEFAULT) { 345 int used_len; 346 nicenum(used, buf, sizeof (buf)); 347 used_len = strlen(buf); 348 if (used_len > len[3]) 349 len[3] = used_len; 350 } 351 352 nicenum(used, buf, sizeof (buf)); 353 } 354 355 for (i = 0; i < NUM_COLS; i++) 356 hdr->cols[i].width = len[i]; 357 } 358 359 static void 360 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr, 361 be_node_list_t *nodes) 362 { 363 char buf[64]; 364 char datetime[DT_BUF_LEN]; 365 be_node_list_t *cur_be; 366 367 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 368 char active[3] = "-\0"; 369 int ai = 0; 370 const char *datetime_fmt = "%F %R"; 371 const char *name = cur_be->be_node_name; 372 const char *mntpt = cur_be->be_mntpt; 373 be_snapshot_list_t *snap = NULL; 374 uint64_t used = cur_be->be_space_used; 375 time_t creation = cur_be->be_node_creation; 376 struct tm *tm; 377 378 if (be_name != NULL && strcmp(be_name, name) != 0) 379 continue; 380 381 if (parsable) 382 active[0] = '\0'; 383 384 tm = localtime(&creation); 385 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 386 387 for (snap = cur_be->be_node_snapshots; snap != NULL; 388 snap = snap->be_next_snapshot) 389 used += snap->be_snapshot_space_used; 390 391 if (!cur_be->be_global_active) 392 active[ai++] = 'x'; 393 394 if (cur_be->be_active) 395 active[ai++] = 'N'; 396 if (cur_be->be_active_on_boot) { 397 if (!cur_be->be_global_active) 398 active[ai] = 'b'; 399 else 400 active[ai] = 'R'; 401 } 402 403 nicenum(used, buf, sizeof (buf)); 404 if (parsable) 405 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 406 name, 407 cur_be->be_uuid_str, 408 active, 409 (cur_be->be_mounted ? mntpt: ""), 410 used, 411 cur_be->be_policy_type, 412 creation); 413 else 414 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n", 415 hdr->cols[0].width, name, 416 hdr->cols[1].width, active, 417 hdr->cols[2].width, (cur_be->be_mounted ? mntpt: 418 "-"), 419 hdr->cols[3].width, buf, 420 hdr->cols[4].width, cur_be->be_policy_type, 421 hdr->cols[5].width, datetime); 422 } 423 } 424 425 static void 426 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable) 427 { 428 char buf[64]; 429 char datetime[DT_BUF_LEN]; 430 be_snapshot_list_t *snap = NULL; 431 432 for (snap = be->be_node_snapshots; snap != NULL; 433 snap = snap->be_next_snapshot) { 434 char name[ZFS_MAXNAMELEN+1]; 435 const char *datetime_fmt = "%F %R"; 436 const char *be_name = be->be_node_name; 437 const char *root_ds = be->be_root_ds; 438 const char *snap_name = snap->be_snapshot_name; 439 char *pos; 440 uint64_t used = snap->be_snapshot_space_used; 441 time_t creation = snap->be_snapshot_creation; 442 struct tm *tm = localtime(&creation); 443 444 (void) strncpy(name, root_ds, sizeof (name)); 445 pos = strstr(name, be_name); 446 (void) strcpy(pos, snap_name); 447 448 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 449 nicenum(used, buf, sizeof (buf)); 450 451 if (parsable) 452 if (hdr->cols[1].width != 0) 453 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 454 be_name, 455 snap_name, 456 "", 457 "", 458 used, 459 be->be_policy_type, 460 creation); 461 else 462 (void) printf("%s;%s;%llu;%s;%ld\n", 463 be_name, 464 snap_name, 465 used, 466 be->be_policy_type, 467 creation); 468 else 469 if (hdr->cols[1].width != 0) 470 (void) printf(" %-*s %-*s %-*s %-*s %-*s " 471 "%-*s\n", 472 hdr->cols[0].width-3, name, 473 hdr->cols[1].width, "-", 474 hdr->cols[2].width, "-", 475 hdr->cols[3].width, buf, 476 hdr->cols[4].width, be->be_policy_type, 477 hdr->cols[5].width, datetime); 478 else 479 (void) printf(" %-*s %-*s %-*s %-*s\n", 480 hdr->cols[0].width-3, snap_name, 481 hdr->cols[3].width, buf, 482 hdr->cols[4].width, be->be_policy_type, 483 hdr->cols[5].width, datetime); 484 } 485 } 486 487 static void 488 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable, 489 struct hdr_info *hdr, be_node_list_t *nodes) 490 { 491 char buf[64]; 492 char datetime[DT_BUF_LEN]; 493 be_node_list_t *cur_be; 494 495 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 496 char active[3] = "-\0"; 497 int ai = 0; 498 const char *datetime_fmt = "%F %R"; 499 const char *name = cur_be->be_node_name; 500 const char *mntpt = cur_be->be_mntpt; 501 uint64_t used = cur_be->be_space_used; 502 time_t creation = cur_be->be_node_creation; 503 struct tm *tm; 504 505 if (be_name != NULL && strcmp(be_name, name) != 0) 506 continue; 507 508 if (!parsable) 509 (void) printf("%-s\n", name); 510 else 511 active[0] = '\0'; 512 513 tm = localtime(&creation); 514 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); 515 516 if (cur_be->be_active) 517 active[ai++] = 'N'; 518 if (cur_be->be_active_on_boot) 519 active[ai] = 'R'; 520 521 nicenum(used, buf, sizeof (buf)); 522 if (be_fmt & BE_FMT_DATASET) 523 if (parsable) 524 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", 525 cur_be->be_node_name, 526 cur_be->be_root_ds, 527 active, 528 (cur_be->be_mounted ? mntpt: ""), 529 used, 530 cur_be->be_policy_type, 531 creation); 532 else 533 (void) printf(" %-*s %-*s %-*s %-*s %-*s " 534 "%-*s\n", 535 hdr->cols[0].width-3, cur_be->be_root_ds, 536 hdr->cols[1].width, active, 537 hdr->cols[2].width, (cur_be->be_mounted ? 538 mntpt: "-"), 539 hdr->cols[3].width, buf, 540 hdr->cols[4].width, cur_be->be_policy_type, 541 hdr->cols[5].width, datetime); 542 543 if (be_fmt & BE_FMT_SNAPSHOT) 544 print_be_snapshots(cur_be, hdr, parsable); 545 } 546 } 547 548 static void 549 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps, 550 boolean_t parsable, be_node_list_t *be_nodes) 551 { 552 struct hdr_info hdr; 553 enum be_fmt be_fmt = BE_FMT_DEFAULT; 554 555 if (dsets) 556 be_fmt |= BE_FMT_DATASET; 557 if (snaps) 558 be_fmt |= BE_FMT_SNAPSHOT; 559 560 if (!parsable) { 561 init_hdr_cols(be_fmt, &hdr); 562 count_widths(be_fmt, &hdr, be_nodes); 563 print_hdr(&hdr); 564 } 565 566 if (be_fmt == BE_FMT_DEFAULT) 567 print_be_nodes(be_name, parsable, &hdr, be_nodes); 568 else 569 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes); 570 } 571 572 static boolean_t 573 confirm_destroy(const char *name) 574 { 575 boolean_t res = B_FALSE; 576 const char *yesre = nl_langinfo(YESEXPR); 577 const char *nore = nl_langinfo(NOEXPR); 578 regex_t yes_re; 579 regex_t no_re; 580 char buf[128]; 581 char *answer; 582 int cflags = REG_EXTENDED; 583 584 if (regcomp(&yes_re, yesre, cflags) != 0) { 585 /* should not happen */ 586 (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n")); 587 return (res); 588 } 589 if (regcomp(&no_re, nore, cflags) != 0) { 590 /* should not happen */ 591 (void) fprintf(stderr, _("Failed to compile 'no' regexp\n")); 592 regfree(&yes_re); 593 return (res); 594 } 595 596 (void) printf(_("Are you sure you want to destroy %s?\n" 597 "This action cannot be undone (y/[n]): "), name); 598 599 answer = fgets(buf, sizeof (buf), stdin); 600 if (answer == NULL || *answer == '\0' || *answer == 10) 601 goto out; 602 603 if (regexec(&yes_re, answer, 0, NULL, 0) == 0) { 604 res = B_TRUE; 605 } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) { 606 (void) fprintf(stderr, _("Invalid response. " 607 "Please enter 'y' or 'n'.\n")); 608 } 609 610 out: 611 regfree(&yes_re); 612 regfree(&no_re); 613 return (res); 614 } 615 616 static int 617 be_nvl_alloc(nvlist_t **nvlp) 618 { 619 assert(nvlp != NULL); 620 621 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) { 622 (void) perror(_("nvlist_alloc failed.\n")); 623 return (1); 624 } 625 626 return (0); 627 } 628 629 static int 630 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val) 631 { 632 assert(nvl != NULL); 633 634 if (nvlist_add_string(nvl, name, val) != 0) { 635 (void) fprintf(stderr, _("nvlist_add_string failed for " 636 "%s (%s).\n"), name, val); 637 return (1); 638 } 639 640 return (0); 641 } 642 643 static int 644 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 645 { 646 assert(nvl != NULL); 647 648 if (nvlist_add_nvlist(nvl, name, val) != 0) { 649 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"), 650 name); 651 return (1); 652 } 653 654 return (0); 655 } 656 657 static int 658 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 659 { 660 assert(nvl != NULL); 661 662 if (nvlist_add_uint16(nvl, name, val) != 0) { 663 (void) fprintf(stderr, _("nvlist_add_uint16 failed for " 664 "%s (%hu).\n"), name, val); 665 return (1); 666 } 667 668 return (0); 669 } 670 671 static int 672 be_do_activate(int argc, char **argv) 673 { 674 nvlist_t *be_attrs; 675 int err = 1; 676 int c; 677 char *obe_name; 678 679 while ((c = getopt(argc, argv, "v")) != -1) { 680 switch (c) { 681 case 'v': 682 libbe_print_errors(B_TRUE); 683 break; 684 default: 685 usage(); 686 return (1); 687 } 688 } 689 690 argc -= optind; 691 argv += optind; 692 693 if (argc != 1) { 694 usage(); 695 return (1); 696 } 697 698 obe_name = argv[0]; 699 700 if (be_nvl_alloc(&be_attrs) != 0) 701 return (1); 702 703 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 704 goto out; 705 706 err = be_activate(be_attrs); 707 708 switch (err) { 709 case BE_SUCCESS: 710 (void) printf(_("Activated successfully\n")); 711 break; 712 case BE_ERR_BE_NOENT: 713 (void) fprintf(stderr, _("%s does not exist or appear " 714 "to be a valid BE.\nPlease check that the name of " 715 "the BE provided is correct.\n"), obe_name); 716 break; 717 case BE_ERR_PERM: 718 case BE_ERR_ACCESS: 719 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); 720 (void) fprintf(stderr, _("You have insufficient privileges to " 721 "execute this command.\n")); 722 break; 723 case BE_ERR_ACTIVATE_CURR: 724 default: 725 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); 726 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 727 } 728 729 out: 730 nvlist_free(be_attrs); 731 return (err); 732 } 733 734 static int 735 be_do_create(int argc, char **argv) 736 { 737 nvlist_t *be_attrs; 738 nvlist_t *zfs_props = NULL; 739 boolean_t activate = B_FALSE; 740 boolean_t is_snap = B_FALSE; 741 int c; 742 int err = 1; 743 char *obe_name = NULL; 744 char *snap_name = NULL; 745 char *nbe_zpool = NULL; 746 char *nbe_name = NULL; 747 char *nbe_desc = NULL; 748 char *propname = NULL; 749 char *propval = NULL; 750 char *strval = NULL; 751 752 while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) { 753 switch (c) { 754 case 'a': 755 activate = B_TRUE; 756 break; 757 case 'd': 758 nbe_desc = optarg; 759 break; 760 case 'e': 761 obe_name = optarg; 762 break; 763 case 'o': 764 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0) 765 return (1); 766 767 propname = optarg; 768 if ((propval = strchr(propname, '=')) == NULL) { 769 (void) fprintf(stderr, _("missing " 770 "'=' for -o option\n")); 771 goto out2; 772 } 773 *propval = '\0'; 774 propval++; 775 if (nvlist_lookup_string(zfs_props, propname, 776 &strval) == 0) { 777 (void) fprintf(stderr, _("property '%s' " 778 "specified multiple times\n"), propname); 779 goto out2; 780 781 } 782 if (be_nvl_add_string(zfs_props, propname, propval) 783 != 0) 784 goto out2; 785 786 break; 787 case 'p': 788 nbe_zpool = optarg; 789 break; 790 case 'v': 791 libbe_print_errors(B_TRUE); 792 break; 793 default: 794 usage(); 795 goto out2; 796 } 797 } 798 799 argc -= optind; 800 argv += optind; 801 802 if (argc != 1) { 803 usage(); 804 goto out2; 805 } 806 807 nbe_name = argv[0]; 808 809 if ((snap_name = strrchr(nbe_name, '@')) != NULL) { 810 if (snap_name[1] == '\0') { 811 usage(); 812 goto out2; 813 } 814 815 snap_name[0] = '\0'; 816 snap_name++; 817 is_snap = B_TRUE; 818 } 819 820 if (obe_name) { 821 if (is_snap) { 822 usage(); 823 goto out2; 824 } 825 826 /* 827 * Check if obe_name is really a snapshot name. 828 * If so, split it out. 829 */ 830 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 831 if (snap_name[1] == '\0') { 832 usage(); 833 goto out2; 834 } 835 836 snap_name[0] = '\0'; 837 snap_name++; 838 } 839 } else if (is_snap) { 840 obe_name = nbe_name; 841 nbe_name = NULL; 842 } 843 844 if (be_nvl_alloc(&be_attrs) != 0) 845 goto out2; 846 847 848 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs, 849 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0) 850 goto out; 851 852 if (obe_name != NULL && be_nvl_add_string(be_attrs, 853 BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 854 goto out; 855 856 if (snap_name != NULL && be_nvl_add_string(be_attrs, 857 BE_ATTR_SNAP_NAME, snap_name) != 0) 858 goto out; 859 860 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs, 861 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0) 862 goto out; 863 864 if (nbe_name != NULL && be_nvl_add_string(be_attrs, 865 BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 866 goto out; 867 868 if (nbe_desc != NULL && be_nvl_add_string(be_attrs, 869 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0) 870 goto out; 871 872 if (is_snap) 873 err = be_create_snapshot(be_attrs); 874 else 875 err = be_copy(be_attrs); 876 877 switch (err) { 878 case BE_SUCCESS: 879 if (!is_snap && !nbe_name) { 880 /* 881 * We requested an auto named BE; find out the 882 * name of the BE that was created for us and 883 * the auto snapshot created from the original BE. 884 */ 885 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, 886 &nbe_name) != 0) { 887 (void) fprintf(stderr, _("failed to get %s " 888 "attribute\n"), BE_ATTR_NEW_BE_NAME); 889 break; 890 } else 891 (void) printf(_("Auto named BE: %s\n"), 892 nbe_name); 893 894 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, 895 &snap_name) != 0) { 896 (void) fprintf(stderr, _("failed to get %s " 897 "attribute\n"), BE_ATTR_SNAP_NAME); 898 break; 899 } else 900 (void) printf(_("Auto named snapshot: %s\n"), 901 snap_name); 902 } 903 904 if (!is_snap && activate) { 905 char *args[] = { "activate", "", NULL }; 906 args[1] = nbe_name; 907 optind = 1; 908 909 err = be_do_activate(2, args); 910 goto out; 911 } 912 913 (void) printf(_("Created successfully\n")); 914 break; 915 case BE_ERR_BE_EXISTS: 916 (void) fprintf(stderr, _("BE %s already exists\n." 917 "Please choose a different BE name.\n"), nbe_name); 918 break; 919 case BE_ERR_SS_EXISTS: 920 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" 921 "Please choose a different snapshot name.\n"), obe_name, 922 snap_name); 923 break; 924 case BE_ERR_PERM: 925 case BE_ERR_ACCESS: 926 if (is_snap) 927 (void) fprintf(stderr, _("Unable to create snapshot " 928 "%s.\n"), snap_name); 929 else 930 (void) fprintf(stderr, _("Unable to create %s.\n"), 931 nbe_name); 932 (void) fprintf(stderr, _("You have insufficient privileges to " 933 "execute this command.\n")); 934 break; 935 default: 936 if (is_snap) 937 (void) fprintf(stderr, _("Unable to create snapshot " 938 "%s.\n"), snap_name); 939 else 940 (void) fprintf(stderr, _("Unable to create %s.\n"), 941 nbe_name); 942 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 943 } 944 945 out: 946 nvlist_free(be_attrs); 947 out2: 948 if (zfs_props != NULL) 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 be_sort(&be_nodes, order); 1183 1184 print_nodes(be_name, dsets, snaps, parsable, be_nodes); 1185 break; 1186 case BE_ERR_BE_NOENT: 1187 if (be_name == NULL) 1188 (void) fprintf(stderr, _("No boot environments found " 1189 "on this system.\n")); 1190 else { 1191 (void) fprintf(stderr, _("%s does not exist or appear " 1192 "to be a valid BE.\nPlease check that the name of " 1193 "the BE provided is correct.\n"), be_name); 1194 } 1195 break; 1196 default: 1197 (void) fprintf(stderr, _("Unable to display Boot " 1198 "Environment\n")); 1199 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1200 } 1201 1202 if (be_nodes != NULL) 1203 be_free_list(be_nodes); 1204 return (err); 1205 } 1206 1207 static int 1208 be_do_mount(int argc, char **argv) 1209 { 1210 nvlist_t *be_attrs; 1211 boolean_t shared_fs = B_FALSE; 1212 int err = 1; 1213 int c; 1214 int mount_flags = 0; 1215 char *obe_name; 1216 char *mountpoint; 1217 char *tmp_mp = NULL; 1218 1219 while ((c = getopt(argc, argv, "s:v")) != -1) { 1220 switch (c) { 1221 case 's': 1222 shared_fs = B_TRUE; 1223 1224 mount_flags |= BE_MOUNT_FLAG_SHARED_FS; 1225 1226 if (strcmp(optarg, "rw") == 0) { 1227 mount_flags |= BE_MOUNT_FLAG_SHARED_RW; 1228 } else if (strcmp(optarg, "ro") != 0) { 1229 (void) fprintf(stderr, _("The -s flag " 1230 "requires an argument [ rw | ro ]\n")); 1231 usage(); 1232 return (1); 1233 } 1234 1235 break; 1236 case 'v': 1237 libbe_print_errors(B_TRUE); 1238 break; 1239 default: 1240 usage(); 1241 return (1); 1242 } 1243 } 1244 1245 argc -= optind; 1246 argv += optind; 1247 1248 if (argc < 1 || argc > 2) { 1249 usage(); 1250 return (1); 1251 } 1252 1253 obe_name = argv[0]; 1254 1255 if (argc == 2) { 1256 mountpoint = argv[1]; 1257 if (mountpoint[0] != '/') { 1258 (void) fprintf(stderr, _("Invalid mount point %s. " 1259 "Mount point must start with a /.\n"), mountpoint); 1260 return (1); 1261 } 1262 } else { 1263 const char *tmpdir = getenv("TMPDIR"); 1264 const char *tmpname = "tmp.XXXXXX"; 1265 int sz; 1266 1267 if (tmpdir == NULL) 1268 tmpdir = "/tmp"; 1269 1270 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname); 1271 if (sz < 0) { 1272 (void) fprintf(stderr, _("internal error: " 1273 "out of memory\n")); 1274 return (1); 1275 } 1276 1277 mountpoint = mkdtemp(tmp_mp); 1278 } 1279 1280 if (be_nvl_alloc(&be_attrs) != 0) 1281 return (1); 1282 1283 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1284 goto out; 1285 1286 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0) 1287 goto out; 1288 1289 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS, 1290 mount_flags) != 0) 1291 goto out; 1292 1293 err = be_mount(be_attrs); 1294 1295 switch (err) { 1296 case BE_SUCCESS: 1297 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint); 1298 break; 1299 case BE_ERR_BE_NOENT: 1300 (void) fprintf(stderr, _("%s does not exist or appear " 1301 "to be a valid BE.\nPlease check that the name of " 1302 "the BE provided is correct.\n"), obe_name); 1303 break; 1304 case BE_ERR_MOUNTED: 1305 (void) fprintf(stderr, _("%s is already mounted.\n" 1306 "Please unmount the BE before mounting it again.\n"), 1307 obe_name); 1308 break; 1309 case BE_ERR_PERM: 1310 case BE_ERR_ACCESS: 1311 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1312 (void) fprintf(stderr, _("You have insufficient privileges to " 1313 "execute this command.\n")); 1314 break; 1315 case BE_ERR_NO_MOUNTED_ZONE: 1316 (void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount " 1317 "one of %s's zone BE's.\n"), mountpoint, obe_name); 1318 break; 1319 default: 1320 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1321 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1322 } 1323 1324 out: 1325 if (tmp_mp != NULL) 1326 free(tmp_mp); 1327 nvlist_free(be_attrs); 1328 return (err); 1329 } 1330 1331 static int 1332 be_do_unmount(int argc, char **argv) 1333 { 1334 nvlist_t *be_attrs; 1335 char *obe_name; 1336 int err = 1; 1337 int c; 1338 int unmount_flags = 0; 1339 1340 while ((c = getopt(argc, argv, "fv")) != -1) { 1341 switch (c) { 1342 case 'f': 1343 unmount_flags |= BE_UNMOUNT_FLAG_FORCE; 1344 break; 1345 case 'v': 1346 libbe_print_errors(B_TRUE); 1347 break; 1348 default: 1349 usage(); 1350 return (1); 1351 } 1352 } 1353 1354 argc -= optind; 1355 argv += optind; 1356 1357 if (argc != 1) { 1358 usage(); 1359 return (1); 1360 } 1361 1362 obe_name = argv[0]; 1363 1364 if (be_nvl_alloc(&be_attrs) != 0) 1365 return (1); 1366 1367 1368 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1369 goto out; 1370 1371 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, 1372 unmount_flags) != 0) 1373 goto out; 1374 1375 err = be_unmount(be_attrs); 1376 1377 switch (err) { 1378 case BE_SUCCESS: 1379 (void) printf(_("Unmounted successfully\n")); 1380 break; 1381 case BE_ERR_BE_NOENT: 1382 (void) fprintf(stderr, _("%s does not exist or appear " 1383 "to be a valid BE.\nPlease check that the name of " 1384 "the BE provided is correct.\n"), obe_name); 1385 break; 1386 case BE_ERR_UMOUNT_CURR_BE: 1387 (void) fprintf(stderr, _("%s is the currently active BE.\n" 1388 "It cannot be unmounted unless another BE is the " 1389 "currently active BE.\n"), obe_name); 1390 break; 1391 case BE_ERR_UMOUNT_SHARED: 1392 (void) fprintf(stderr, _("%s is a shared file system and it " 1393 "cannot be unmounted.\n"), obe_name); 1394 break; 1395 case BE_ERR_PERM: 1396 case BE_ERR_ACCESS: 1397 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1398 (void) fprintf(stderr, _("You have insufficient privileges to " 1399 "execute this command.\n")); 1400 break; 1401 default: 1402 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1403 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1404 } 1405 1406 out: 1407 nvlist_free(be_attrs); 1408 return (err); 1409 } 1410 1411 static int 1412 be_do_rename(int argc, char **argv) 1413 { 1414 nvlist_t *be_attrs; 1415 char *obe_name; 1416 char *nbe_name; 1417 int err = 1; 1418 int c; 1419 1420 while ((c = getopt(argc, argv, "v")) != -1) { 1421 switch (c) { 1422 case 'v': 1423 libbe_print_errors(B_TRUE); 1424 break; 1425 default: 1426 usage(); 1427 return (1); 1428 } 1429 } 1430 1431 argc -= optind; 1432 argv += optind; 1433 1434 if (argc != 2) { 1435 usage(); 1436 return (1); 1437 } 1438 1439 obe_name = argv[0]; 1440 nbe_name = argv[1]; 1441 1442 if (be_nvl_alloc(&be_attrs) != 0) 1443 return (1); 1444 1445 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1446 goto out; 1447 1448 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 1449 goto out; 1450 1451 err = be_rename(be_attrs); 1452 1453 switch (err) { 1454 case BE_SUCCESS: 1455 (void) printf(_("Renamed successfully\n")); 1456 break; 1457 case BE_ERR_BE_NOENT: 1458 (void) fprintf(stderr, _("%s does not exist or appear " 1459 "to be a valid BE.\nPlease check that the name of " 1460 "the BE provided is correct.\n"), obe_name); 1461 break; 1462 case BE_ERR_PERM: 1463 case BE_ERR_ACCESS: 1464 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1465 obe_name); 1466 (void) fprintf(stderr, _("You have insufficient privileges to " 1467 "execute this command.\n")); 1468 break; 1469 default: 1470 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1471 obe_name); 1472 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1473 } 1474 1475 out: 1476 nvlist_free(be_attrs); 1477 return (err); 1478 } 1479 1480 static int 1481 be_do_rollback(int argc, char **argv) 1482 { 1483 nvlist_t *be_attrs; 1484 char *obe_name; 1485 char *snap_name; 1486 int err = 1; 1487 int c; 1488 1489 while ((c = getopt(argc, argv, "v")) != -1) { 1490 switch (c) { 1491 case 'v': 1492 libbe_print_errors(B_TRUE); 1493 break; 1494 default: 1495 usage(); 1496 return (1); 1497 } 1498 } 1499 1500 argc -= optind; 1501 argv += optind; 1502 1503 if (argc < 1 || argc > 2) { 1504 usage(); 1505 return (1); 1506 } 1507 1508 obe_name = argv[0]; 1509 if (argc == 2) 1510 snap_name = argv[1]; 1511 else { /* argc == 1 */ 1512 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 1513 if (snap_name[1] == '\0') { 1514 usage(); 1515 return (1); 1516 } 1517 1518 snap_name[0] = '\0'; 1519 snap_name++; 1520 } else { 1521 usage(); 1522 return (1); 1523 } 1524 } 1525 1526 if (be_nvl_alloc(&be_attrs) != 0) 1527 return (1); 1528 1529 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1530 goto out; 1531 1532 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) 1533 goto out; 1534 1535 err = be_rollback(be_attrs); 1536 1537 switch (err) { 1538 case BE_SUCCESS: 1539 (void) printf(_("Rolled back successfully\n")); 1540 break; 1541 case BE_ERR_BE_NOENT: 1542 (void) fprintf(stderr, _("%s does not exist or appear " 1543 "to be a valid BE.\nPlease check that the name of " 1544 "the BE provided is correct.\n"), obe_name); 1545 break; 1546 case BE_ERR_SS_NOENT: 1547 (void) fprintf(stderr, _("%s does not exist or appear " 1548 "to be a valid snapshot.\nPlease check that the name of " 1549 "the snapshot provided is correct.\n"), snap_name); 1550 break; 1551 case BE_ERR_PERM: 1552 case BE_ERR_ACCESS: 1553 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1554 "failed.\n"), obe_name, snap_name); 1555 (void) fprintf(stderr, _("You have insufficient privileges to " 1556 "execute this command.\n")); 1557 break; 1558 default: 1559 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1560 "failed.\n"), obe_name, snap_name); 1561 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1562 } 1563 1564 out: 1565 nvlist_free(be_attrs); 1566 return (err); 1567 }