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