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 2018 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] [-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] | [-d] [-s]] [-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 + 1]; 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 + 1]; 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 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:v")) != -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 'v': 816 libbe_print_errors(B_TRUE); 817 break; 818 default: 819 usage(); 820 goto out2; 821 } 822 } 823 824 argc -= optind; 825 argv += optind; 826 827 if (argc != 1) { 828 usage(); 829 goto out2; 830 } 831 832 nbe_name = argv[0]; 833 834 if ((snap_name = strrchr(nbe_name, '@')) != NULL) { 835 if (snap_name[1] == '\0') { 836 usage(); 837 goto out2; 838 } 839 840 snap_name[0] = '\0'; 841 snap_name++; 842 is_snap = B_TRUE; 843 } 844 845 if (obe_name) { 846 if (is_snap) { 847 usage(); 848 goto out2; 849 } 850 851 /* 852 * Check if obe_name is really a snapshot name. 853 * If so, split it out. 854 */ 855 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 856 if (snap_name[1] == '\0') { 857 usage(); 858 goto out2; 859 } 860 861 snap_name[0] = '\0'; 862 snap_name++; 863 } 864 } else if (is_snap) { 865 obe_name = nbe_name; 866 nbe_name = NULL; 867 } 868 869 if (be_nvl_alloc(&be_attrs) != 0) 870 goto out2; 871 872 873 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs, 874 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0) 875 goto out; 876 877 if (obe_name != NULL && be_nvl_add_string(be_attrs, 878 BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 879 goto out; 880 881 if (snap_name != NULL && be_nvl_add_string(be_attrs, 882 BE_ATTR_SNAP_NAME, snap_name) != 0) 883 goto out; 884 885 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs, 886 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0) 887 goto out; 888 889 if (nbe_name != NULL && be_nvl_add_string(be_attrs, 890 BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 891 goto out; 892 893 if (nbe_desc != NULL && be_nvl_add_string(be_attrs, 894 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0) 895 goto out; 896 897 if (is_snap) 898 err = be_create_snapshot(be_attrs); 899 else 900 err = be_copy(be_attrs); 901 902 switch (err) { 903 case BE_SUCCESS: 904 if (!is_snap && !nbe_name) { 905 /* 906 * We requested an auto named BE; find out the 907 * name of the BE that was created for us and 908 * the auto snapshot created from the original BE. 909 */ 910 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, 911 &nbe_name) != 0) { 912 (void) fprintf(stderr, _("failed to get %s " 913 "attribute\n"), BE_ATTR_NEW_BE_NAME); 914 break; 915 } else 916 (void) printf(_("Auto named BE: %s\n"), 917 nbe_name); 918 919 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, 920 &snap_name) != 0) { 921 (void) fprintf(stderr, _("failed to get %s " 922 "attribute\n"), BE_ATTR_SNAP_NAME); 923 break; 924 } else 925 (void) printf(_("Auto named snapshot: %s\n"), 926 snap_name); 927 } 928 929 if (!is_snap && activate) { 930 char *args[] = { "activate", "", NULL }; 931 args[1] = nbe_name; 932 optind = 1; 933 934 err = be_do_activate(2, args); 935 goto out; 936 } 937 938 (void) printf(_("Created successfully\n")); 939 break; 940 case BE_ERR_BE_EXISTS: 941 (void) fprintf(stderr, _("BE %s already exists\n." 942 "Please choose a different BE name.\n"), nbe_name); 943 break; 944 case BE_ERR_SS_EXISTS: 945 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" 946 "Please choose a different snapshot name.\n"), obe_name, 947 snap_name); 948 break; 949 case BE_ERR_PERM: 950 case BE_ERR_ACCESS: 951 if (is_snap) 952 (void) fprintf(stderr, _("Unable to create snapshot " 953 "%s.\n"), snap_name); 954 else 955 (void) fprintf(stderr, _("Unable to create %s.\n"), 956 nbe_name); 957 (void) fprintf(stderr, _("You have insufficient privileges to " 958 "execute this command.\n")); 959 break; 960 default: 961 if (is_snap) 962 (void) fprintf(stderr, _("Unable to create snapshot " 963 "%s.\n"), snap_name); 964 else 965 (void) fprintf(stderr, _("Unable to create %s.\n"), 966 nbe_name); 967 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 968 } 969 970 out: 971 nvlist_free(be_attrs); 972 out2: 973 nvlist_free(zfs_props); 974 975 return (err); 976 } 977 978 static int 979 be_do_destroy(int argc, char **argv) 980 { 981 nvlist_t *be_attrs; 982 boolean_t is_snap = B_FALSE; 983 boolean_t suppress_prompt = B_FALSE; 984 int err = 1; 985 int c; 986 int destroy_flags = 0; 987 char *snap_name; 988 char *be_name; 989 990 while ((c = getopt(argc, argv, "fFsv")) != -1) { 991 switch (c) { 992 case 'f': 993 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT; 994 break; 995 case 's': 996 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS; 997 break; 998 case 'v': 999 libbe_print_errors(B_TRUE); 1000 break; 1001 case 'F': 1002 suppress_prompt = B_TRUE; 1003 break; 1004 default: 1005 usage(); 1006 return (1); 1007 } 1008 } 1009 1010 argc -= optind; 1011 argv += optind; 1012 1013 if (argc != 1) { 1014 usage(); 1015 return (1); 1016 } 1017 1018 be_name = argv[0]; 1019 if (!suppress_prompt && !confirm_destroy(be_name)) { 1020 (void) printf(_("%s has not been destroyed.\n"), be_name); 1021 return (0); 1022 } 1023 1024 if ((snap_name = strrchr(be_name, '@')) != NULL) { 1025 if (snap_name[1] == '\0') { 1026 usage(); 1027 return (1); 1028 } 1029 1030 is_snap = B_TRUE; 1031 *snap_name = '\0'; 1032 snap_name++; 1033 } 1034 1035 if (be_nvl_alloc(&be_attrs) != 0) 1036 return (1); 1037 1038 1039 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0) 1040 goto out; 1041 1042 if (is_snap) { 1043 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, 1044 snap_name) != 0) 1045 goto out; 1046 1047 err = be_destroy_snapshot(be_attrs); 1048 } else { 1049 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS, 1050 destroy_flags) != 0) 1051 goto out; 1052 1053 err = be_destroy(be_attrs); 1054 } 1055 1056 switch (err) { 1057 case BE_SUCCESS: 1058 (void) printf(_("Destroyed successfully\n")); 1059 break; 1060 case BE_ERR_MOUNTED: 1061 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1062 (void) fprintf(stderr, _("It is currently mounted and must be " 1063 "unmounted before it can be destroyed.\n" "Use 'beadm " 1064 "unmount %s' to unmount the BE before destroying\nit or " 1065 "'beadm destroy -f %s'.\n"), be_name, be_name); 1066 break; 1067 case BE_ERR_DESTROY_CURR_BE: 1068 (void) fprintf(stderr, _("%s is the currently active BE and " 1069 "cannot be destroyed.\nYou must boot from another BE in " 1070 "order to destroy %s.\n"), be_name, be_name); 1071 break; 1072 case BE_ERR_ZONES_UNMOUNT: 1073 (void) fprintf(stderr, _("Unable to destroy one of " "%s's " 1074 "zone BE's.\nUse 'beadm destroy -f %s' or " 1075 "'zfs -f destroy <dataset>'.\n"), be_name, be_name); 1076 break; 1077 case BE_ERR_SS_NOENT: 1078 (void) fprintf(stderr, _("%s does not exist or appear " 1079 "to be a valid snapshot.\nPlease check that the name of " 1080 "the snapshot provided is correct.\n"), snap_name); 1081 break; 1082 case BE_ERR_PERM: 1083 case BE_ERR_ACCESS: 1084 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1085 (void) fprintf(stderr, _("You have insufficient privileges to " 1086 "execute this command.\n")); 1087 break; 1088 case BE_ERR_SS_EXISTS: 1089 (void) fprintf(stderr, _("Unable to destroy %s: " 1090 "BE has snapshots.\nUse 'beadm destroy -s %s' or " 1091 "'zfs -r destroy <dataset>'.\n"), be_name, be_name); 1092 break; 1093 default: 1094 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); 1095 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1096 } 1097 1098 out: 1099 nvlist_free(be_attrs); 1100 return (err); 1101 } 1102 1103 static int 1104 be_do_list(int argc, char **argv) 1105 { 1106 be_node_list_t *be_nodes = NULL; 1107 boolean_t all = B_FALSE; 1108 boolean_t dsets = B_FALSE; 1109 boolean_t snaps = B_FALSE; 1110 boolean_t parsable = B_FALSE; 1111 int err = 1; 1112 int c = 0; 1113 char *be_name = NULL; 1114 be_sort_t order = BE_SORT_UNSPECIFIED; 1115 1116 while ((c = getopt(argc, argv, "adk:svHK:")) != -1) { 1117 switch (c) { 1118 case 'a': 1119 all = B_TRUE; 1120 break; 1121 case 'd': 1122 dsets = B_TRUE; 1123 break; 1124 case 'k': 1125 case 'K': 1126 if (order != BE_SORT_UNSPECIFIED) { 1127 (void) fprintf(stderr, _("Sort key can be " 1128 "specified only once.\n")); 1129 usage(); 1130 return (1); 1131 } 1132 if (strcmp(optarg, "date") == 0) { 1133 if (c == 'k') 1134 order = BE_SORT_DATE; 1135 else 1136 order = BE_SORT_DATE_REV; 1137 break; 1138 } 1139 if (strcmp(optarg, "name") == 0) { 1140 if (c == 'k') 1141 order = BE_SORT_NAME; 1142 else 1143 order = BE_SORT_NAME_REV; 1144 break; 1145 } 1146 if (strcmp(optarg, "space") == 0) { 1147 if (c == 'k') 1148 order = BE_SORT_SPACE; 1149 else 1150 order = BE_SORT_SPACE_REV; 1151 break; 1152 } 1153 (void) fprintf(stderr, _("Unknown sort key: %s\n"), 1154 optarg); 1155 usage(); 1156 return (1); 1157 case 's': 1158 snaps = B_TRUE; 1159 break; 1160 case 'v': 1161 libbe_print_errors(B_TRUE); 1162 break; 1163 case 'H': 1164 parsable = B_TRUE; 1165 break; 1166 default: 1167 usage(); 1168 return (1); 1169 } 1170 } 1171 1172 if (all) { 1173 if (dsets) { 1174 (void) fprintf(stderr, _("Invalid options: -a and %s " 1175 "are mutually exclusive.\n"), "-d"); 1176 usage(); 1177 return (1); 1178 } 1179 if (snaps) { 1180 (void) fprintf(stderr, _("Invalid options: -a and %s " 1181 "are mutually exclusive.\n"), "-s"); 1182 usage(); 1183 return (1); 1184 } 1185 1186 dsets = B_TRUE; 1187 snaps = B_TRUE; 1188 } 1189 1190 argc -= optind; 1191 argv += optind; 1192 1193 1194 if (argc == 1) 1195 be_name = argv[0]; 1196 1197 err = be_list(be_name, &be_nodes, 1198 snaps ? BE_LIST_SNAPSHOTS : BE_LIST_DEFAULT); 1199 1200 switch (err) { 1201 case BE_SUCCESS: 1202 /* the default sort is ascending date, no need to sort twice */ 1203 if (order == BE_SORT_UNSPECIFIED) 1204 order = BE_SORT_DATE; 1205 1206 if (order != BE_SORT_DATE) { 1207 err = be_sort(&be_nodes, order); 1208 if (err != BE_SUCCESS) { 1209 (void) fprintf(stderr, _("Unable to sort Boot " 1210 "Environment\n")); 1211 (void) fprintf(stderr, "%s\n", 1212 be_err_to_str(err)); 1213 break; 1214 } 1215 } 1216 1217 print_nodes(be_name, dsets, snaps, parsable, be_nodes); 1218 break; 1219 case BE_ERR_BE_NOENT: 1220 if (be_name == NULL) 1221 (void) fprintf(stderr, _("No boot environments found " 1222 "on this system.\n")); 1223 else { 1224 (void) fprintf(stderr, _("%s does not exist or appear " 1225 "to be a valid BE.\nPlease check that the name of " 1226 "the BE provided is correct.\n"), be_name); 1227 } 1228 break; 1229 default: 1230 (void) fprintf(stderr, _("Unable to display Boot " 1231 "Environment\n")); 1232 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1233 } 1234 1235 if (be_nodes != NULL) 1236 be_free_list(be_nodes); 1237 return (err); 1238 } 1239 1240 static int 1241 be_do_mount(int argc, char **argv) 1242 { 1243 nvlist_t *be_attrs; 1244 boolean_t shared_fs = B_FALSE; 1245 int err = 1; 1246 int c; 1247 int mount_flags = 0; 1248 char *obe_name; 1249 char *mountpoint; 1250 char *tmp_mp = NULL; 1251 1252 while ((c = getopt(argc, argv, "s:v")) != -1) { 1253 switch (c) { 1254 case 's': 1255 shared_fs = B_TRUE; 1256 1257 mount_flags |= BE_MOUNT_FLAG_SHARED_FS; 1258 1259 if (strcmp(optarg, "rw") == 0) { 1260 mount_flags |= BE_MOUNT_FLAG_SHARED_RW; 1261 } else if (strcmp(optarg, "ro") != 0) { 1262 (void) fprintf(stderr, _("The -s flag " 1263 "requires an argument [ rw | ro ]\n")); 1264 usage(); 1265 return (1); 1266 } 1267 1268 break; 1269 case 'v': 1270 libbe_print_errors(B_TRUE); 1271 break; 1272 default: 1273 usage(); 1274 return (1); 1275 } 1276 } 1277 1278 argc -= optind; 1279 argv += optind; 1280 1281 if (argc < 1 || argc > 2) { 1282 usage(); 1283 return (1); 1284 } 1285 1286 obe_name = argv[0]; 1287 1288 if (argc == 2) { 1289 mountpoint = argv[1]; 1290 if (mountpoint[0] != '/') { 1291 (void) fprintf(stderr, _("Invalid mount point %s. " 1292 "Mount point must start with a /.\n"), mountpoint); 1293 return (1); 1294 } 1295 } else { 1296 const char *tmpdir = getenv("TMPDIR"); 1297 const char *tmpname = "tmp.XXXXXX"; 1298 int sz; 1299 1300 if (tmpdir == NULL) 1301 tmpdir = "/tmp"; 1302 1303 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname); 1304 if (sz < 0) { 1305 (void) fprintf(stderr, _("internal error: " 1306 "out of memory\n")); 1307 return (1); 1308 } 1309 1310 mountpoint = mkdtemp(tmp_mp); 1311 } 1312 1313 if (be_nvl_alloc(&be_attrs) != 0) 1314 return (1); 1315 1316 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1317 goto out; 1318 1319 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0) 1320 goto out; 1321 1322 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS, 1323 mount_flags) != 0) 1324 goto out; 1325 1326 err = be_mount(be_attrs); 1327 1328 switch (err) { 1329 case BE_SUCCESS: 1330 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint); 1331 break; 1332 case BE_ERR_BE_NOENT: 1333 (void) fprintf(stderr, _("%s does not exist or appear " 1334 "to be a valid BE.\nPlease check that the name of " 1335 "the BE provided is correct.\n"), obe_name); 1336 break; 1337 case BE_ERR_MOUNTED: 1338 (void) fprintf(stderr, _("%s is already mounted.\n" 1339 "Please unmount the BE before mounting it again.\n"), 1340 obe_name); 1341 break; 1342 case BE_ERR_PERM: 1343 case BE_ERR_ACCESS: 1344 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1345 (void) fprintf(stderr, _("You have insufficient privileges to " 1346 "execute this command.\n")); 1347 break; 1348 case BE_ERR_NO_MOUNTED_ZONE: 1349 (void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount " 1350 "one of %s's zone BE's.\n"), mountpoint, obe_name); 1351 break; 1352 default: 1353 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); 1354 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1355 } 1356 1357 out: 1358 if (tmp_mp != NULL) 1359 free(tmp_mp); 1360 nvlist_free(be_attrs); 1361 return (err); 1362 } 1363 1364 static int 1365 be_do_unmount(int argc, char **argv) 1366 { 1367 nvlist_t *be_attrs; 1368 char *obe_name; 1369 int err = 1; 1370 int c; 1371 int unmount_flags = 0; 1372 1373 while ((c = getopt(argc, argv, "fv")) != -1) { 1374 switch (c) { 1375 case 'f': 1376 unmount_flags |= BE_UNMOUNT_FLAG_FORCE; 1377 break; 1378 case 'v': 1379 libbe_print_errors(B_TRUE); 1380 break; 1381 default: 1382 usage(); 1383 return (1); 1384 } 1385 } 1386 1387 argc -= optind; 1388 argv += optind; 1389 1390 if (argc != 1) { 1391 usage(); 1392 return (1); 1393 } 1394 1395 obe_name = argv[0]; 1396 1397 if (be_nvl_alloc(&be_attrs) != 0) 1398 return (1); 1399 1400 1401 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1402 goto out; 1403 1404 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, 1405 unmount_flags) != 0) 1406 goto out; 1407 1408 err = be_unmount(be_attrs); 1409 1410 switch (err) { 1411 case BE_SUCCESS: 1412 (void) printf(_("Unmounted successfully\n")); 1413 break; 1414 case BE_ERR_BE_NOENT: 1415 (void) fprintf(stderr, _("%s does not exist or appear " 1416 "to be a valid BE.\nPlease check that the name of " 1417 "the BE provided is correct.\n"), obe_name); 1418 break; 1419 case BE_ERR_UMOUNT_CURR_BE: 1420 (void) fprintf(stderr, _("%s is the currently active BE.\n" 1421 "It cannot be unmounted unless another BE is the " 1422 "currently active BE.\n"), obe_name); 1423 break; 1424 case BE_ERR_UMOUNT_SHARED: 1425 (void) fprintf(stderr, _("%s is a shared file system and it " 1426 "cannot be unmounted.\n"), obe_name); 1427 break; 1428 case BE_ERR_PERM: 1429 case BE_ERR_ACCESS: 1430 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1431 (void) fprintf(stderr, _("You have insufficient privileges to " 1432 "execute this command.\n")); 1433 break; 1434 default: 1435 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); 1436 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1437 } 1438 1439 out: 1440 nvlist_free(be_attrs); 1441 return (err); 1442 } 1443 1444 static int 1445 be_do_rename(int argc, char **argv) 1446 { 1447 nvlist_t *be_attrs; 1448 char *obe_name; 1449 char *nbe_name; 1450 int err = 1; 1451 int c; 1452 1453 while ((c = getopt(argc, argv, "v")) != -1) { 1454 switch (c) { 1455 case 'v': 1456 libbe_print_errors(B_TRUE); 1457 break; 1458 default: 1459 usage(); 1460 return (1); 1461 } 1462 } 1463 1464 argc -= optind; 1465 argv += optind; 1466 1467 if (argc != 2) { 1468 usage(); 1469 return (1); 1470 } 1471 1472 obe_name = argv[0]; 1473 nbe_name = argv[1]; 1474 1475 if (be_nvl_alloc(&be_attrs) != 0) 1476 return (1); 1477 1478 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1479 goto out; 1480 1481 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0) 1482 goto out; 1483 1484 err = be_rename(be_attrs); 1485 1486 switch (err) { 1487 case BE_SUCCESS: 1488 (void) printf(_("Renamed successfully\n")); 1489 break; 1490 case BE_ERR_BE_NOENT: 1491 (void) fprintf(stderr, _("%s does not exist or appear " 1492 "to be a valid BE.\nPlease check that the name of " 1493 "the BE provided is correct.\n"), obe_name); 1494 break; 1495 case BE_ERR_PERM: 1496 case BE_ERR_ACCESS: 1497 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1498 obe_name); 1499 (void) fprintf(stderr, _("You have insufficient privileges to " 1500 "execute this command.\n")); 1501 break; 1502 default: 1503 (void) fprintf(stderr, _("Rename of BE %s failed.\n"), 1504 obe_name); 1505 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1506 } 1507 1508 out: 1509 nvlist_free(be_attrs); 1510 return (err); 1511 } 1512 1513 static int 1514 be_do_rollback(int argc, char **argv) 1515 { 1516 nvlist_t *be_attrs; 1517 char *obe_name; 1518 char *snap_name; 1519 int err = 1; 1520 int c; 1521 1522 while ((c = getopt(argc, argv, "v")) != -1) { 1523 switch (c) { 1524 case 'v': 1525 libbe_print_errors(B_TRUE); 1526 break; 1527 default: 1528 usage(); 1529 return (1); 1530 } 1531 } 1532 1533 argc -= optind; 1534 argv += optind; 1535 1536 if (argc < 1 || argc > 2) { 1537 usage(); 1538 return (1); 1539 } 1540 1541 obe_name = argv[0]; 1542 if (argc == 2) 1543 snap_name = argv[1]; 1544 else { /* argc == 1 */ 1545 if ((snap_name = strrchr(obe_name, '@')) != NULL) { 1546 if (snap_name[1] == '\0') { 1547 usage(); 1548 return (1); 1549 } 1550 1551 snap_name[0] = '\0'; 1552 snap_name++; 1553 } else { 1554 usage(); 1555 return (1); 1556 } 1557 } 1558 1559 if (be_nvl_alloc(&be_attrs) != 0) 1560 return (1); 1561 1562 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) 1563 goto out; 1564 1565 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) 1566 goto out; 1567 1568 err = be_rollback(be_attrs); 1569 1570 switch (err) { 1571 case BE_SUCCESS: 1572 (void) printf(_("Rolled back successfully\n")); 1573 break; 1574 case BE_ERR_BE_NOENT: 1575 (void) fprintf(stderr, _("%s does not exist or appear " 1576 "to be a valid BE.\nPlease check that the name of " 1577 "the BE provided is correct.\n"), obe_name); 1578 break; 1579 case BE_ERR_SS_NOENT: 1580 (void) fprintf(stderr, _("%s does not exist or appear " 1581 "to be a valid snapshot.\nPlease check that the name of " 1582 "the snapshot provided is correct.\n"), snap_name); 1583 break; 1584 case BE_ERR_PERM: 1585 case BE_ERR_ACCESS: 1586 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1587 "failed.\n"), obe_name, snap_name); 1588 (void) fprintf(stderr, _("You have insufficient privileges to " 1589 "execute this command.\n")); 1590 break; 1591 default: 1592 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " 1593 "failed.\n"), obe_name, snap_name); 1594 (void) fprintf(stderr, "%s\n", be_err_to_str(err)); 1595 } 1596 1597 out: 1598 nvlist_free(be_attrs); 1599 return (err); 1600 } 1601