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