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