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 2012 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_active)
 390                         active[ai++] = 'N';
 391                 if (cur_be->be_active_on_boot)
 392                         active[ai] = 'R';
 393 
 394                 nicenum(used, buf, sizeof (buf));
 395                 if (parsable)
 396                         (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
 397                             name,
 398                             cur_be->be_uuid_str,
 399                             active,
 400                             (cur_be->be_mounted ? mntpt: ""),
 401                             used,
 402                             cur_be->be_policy_type,
 403                             creation);
 404                 else
 405                         (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
 406                             hdr->cols[0].width, name,
 407                             hdr->cols[1].width, active,
 408                             hdr->cols[2].width, (cur_be->be_mounted ? mntpt:
 409                             "-"),
 410                             hdr->cols[3].width, buf,
 411                             hdr->cols[4].width, cur_be->be_policy_type,
 412                             hdr->cols[5].width, datetime);
 413         }
 414 }
 415 
 416 static void
 417 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
 418 {
 419         char buf[64];
 420         char datetime[DT_BUF_LEN];
 421         be_snapshot_list_t *snap = NULL;
 422 
 423         for (snap = be->be_node_snapshots; snap != NULL;
 424             snap = snap->be_next_snapshot) {
 425                 char name[ZFS_MAXNAMELEN+1];
 426                 const char *datetime_fmt = "%F %R";
 427                 const char *be_name = be->be_node_name;
 428                 const char *root_ds = be->be_root_ds;
 429                 const char *snap_name = snap->be_snapshot_name;
 430                 char *pos;
 431                 uint64_t used = snap->be_snapshot_space_used;
 432                 time_t creation = snap->be_snapshot_creation;
 433                 struct tm *tm = localtime(&creation);
 434 
 435                 (void) strncpy(name, root_ds, sizeof (name));
 436                 pos = strstr(name, be_name);
 437                 (void) strcpy(pos, snap_name);
 438 
 439                 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
 440                 nicenum(used, buf, sizeof (buf));
 441 
 442                 if (parsable)
 443                         if (hdr->cols[1].width != 0)
 444                                 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
 445                                     be_name,
 446                                     snap_name,
 447                                     "",
 448                                     "",
 449                                     used,
 450                                     be->be_policy_type,
 451                                     creation);
 452                         else
 453                                 (void) printf("%s;%s;%llu;%s;%ld\n",
 454                                     be_name,
 455                                     snap_name,
 456                                     used,
 457                                     be->be_policy_type,
 458                                     creation);
 459                 else
 460                         if (hdr->cols[1].width != 0)
 461                                 (void) printf("   %-*s %-*s %-*s %-*s %-*s "
 462                                     "%-*s\n",
 463                                     hdr->cols[0].width-3, name,
 464                                     hdr->cols[1].width, "-",
 465                                     hdr->cols[2].width, "-",
 466                                     hdr->cols[3].width, buf,
 467                                     hdr->cols[4].width, be->be_policy_type,
 468                                     hdr->cols[5].width, datetime);
 469                         else
 470                                 (void) printf("   %-*s %-*s %-*s %-*s\n",
 471                                     hdr->cols[0].width-3, snap_name,
 472                                     hdr->cols[3].width, buf,
 473                                     hdr->cols[4].width, be->be_policy_type,
 474                                     hdr->cols[5].width, datetime);
 475         }
 476 }
 477 
 478 static void
 479 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable,
 480     struct hdr_info *hdr, be_node_list_t *nodes)
 481 {
 482         char buf[64];
 483         char datetime[DT_BUF_LEN];
 484         be_node_list_t  *cur_be;
 485 
 486         for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
 487                 char active[3] = "-\0";
 488                 int ai = 0;
 489                 const char *datetime_fmt = "%F %R";
 490                 const char *name = cur_be->be_node_name;
 491                 const char *mntpt = cur_be->be_mntpt;
 492                 uint64_t used = cur_be->be_space_used;
 493                 time_t creation = cur_be->be_node_creation;
 494                 struct tm *tm;
 495 
 496                 if (be_name != NULL && strcmp(be_name, name) != 0)
 497                         continue;
 498 
 499                 if (!parsable)
 500                         (void) printf("%-s\n", name);
 501                 else
 502                         active[0] = '\0';
 503 
 504                 tm = localtime(&creation);
 505                 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
 506 
 507                 if (cur_be->be_active)
 508                         active[ai++] = 'N';
 509                 if (cur_be->be_active_on_boot)
 510                         active[ai] = 'R';
 511 
 512                 nicenum(used, buf, sizeof (buf));
 513                 if (be_fmt & BE_FMT_DATASET)
 514                         if (parsable)
 515                                 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
 516                                     cur_be->be_node_name,
 517                                     cur_be->be_root_ds,
 518                                     active,
 519                                     (cur_be->be_mounted ? mntpt: ""),
 520                                     used,
 521                                     cur_be->be_policy_type,
 522                                     creation);
 523                         else
 524                                 (void) printf("   %-*s %-*s %-*s %-*s %-*s "
 525                                     "%-*s\n",
 526                                     hdr->cols[0].width-3, cur_be->be_root_ds,
 527                                     hdr->cols[1].width, active,
 528                                     hdr->cols[2].width, (cur_be->be_mounted ?
 529                                     mntpt: "-"),
 530                                     hdr->cols[3].width, buf,
 531                                     hdr->cols[4].width, cur_be->be_policy_type,
 532                                     hdr->cols[5].width, datetime);
 533 
 534                 if (be_fmt & BE_FMT_SNAPSHOT)
 535                         print_be_snapshots(cur_be, hdr, parsable);
 536         }
 537 }
 538 
 539 static void
 540 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
 541     boolean_t parsable, be_node_list_t *be_nodes)
 542 {
 543         struct hdr_info hdr;
 544         enum be_fmt be_fmt  = BE_FMT_DEFAULT;
 545 
 546         if (dsets)
 547                 be_fmt |= BE_FMT_DATASET;
 548         if (snaps)
 549                 be_fmt |= BE_FMT_SNAPSHOT;
 550 
 551         if (!parsable) {
 552                 init_hdr_cols(be_fmt, &hdr);
 553                 count_widths(be_fmt, &hdr, be_nodes);
 554                 print_hdr(&hdr);
 555         }
 556 
 557         if (be_fmt == BE_FMT_DEFAULT)
 558                 print_be_nodes(be_name, parsable, &hdr, be_nodes);
 559         else
 560                 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
 561 }
 562 
 563 static boolean_t
 564 confirm_destroy(const char *name)
 565 {
 566         boolean_t res = B_FALSE;
 567         const char *yesre = nl_langinfo(YESEXPR);
 568         const char *nore = nl_langinfo(NOEXPR);
 569         regex_t yes_re;
 570         regex_t no_re;
 571         char buf[128];
 572         char *answer;
 573         int cflags = REG_EXTENDED;
 574 
 575         if (regcomp(&yes_re, yesre, cflags) != 0) {
 576                 /* should not happen */
 577                 (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n"));
 578                 return (res);
 579         }
 580         if (regcomp(&no_re, nore, cflags) != 0) {
 581                 /* should not happen */
 582                 (void) fprintf(stderr, _("Failed to compile 'no' regexp\n"));
 583                 regfree(&yes_re);
 584                 return (res);
 585         }
 586 
 587         (void) printf(_("Are you sure you want to destroy %s?\n"
 588             "This action cannot be undone (y/[n]): "), name);
 589 
 590         answer = fgets(buf, sizeof (buf), stdin);
 591         if (answer == NULL || *answer == '\0' || *answer == 10)
 592                 goto out;
 593 
 594         if (regexec(&yes_re, answer, 0, NULL, 0) == 0) {
 595                 res = B_TRUE;
 596         } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) {
 597                 (void) fprintf(stderr, _("Invalid response. "
 598                     "Please enter 'y' or 'n'.\n"));
 599         }
 600 
 601 out:
 602         regfree(&yes_re);
 603         regfree(&no_re);
 604         return (res);
 605 }
 606 
 607 static int
 608 be_nvl_alloc(nvlist_t **nvlp)
 609 {
 610         assert(nvlp != NULL);
 611 
 612         if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) {
 613                 (void) perror(_("nvlist_alloc failed.\n"));
 614                 return (1);
 615         }
 616 
 617         return (0);
 618 }
 619 
 620 static int
 621 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
 622 {
 623         assert(nvl != NULL);
 624 
 625         if (nvlist_add_string(nvl, name, val) != 0) {
 626                 (void) fprintf(stderr, _("nvlist_add_string failed for "
 627                     "%s (%s).\n"), name, val);
 628                 return (1);
 629         }
 630 
 631         return (0);
 632 }
 633 
 634 static int
 635 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
 636 {
 637         assert(nvl != NULL);
 638 
 639         if (nvlist_add_nvlist(nvl, name, val) != 0) {
 640                 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
 641                     name);
 642                 return (1);
 643         }
 644 
 645         return (0);
 646 }
 647 
 648 static int
 649 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
 650 {
 651         assert(nvl != NULL);
 652 
 653         if (nvlist_add_uint16(nvl, name, val) != 0) {
 654                 (void) fprintf(stderr, _("nvlist_add_uint16 failed for "
 655                     "%s (%hu).\n"), name, val);
 656                 return (1);
 657         }
 658 
 659         return (0);
 660 }
 661 
 662 static int
 663 be_do_activate(int argc, char **argv)
 664 {
 665         nvlist_t        *be_attrs;
 666         int             err = 1;
 667         int             c;
 668         char            *obe_name;
 669 
 670         while ((c = getopt(argc, argv, "v")) != -1) {
 671                 switch (c) {
 672                 case 'v':
 673                         libbe_print_errors(B_TRUE);
 674                         break;
 675                 default:
 676                         usage();
 677                         return (1);
 678                 }
 679         }
 680 
 681         argc -= optind;
 682         argv += optind;
 683 
 684         if (argc != 1) {
 685                 usage();
 686                 return (1);
 687         }
 688 
 689         obe_name = argv[0];
 690 
 691         if (be_nvl_alloc(&be_attrs) != 0)
 692                 return (1);
 693 
 694         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
 695                 goto out;
 696 
 697         err = be_activate(be_attrs);
 698 
 699         switch (err) {
 700         case BE_SUCCESS:
 701                 (void) printf(_("Activated successfully\n"));
 702                 break;
 703         case BE_ERR_BE_NOENT:
 704                 (void) fprintf(stderr, _("%s does not exist or appear "
 705                     "to be a valid BE.\nPlease check that the name of "
 706                     "the BE provided is correct.\n"), obe_name);
 707                 break;
 708         case BE_ERR_PERM:
 709         case BE_ERR_ACCESS:
 710                 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
 711                 (void) fprintf(stderr, _("You have insufficient privileges to "
 712                     "execute this command.\n"));
 713                 break;
 714         case BE_ERR_ACTIVATE_CURR:
 715         default:
 716                 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
 717                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
 718         }
 719 
 720 out:
 721         nvlist_free(be_attrs);
 722         return (err);
 723 }
 724 
 725 static int
 726 be_do_create(int argc, char **argv)
 727 {
 728         nvlist_t        *be_attrs;
 729         nvlist_t        *zfs_props = NULL;
 730         boolean_t       activate = B_FALSE;
 731         boolean_t       is_snap = B_FALSE;
 732         int             c;
 733         int             err = 1;
 734         char            *obe_name = NULL;
 735         char            *snap_name = NULL;
 736         char            *nbe_zpool = NULL;
 737         char            *nbe_name = NULL;
 738         char            *nbe_desc = NULL;
 739         char            *propname = NULL;
 740         char            *propval = NULL;
 741         char            *strval = NULL;
 742 
 743         while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
 744                 switch (c) {
 745                 case 'a':
 746                         activate = B_TRUE;
 747                         break;
 748                 case 'd':
 749                         nbe_desc = optarg;
 750                         break;
 751                 case 'e':
 752                         obe_name = optarg;
 753                         break;
 754                 case 'o':
 755                         if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
 756                                 return (1);
 757 
 758                         propname = optarg;
 759                         if ((propval = strchr(propname, '=')) == NULL) {
 760                                 (void) fprintf(stderr, _("missing "
 761                                     "'=' for -o option\n"));
 762                                 goto out2;
 763                         }
 764                         *propval = '\0';
 765                         propval++;
 766                         if (nvlist_lookup_string(zfs_props, propname,
 767                             &strval) == 0) {
 768                                 (void) fprintf(stderr, _("property '%s' "
 769                                     "specified multiple times\n"), propname);
 770                                 goto out2;
 771 
 772                         }
 773                         if (be_nvl_add_string(zfs_props, propname, propval)
 774                             != 0)
 775                                 goto out2;
 776 
 777                         break;
 778                 case 'p':
 779                         nbe_zpool = optarg;
 780                         break;
 781                 case 'v':
 782                         libbe_print_errors(B_TRUE);
 783                         break;
 784                 default:
 785                         usage();
 786                         goto out2;
 787                 }
 788         }
 789 
 790         argc -= optind;
 791         argv += optind;
 792 
 793         if (argc != 1) {
 794                 usage();
 795                 goto out2;
 796         }
 797 
 798         nbe_name = argv[0];
 799 
 800         if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
 801                 if (snap_name[1] == '\0') {
 802                         usage();
 803                         goto out2;
 804                 }
 805 
 806                 snap_name[0] = '\0';
 807                 snap_name++;
 808                 is_snap = B_TRUE;
 809         }
 810 
 811         if (obe_name) {
 812                 if (is_snap) {
 813                         usage();
 814                         goto out2;
 815                 }
 816 
 817                 /*
 818                  * Check if obe_name is really a snapshot name.
 819                  * If so, split it out.
 820                  */
 821                 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
 822                         if (snap_name[1] == '\0') {
 823                                 usage();
 824                                 goto out2;
 825                         }
 826 
 827                         snap_name[0] = '\0';
 828                         snap_name++;
 829                 }
 830         } else if (is_snap) {
 831                 obe_name = nbe_name;
 832                 nbe_name = NULL;
 833         }
 834 
 835         if (be_nvl_alloc(&be_attrs) != 0)
 836                 goto out2;
 837 
 838 
 839         if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
 840             BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
 841                 goto out;
 842 
 843         if (obe_name != NULL && be_nvl_add_string(be_attrs,
 844             BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
 845                 goto out;
 846 
 847         if (snap_name != NULL && be_nvl_add_string(be_attrs,
 848             BE_ATTR_SNAP_NAME, snap_name) != 0)
 849                 goto out;
 850 
 851         if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
 852             BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
 853                 goto out;
 854 
 855         if (nbe_name != NULL && be_nvl_add_string(be_attrs,
 856             BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
 857                 goto out;
 858 
 859         if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
 860             BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
 861                 goto out;
 862 
 863         if (is_snap)
 864                 err = be_create_snapshot(be_attrs);
 865         else
 866                 err = be_copy(be_attrs);
 867 
 868         switch (err) {
 869         case BE_SUCCESS:
 870                 if (!is_snap && !nbe_name) {
 871                         /*
 872                          * We requested an auto named BE; find out the
 873                          * name of the BE that was created for us and
 874                          * the auto snapshot created from the original BE.
 875                          */
 876                         if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
 877                             &nbe_name) != 0) {
 878                                 (void) fprintf(stderr, _("failed to get %s "
 879                                     "attribute\n"), BE_ATTR_NEW_BE_NAME);
 880                                 break;
 881                         } else
 882                                 (void) printf(_("Auto named BE: %s\n"),
 883                                     nbe_name);
 884 
 885                         if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
 886                             &snap_name) != 0) {
 887                                 (void) fprintf(stderr, _("failed to get %s "
 888                                     "attribute\n"), BE_ATTR_SNAP_NAME);
 889                                 break;
 890                         } else
 891                                 (void) printf(_("Auto named snapshot: %s\n"),
 892                                     snap_name);
 893                 }
 894 
 895                 if (!is_snap && activate) {
 896                         char *args[] = { "activate", "", NULL };
 897                         args[1] = nbe_name;
 898                         optind = 1;
 899 
 900                         err = be_do_activate(2, args);
 901                         goto out;
 902                 }
 903 
 904                 (void) printf(_("Created successfully\n"));
 905                 break;
 906         case BE_ERR_BE_EXISTS:
 907                 (void) fprintf(stderr, _("BE %s already exists\n."
 908                     "Please choose a different BE name.\n"), nbe_name);
 909                 break;
 910         case BE_ERR_SS_EXISTS:
 911                 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
 912                     "Please choose a different snapshot name.\n"), obe_name,
 913                     snap_name);
 914                 break;
 915         case BE_ERR_PERM:
 916         case BE_ERR_ACCESS:
 917                 if (is_snap)
 918                         (void) fprintf(stderr, _("Unable to create snapshot "
 919                             "%s.\n"), snap_name);
 920                 else
 921                         (void) fprintf(stderr, _("Unable to create %s.\n"),
 922                             nbe_name);
 923                 (void) fprintf(stderr, _("You have insufficient privileges to "
 924                     "execute this command.\n"));
 925                 break;
 926         default:
 927                 if (is_snap)
 928                         (void) fprintf(stderr, _("Unable to create snapshot "
 929                             "%s.\n"), snap_name);
 930                 else
 931                         (void) fprintf(stderr, _("Unable to create %s.\n"),
 932                             nbe_name);
 933                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
 934         }
 935 
 936 out:
 937         nvlist_free(be_attrs);
 938 out2:
 939         if (zfs_props != NULL)
 940                 nvlist_free(zfs_props);
 941 
 942         return (err);
 943 }
 944 
 945 static int
 946 be_do_destroy(int argc, char **argv)
 947 {
 948         nvlist_t        *be_attrs;
 949         boolean_t       is_snap = B_FALSE;
 950         boolean_t       suppress_prompt = B_FALSE;
 951         int             err = 1;
 952         int             c;
 953         int             destroy_flags = 0;
 954         char            *snap_name;
 955         char            *be_name;
 956 
 957         while ((c = getopt(argc, argv, "fFsv")) != -1) {
 958                 switch (c) {
 959                 case 'f':
 960                         destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
 961                         break;
 962                 case 's':
 963                         destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
 964                         break;
 965                 case 'v':
 966                         libbe_print_errors(B_TRUE);
 967                         break;
 968                 case 'F':
 969                         suppress_prompt = B_TRUE;
 970                         break;
 971                 default:
 972                         usage();
 973                         return (1);
 974                 }
 975         }
 976 
 977         argc -= optind;
 978         argv += optind;
 979 
 980         if (argc != 1) {
 981                 usage();
 982                 return (1);
 983         }
 984 
 985         be_name = argv[0];
 986         if (!suppress_prompt && !confirm_destroy(be_name)) {
 987                 (void) printf(_("%s has not been destroyed.\n"), be_name);
 988                 return (0);
 989         }
 990 
 991         if ((snap_name = strrchr(be_name, '@')) != NULL) {
 992                 if (snap_name[1] == '\0') {
 993                         usage();
 994                         return (1);
 995                 }
 996 
 997                 is_snap = B_TRUE;
 998                 *snap_name = '\0';
 999                 snap_name++;
1000         }
1001 
1002         if (be_nvl_alloc(&be_attrs) != 0)
1003                 return (1);
1004 
1005 
1006         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
1007                 goto out;
1008 
1009         if (is_snap) {
1010                 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
1011                     snap_name) != 0)
1012                         goto out;
1013 
1014                 err = be_destroy_snapshot(be_attrs);
1015         } else {
1016                 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
1017                     destroy_flags) != 0)
1018                         goto out;
1019 
1020                 err = be_destroy(be_attrs);
1021         }
1022 
1023         switch (err) {
1024         case BE_SUCCESS:
1025                 (void) printf(_("Destroyed successfully\n"));
1026                 break;
1027         case BE_ERR_MOUNTED:
1028                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1029                 (void) fprintf(stderr, _("It is currently mounted and must be "
1030                     "unmounted before it can be destroyed.\n" "Use 'beadm "
1031                     "unmount %s' to unmount the BE before destroying\nit or "
1032                     "'beadm destroy -f %s'.\n"), be_name, be_name);
1033                 break;
1034         case BE_ERR_DESTROY_CURR_BE:
1035                 (void) fprintf(stderr, _("%s is the currently active BE and "
1036                     "cannot be destroyed.\nYou must boot from another BE in "
1037                     "order to destroy %s.\n"), be_name, be_name);
1038                 break;
1039         case BE_ERR_ZONES_UNMOUNT:
1040                 (void) fprintf(stderr, _("Unable to destroy one of " "%s's "
1041                     "zone BE's.\nUse 'beadm destroy -f %s' or "
1042                     "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
1043                 break;
1044         case BE_ERR_SS_NOENT:
1045                 (void) fprintf(stderr, _("%s does not exist or appear "
1046                     "to be a valid snapshot.\nPlease check that the name of "
1047                     "the snapshot provided is correct.\n"), snap_name);
1048                 break;
1049         case BE_ERR_PERM:
1050         case BE_ERR_ACCESS:
1051                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1052                 (void) fprintf(stderr, _("You have insufficient privileges to "
1053                     "execute this command.\n"));
1054                 break;
1055         case BE_ERR_SS_EXISTS:
1056                 (void) fprintf(stderr, _("Unable to destroy %s: "
1057                     "BE has snapshots.\nUse 'beadm destroy -s %s' or "
1058                     "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
1059                 break;
1060         default:
1061                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1062                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1063         }
1064 
1065 out:
1066         nvlist_free(be_attrs);
1067         return (err);
1068 }
1069 
1070 static int
1071 be_do_list(int argc, char **argv)
1072 {
1073         be_node_list_t  *be_nodes = NULL;
1074         boolean_t       all = B_FALSE;
1075         boolean_t       dsets = B_FALSE;
1076         boolean_t       snaps = B_FALSE;
1077         boolean_t       parsable = B_FALSE;
1078         int             err = 1;
1079         int             c = 0;
1080         char            *be_name = NULL;
1081 
1082         while ((c = getopt(argc, argv, "adsvH")) != -1) {
1083                 switch (c) {
1084                 case 'a':
1085                         all = B_TRUE;
1086                         break;
1087                 case 'd':
1088                         dsets = B_TRUE;
1089                         break;
1090                 case 's':
1091                         snaps = B_TRUE;
1092                         break;
1093                 case 'v':
1094                         libbe_print_errors(B_TRUE);
1095                         break;
1096                 case 'H':
1097                         parsable = B_TRUE;
1098                         break;
1099                 default:
1100                         usage();
1101                         return (1);
1102                 }
1103         }
1104 
1105         if (all) {
1106                 if (dsets) {
1107                         (void) fprintf(stderr, _("Invalid options: -a and %s "
1108                             "are mutually exclusive.\n"), "-d");
1109                         usage();
1110                         return (1);
1111                 }
1112                 if (snaps) {
1113                         (void) fprintf(stderr, _("Invalid options: -a and %s "
1114                             "are mutually exclusive.\n"), "-s");
1115                         usage();
1116                         return (1);
1117                 }
1118 
1119                 dsets = B_TRUE;
1120                 snaps = B_TRUE;
1121         }
1122 
1123         argc -= optind;
1124         argv += optind;
1125 
1126 
1127         if (argc == 1)
1128                 be_name = argv[0];
1129 
1130         err = be_list(be_name, &be_nodes);
1131 
1132         switch (err) {
1133         case BE_SUCCESS:
1134                 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1135                 break;
1136         case BE_ERR_BE_NOENT:
1137                 if (be_name == NULL)
1138                         (void) fprintf(stderr, _("No boot environments found "
1139                             "on this system.\n"));
1140                 else {
1141                         (void) fprintf(stderr, _("%s does not exist or appear "
1142                             "to be a valid BE.\nPlease check that the name of "
1143                             "the BE provided is correct.\n"), be_name);
1144                 }
1145                 break;
1146         default:
1147                 (void) fprintf(stderr, _("Unable to display Boot "
1148                     "Environment\n"));
1149                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1150         }
1151 
1152         if (be_nodes != NULL)
1153                 be_free_list(be_nodes);
1154         return (err);
1155 }
1156 
1157 static int
1158 be_do_mount(int argc, char **argv)
1159 {
1160         nvlist_t        *be_attrs;
1161         boolean_t       shared_fs = B_FALSE;
1162         int             err = 1;
1163         int             c;
1164         int             mount_flags = 0;
1165         char            *obe_name;
1166         char            *mountpoint;
1167         char            *tmp_mp = NULL;
1168 
1169         while ((c = getopt(argc, argv, "s:v")) != -1) {
1170                 switch (c) {
1171                 case 's':
1172                         shared_fs = B_TRUE;
1173 
1174                         mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1175 
1176                         if (strcmp(optarg, "rw") == 0) {
1177                                 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1178                         } else if (strcmp(optarg, "ro") != 0) {
1179                                 (void) fprintf(stderr, _("The -s flag "
1180                                     "requires an argument [ rw | ro ]\n"));
1181                                 usage();
1182                                 return (1);
1183                         }
1184 
1185                         break;
1186                 case 'v':
1187                         libbe_print_errors(B_TRUE);
1188                         break;
1189                 default:
1190                         usage();
1191                         return (1);
1192                 }
1193         }
1194 
1195         argc -= optind;
1196         argv += optind;
1197 
1198         if (argc < 1 || argc > 2) {
1199                 usage();
1200                 return (1);
1201         }
1202 
1203         obe_name = argv[0];
1204 
1205         if (argc == 2) {
1206                 mountpoint = argv[1];
1207                 if (mountpoint[0] != '/') {
1208                         (void) fprintf(stderr, _("Invalid mount point %s. "
1209                             "Mount point must start with a /.\n"), mountpoint);
1210                         return (1);
1211                 }
1212         } else {
1213                 const char *tmpdir = getenv("TMPDIR");
1214                 const char *tmpname = "tmp.XXXXXX";
1215                 int sz;
1216 
1217                 if (tmpdir == NULL)
1218                         tmpdir = "/tmp";
1219 
1220                 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1221                 if (sz < 0) {
1222                         (void) fprintf(stderr, _("internal error: "
1223                             "out of memory\n"));
1224                         return (1);
1225                 }
1226 
1227                 mountpoint = mkdtemp(tmp_mp);
1228         }
1229 
1230         if (be_nvl_alloc(&be_attrs) != 0)
1231                 return (1);
1232 
1233         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1234                 goto out;
1235 
1236         if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1237                 goto out;
1238 
1239         if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1240             mount_flags) != 0)
1241                 goto out;
1242 
1243         err = be_mount(be_attrs);
1244 
1245         switch (err) {
1246         case BE_SUCCESS:
1247                 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1248                 break;
1249         case BE_ERR_BE_NOENT:
1250                 (void) fprintf(stderr, _("%s does not exist or appear "
1251                     "to be a valid BE.\nPlease check that the name of "
1252                     "the BE provided is correct.\n"), obe_name);
1253                 break;
1254         case BE_ERR_MOUNTED:
1255                 (void) fprintf(stderr, _("%s is already mounted.\n"
1256                     "Please unmount the BE before mounting it again.\n"),
1257                     obe_name);
1258                 break;
1259         case BE_ERR_PERM:
1260         case BE_ERR_ACCESS:
1261                 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1262                 (void) fprintf(stderr, _("You have insufficient privileges to "
1263                     "execute this command.\n"));
1264                 break;
1265         default:
1266                 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1267                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1268         }
1269 
1270 out:
1271         if (tmp_mp != NULL)
1272                 free(tmp_mp);
1273         nvlist_free(be_attrs);
1274         return (err);
1275 }
1276 
1277 static int
1278 be_do_unmount(int argc, char **argv)
1279 {
1280         nvlist_t        *be_attrs;
1281         char            *obe_name;
1282         int             err = 1;
1283         int             c;
1284         int             unmount_flags = 0;
1285 
1286         while ((c = getopt(argc, argv, "fv")) != -1) {
1287                 switch (c) {
1288                 case 'f':
1289                         unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1290                         break;
1291                 case 'v':
1292                         libbe_print_errors(B_TRUE);
1293                         break;
1294                 default:
1295                         usage();
1296                         return (1);
1297                 }
1298         }
1299 
1300         argc -= optind;
1301         argv += optind;
1302 
1303         if (argc != 1) {
1304                 usage();
1305                 return (1);
1306         }
1307 
1308         obe_name = argv[0];
1309 
1310         if (be_nvl_alloc(&be_attrs) != 0)
1311                 return (1);
1312 
1313 
1314         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1315                 goto out;
1316 
1317         if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1318             unmount_flags) != 0)
1319                 goto out;
1320 
1321         err = be_unmount(be_attrs);
1322 
1323         switch (err) {
1324         case BE_SUCCESS:
1325                 (void) printf(_("Unmounted successfully\n"));
1326                 break;
1327         case BE_ERR_BE_NOENT:
1328                 (void) fprintf(stderr, _("%s does not exist or appear "
1329                     "to be a valid BE.\nPlease check that the name of "
1330                     "the BE provided is correct.\n"), obe_name);
1331                 break;
1332         case BE_ERR_UMOUNT_CURR_BE:
1333                 (void) fprintf(stderr, _("%s is the currently active BE.\n"
1334                     "It cannot be unmounted unless another BE is the "
1335                     "currently active BE.\n"), obe_name);
1336                 break;
1337         case BE_ERR_UMOUNT_SHARED:
1338                 (void) fprintf(stderr, _("%s is a shared file system and it "
1339                     "cannot be unmounted.\n"), obe_name);
1340                 break;
1341         case BE_ERR_PERM:
1342         case BE_ERR_ACCESS:
1343                 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1344                 (void) fprintf(stderr, _("You have insufficient privileges to "
1345                     "execute this command.\n"));
1346                 break;
1347         default:
1348                 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1349                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1350         }
1351 
1352 out:
1353         nvlist_free(be_attrs);
1354         return (err);
1355 }
1356 
1357 static int
1358 be_do_rename(int argc, char **argv)
1359 {
1360         nvlist_t        *be_attrs;
1361         char            *obe_name;
1362         char            *nbe_name;
1363         int err = 1;
1364         int c;
1365 
1366         while ((c = getopt(argc, argv, "v")) != -1) {
1367                 switch (c) {
1368                 case 'v':
1369                         libbe_print_errors(B_TRUE);
1370                         break;
1371                 default:
1372                         usage();
1373                         return (1);
1374                 }
1375         }
1376 
1377         argc -= optind;
1378         argv += optind;
1379 
1380         if (argc != 2) {
1381                 usage();
1382                 return (1);
1383         }
1384 
1385         obe_name = argv[0];
1386         nbe_name = argv[1];
1387 
1388         if (be_nvl_alloc(&be_attrs) != 0)
1389                 return (1);
1390 
1391         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1392                 goto out;
1393 
1394         if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1395                 goto out;
1396 
1397         err = be_rename(be_attrs);
1398 
1399         switch (err) {
1400         case BE_SUCCESS:
1401                 (void) printf(_("Renamed successfully\n"));
1402                 break;
1403         case BE_ERR_BE_NOENT:
1404                 (void) fprintf(stderr, _("%s does not exist or appear "
1405                     "to be a valid BE.\nPlease check that the name of "
1406                     "the BE provided is correct.\n"), obe_name);
1407                 break;
1408         case BE_ERR_PERM:
1409         case BE_ERR_ACCESS:
1410                 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1411                     obe_name);
1412                 (void) fprintf(stderr, _("You have insufficient privileges to "
1413                     "execute this command.\n"));
1414                 break;
1415         default:
1416                 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1417                     obe_name);
1418                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1419         }
1420 
1421 out:
1422         nvlist_free(be_attrs);
1423         return (err);
1424 }
1425 
1426 static int
1427 be_do_rollback(int argc, char **argv)
1428 {
1429         nvlist_t        *be_attrs;
1430         char            *obe_name;
1431         char            *snap_name;
1432         int             err = 1;
1433         int             c;
1434 
1435         while ((c = getopt(argc, argv, "v")) != -1) {
1436                 switch (c) {
1437                 case 'v':
1438                         libbe_print_errors(B_TRUE);
1439                         break;
1440                 default:
1441                         usage();
1442                         return (1);
1443                 }
1444         }
1445 
1446         argc -= optind;
1447         argv += optind;
1448 
1449         if (argc < 1 || argc > 2) {
1450                 usage();
1451                 return (1);
1452         }
1453 
1454         obe_name = argv[0];
1455         if (argc == 2)
1456                 snap_name = argv[1];
1457         else { /* argc == 1 */
1458                 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1459                         if (snap_name[1] == '\0') {
1460                                 usage();
1461                                 return (1);
1462                         }
1463 
1464                         snap_name[0] = '\0';
1465                         snap_name++;
1466                 } else {
1467                         usage();
1468                         return (1);
1469                 }
1470         }
1471 
1472         if (be_nvl_alloc(&be_attrs) != 0)
1473                 return (1);
1474 
1475         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1476                 goto out;
1477 
1478         if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1479                 goto out;
1480 
1481         err = be_rollback(be_attrs);
1482 
1483         switch (err) {
1484         case BE_SUCCESS:
1485                 (void) printf(_("Rolled back successfully\n"));
1486                 break;
1487         case BE_ERR_BE_NOENT:
1488                 (void) fprintf(stderr, _("%s does not exist or appear "
1489                     "to be a valid BE.\nPlease check that the name of "
1490                     "the BE provided is correct.\n"), obe_name);
1491                 break;
1492         case BE_ERR_SS_NOENT:
1493                 (void) fprintf(stderr, _("%s does not exist or appear "
1494                     "to be a valid snapshot.\nPlease check that the name of "
1495                     "the snapshot provided is correct.\n"), snap_name);
1496                 break;
1497         case BE_ERR_PERM:
1498         case BE_ERR_ACCESS:
1499                 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1500                     "failed.\n"), obe_name, snap_name);
1501                 (void) fprintf(stderr, _("You have insufficient privileges to "
1502                     "execute this command.\n"));
1503                 break;
1504         default:
1505                 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1506                     "failed.\n"), obe_name, snap_name);
1507                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1508         }
1509 
1510 out:
1511         nvlist_free(be_attrs);
1512         return (err);
1513 }