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