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