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 beName\n"
 127             "\tbeadm create [-d BE_desc]\n"
 128             "\t\t[-o property=value] ... [-p zpool] \n"
 129             "\t\t[-e nonActiveBe | beName@snapshot] beName\n"
 130             "\tbeadm create [-d BE_desc]\n"
 131             "\t\t[-o property=value] ... [-p zpool] beName@snapshot\n"
 132             "\tbeadm destroy [-Ffs] beName \n"
 133             "\tbeadm destroy [-F] beName@snapshot \n"
 134             "\tbeadm list [[-a] | [-d] [-s]] [-H] [beName]\n"
 135             "\tbeadm mount [-s ro|rw] beName [mountpoint]\n"
 136             "\tbeadm unmount [-f] beName | mountpoint\n"
 137             "\tbeadm umount [-f] beName | mountpoint\n"
 138             "\tbeadm rename origBeName newBeName\n"
 139             "\tbeadm rollback beName snapshot\n"
 140             "\tbeadm rollback 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         char            *obe_name;
 668 
 669         argc -= optind;
 670         argv += optind;
 671 
 672         if (argc != 1) {
 673                 usage();
 674                 return (1);
 675         }
 676 
 677         obe_name = argv[0];
 678 
 679         if (be_nvl_alloc(&be_attrs) != 0)
 680                 return (1);
 681 
 682         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
 683                 goto out;
 684 
 685         err = be_activate(be_attrs);
 686 
 687         switch (err) {
 688         case BE_SUCCESS:
 689                 (void) printf(_("Activated successfully\n"));
 690                 break;
 691         case BE_ERR_BE_NOENT:
 692                 (void) fprintf(stderr, _("%s does not exist or appear "
 693                     "to be a valid BE.\nPlease check that the name of "
 694                     "the BE provided is correct.\n"), obe_name);
 695                 break;
 696         case BE_ERR_PERM:
 697         case BE_ERR_ACCESS:
 698                 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
 699                 (void) fprintf(stderr, _("You have insufficient privileges to "
 700                     "execute this command.\n"));
 701                 break;
 702         case BE_ERR_ACTIVATE_CURR:
 703         default:
 704                 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
 705                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
 706         }
 707 
 708 out:
 709         nvlist_free(be_attrs);
 710         return (err);
 711 }
 712 
 713 static int
 714 be_do_create(int argc, char **argv)
 715 {
 716         nvlist_t        *be_attrs;
 717         nvlist_t        *zfs_props = NULL;
 718         boolean_t       activate = B_FALSE;
 719         boolean_t       is_snap = B_FALSE;
 720         int             c;
 721         int             err = 1;
 722         char            *obe_name = NULL;
 723         char            *snap_name = NULL;
 724         char            *nbe_zpool = NULL;
 725         char            *nbe_name = NULL;
 726         char            *nbe_desc = NULL;
 727         char            *propname = NULL;
 728         char            *propval = NULL;
 729         char            *strval = NULL;
 730 
 731         while ((c = getopt(argc, argv, "ad:e:io:p:")) != -1) {
 732                 switch (c) {
 733                 case 'a':
 734                         activate = B_TRUE;
 735                         break;
 736                 case 'd':
 737                         nbe_desc = optarg;
 738                         break;
 739                 case 'e':
 740                         obe_name = optarg;
 741                         break;
 742                 case 'o':
 743                         if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
 744                                 return (1);
 745 
 746                         propname = optarg;
 747                         if ((propval = strchr(propname, '=')) == NULL) {
 748                                 (void) fprintf(stderr, _("missing "
 749                                     "'=' for -o option\n"));
 750                                 goto out2;
 751                         }
 752                         *propval = '\0';
 753                         propval++;
 754                         if (nvlist_lookup_string(zfs_props, propname,
 755                             &strval) == 0) {
 756                                 (void) fprintf(stderr, _("property '%s' "
 757                                     "specified multiple times\n"), propname);
 758                                 goto out2;
 759 
 760                         }
 761                         if (be_nvl_add_string(zfs_props, propname, propval)
 762                             != 0)
 763                                 goto out2;
 764 
 765                         break;
 766                 case 'p':
 767                         nbe_zpool = optarg;
 768                         break;
 769                 default:
 770                         usage();
 771                         goto out2;
 772                 }
 773         }
 774 
 775         argc -= optind;
 776         argv += optind;
 777 
 778         if (argc != 1) {
 779                 usage();
 780                 goto out2;
 781         }
 782 
 783         nbe_name = argv[0];
 784 
 785         if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
 786                 if (snap_name[1] == '\0') {
 787                         usage();
 788                         goto out2;
 789                 }
 790 
 791                 snap_name[0] = '\0';
 792                 snap_name++;
 793                 is_snap = B_TRUE;
 794         }
 795 
 796         if (obe_name) {
 797                 if (is_snap) {
 798                         usage();
 799                         goto out2;
 800                 }
 801 
 802                 /*
 803                  * Check if obe_name is really a snapshot name.
 804                  * If so, split it out.
 805                  */
 806                 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
 807                         if (snap_name[1] == '\0') {
 808                                 usage();
 809                                 goto out2;
 810                         }
 811 
 812                         snap_name[0] = '\0';
 813                         snap_name++;
 814                 }
 815         } else if (is_snap) {
 816                 obe_name = nbe_name;
 817                 nbe_name = NULL;
 818         }
 819 
 820         if (be_nvl_alloc(&be_attrs) != 0)
 821                 goto out2;
 822 
 823 
 824         if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
 825             BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
 826                 goto out;
 827 
 828         if (obe_name != NULL && be_nvl_add_string(be_attrs,
 829             BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
 830                 goto out;
 831 
 832         if (snap_name != NULL && be_nvl_add_string(be_attrs,
 833             BE_ATTR_SNAP_NAME, snap_name) != 0)
 834                 goto out;
 835 
 836         if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
 837             BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
 838                 goto out;
 839 
 840         if (nbe_name != NULL && be_nvl_add_string(be_attrs,
 841             BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
 842                 goto out;
 843 
 844         if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
 845             BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
 846                 goto out;
 847 
 848         if (is_snap)
 849                 err = be_create_snapshot(be_attrs);
 850         else
 851                 err = be_copy(be_attrs);
 852 
 853         switch (err) {
 854         case BE_SUCCESS:
 855                 if (!is_snap && !nbe_name) {
 856                         /*
 857                          * We requested an auto named BE; find out the
 858                          * name of the BE that was created for us and
 859                          * the auto snapshot created from the original BE.
 860                          */
 861                         if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
 862                             &nbe_name) != 0) {
 863                                 (void) fprintf(stderr, _("failed to get %s "
 864                                     "attribute\n"), BE_ATTR_NEW_BE_NAME);
 865                                 break;
 866                         } else
 867                                 (void) printf(_("Auto named BE: %s\n"),
 868                                     nbe_name);
 869 
 870                         if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
 871                             &snap_name) != 0) {
 872                                 (void) fprintf(stderr, _("failed to get %s "
 873                                     "attribute\n"), BE_ATTR_SNAP_NAME);
 874                                 break;
 875                         } else
 876                                 (void) printf(_("Auto named snapshot: %s\n"),
 877                                     snap_name);
 878                 }
 879 
 880                 if (!is_snap && activate) {
 881                         char *args[] = { "activate", "", NULL };
 882                         args[1] = nbe_name;
 883                         optind = 1;
 884 
 885                         err = be_do_activate(2, args);
 886                         goto out;
 887                 }
 888 
 889                 (void) printf(_("Created successfully\n"));
 890                 break;
 891         case BE_ERR_BE_EXISTS:
 892                 (void) fprintf(stderr, _("BE %s already exists\n."
 893                     "Please choose a different BE name.\n"), nbe_name);
 894                 break;
 895         case BE_ERR_SS_EXISTS:
 896                 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
 897                     "Please choose a different snapshot name.\n"), obe_name,
 898                     snap_name);
 899                 break;
 900         case BE_ERR_PERM:
 901         case BE_ERR_ACCESS:
 902                 if (is_snap)
 903                         (void) fprintf(stderr, _("Unable to create snapshot "
 904                             "%s.\n"), snap_name);
 905                 else
 906                         (void) fprintf(stderr, _("Unable to create %s.\n"),
 907                             nbe_name);
 908                 (void) fprintf(stderr, _("You have insufficient privileges to "
 909                     "execute this command.\n"));
 910                 break;
 911         default:
 912                 if (is_snap)
 913                         (void) fprintf(stderr, _("Unable to create snapshot "
 914                             "%s.\n"), snap_name);
 915                 else
 916                         (void) fprintf(stderr, _("Unable to create %s.\n"),
 917                             nbe_name);
 918                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
 919         }
 920 
 921 out:
 922         nvlist_free(be_attrs);
 923 out2:
 924         if (zfs_props != NULL)
 925                 nvlist_free(zfs_props);
 926 
 927         return (err);
 928 }
 929 
 930 static int
 931 be_do_destroy(int argc, char **argv)
 932 {
 933         nvlist_t        *be_attrs;
 934         boolean_t       is_snap = B_FALSE;
 935         boolean_t       suppress_prompt = B_FALSE;
 936         int             err = 1;
 937         int             c;
 938         int             destroy_flags = 0;
 939         char            *snap_name;
 940         char            *be_name;
 941 
 942         while ((c = getopt(argc, argv, "fFs")) != -1) {
 943                 switch (c) {
 944                 case 'f':
 945                         destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
 946                         break;
 947                 case 's':
 948                         destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
 949                         break;
 950                 case 'F':
 951                         suppress_prompt = B_TRUE;
 952                         break;
 953                 default:
 954                         usage();
 955                         return (1);
 956                 }
 957         }
 958 
 959         argc -= optind;
 960         argv += optind;
 961 
 962         if (argc != 1) {
 963                 usage();
 964                 return (1);
 965         }
 966 
 967         be_name = argv[0];
 968         if (!suppress_prompt && !confirm_destroy(be_name)) {
 969                 (void) printf(_("%s has not been destroyed.\n"), be_name);
 970                 return (0);
 971         }
 972 
 973         if ((snap_name = strrchr(be_name, '@')) != NULL) {
 974                 if (snap_name[1] == '\0') {
 975                         usage();
 976                         return (1);
 977                 }
 978 
 979                 is_snap = B_TRUE;
 980                 *snap_name = '\0';
 981                 snap_name++;
 982         }
 983 
 984         if (be_nvl_alloc(&be_attrs) != 0)
 985                 return (1);
 986 
 987 
 988         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
 989                 goto out;
 990 
 991         if (is_snap) {
 992                 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
 993                     snap_name) != 0)
 994                         goto out;
 995 
 996                 err = be_destroy_snapshot(be_attrs);
 997         } else {
 998                 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
 999                     destroy_flags) != 0)
1000                         goto out;
1001 
1002                 err = be_destroy(be_attrs);
1003         }
1004 
1005         switch (err) {
1006         case BE_SUCCESS:
1007                 (void) printf(_("Destroyed successfully\n"));
1008                 break;
1009         case BE_ERR_MOUNTED:
1010                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1011                 (void) fprintf(stderr, _("It is currently mounted and must be "
1012                     "unmounted before it can be destroyed.\n" "Use 'beadm "
1013                     "unmount %s' to unmount the BE before destroying\nit or "
1014                     "'beadm destroy -f %s'.\n"), be_name, be_name);
1015                 break;
1016         case BE_ERR_DESTROY_CURR_BE:
1017                 (void) fprintf(stderr, _("%s is the currently active BE and "
1018                     "cannot be destroyed.\nYou must boot from another BE in "
1019                     "order to destroy %s.\n"), be_name, be_name);
1020                 break;
1021         case BE_ERR_ZONES_UNMOUNT:
1022                 (void) fprintf(stderr, _("Unable to destroy one of " "%s's "
1023                     "zone BE's.\nUse 'beadm destroy -f %s' or "
1024                     "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
1025                 break;
1026         case BE_ERR_SS_NOENT:
1027                 (void) fprintf(stderr, _("%s does not exist or appear "
1028                     "to be a valid snapshot.\nPlease check that the name of "
1029                     "the snapshot provided is correct.\n"), snap_name);
1030                 break;
1031         case BE_ERR_PERM:
1032         case BE_ERR_ACCESS:
1033                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1034                 (void) fprintf(stderr, _("You have insufficient privileges to "
1035                     "execute this command.\n"));
1036                 break;
1037         case BE_ERR_SS_EXISTS:
1038                 (void) fprintf(stderr, _("Unable to destroy %s: "
1039                     "BE has snapshots.\nUse 'beadm destroy -s %s' or "
1040                     "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
1041                 break;
1042         default:
1043                 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1044                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1045         }
1046 
1047 out:
1048         nvlist_free(be_attrs);
1049         return (err);
1050 }
1051 
1052 static int
1053 be_do_list(int argc, char **argv)
1054 {
1055         be_node_list_t  *be_nodes = NULL;
1056         boolean_t       all = B_FALSE;
1057         boolean_t       dsets = B_FALSE;
1058         boolean_t       snaps = B_FALSE;
1059         boolean_t       parsable = B_FALSE;
1060         int             err = 1;
1061         int             c = 0;
1062         char            *be_name = NULL;
1063 
1064         while ((c = getopt(argc, argv, "nadsH")) != -1) {
1065                 switch (c) {
1066                 case 'a':
1067                         all = B_TRUE;
1068                         break;
1069                 case 'd':
1070                         dsets = B_TRUE;
1071                         break;
1072                 case 's':
1073                         snaps = B_TRUE;
1074                         break;
1075                 case 'H':
1076                         parsable = B_TRUE;
1077                         break;
1078                 default:
1079                         usage();
1080                         return (1);
1081                 }
1082         }
1083 
1084         if (all) {
1085                 if (dsets) {
1086                         (void) fprintf(stderr, _("Invalid options: -a and %s "
1087                             "are mutually exclusive.\n"), "-d");
1088                         usage();
1089                         return (1);
1090                 }
1091                 if (snaps) {
1092                         (void) fprintf(stderr, _("Invalid options: -a and %s "
1093                             "are mutually exclusive.\n"), "-s");
1094                         usage();
1095                         return (1);
1096                 }
1097 
1098                 dsets = B_TRUE;
1099                 snaps = B_TRUE;
1100         }
1101 
1102         argc -= optind;
1103         argv += optind;
1104 
1105 
1106         if (argc == 1)
1107                 be_name = argv[0];
1108 
1109         err = be_list(be_name, &be_nodes);
1110 
1111         switch (err) {
1112         case BE_SUCCESS:
1113                 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1114                 break;
1115         case BE_ERR_BE_NOENT:
1116                 if (be_name == NULL)
1117                         (void) fprintf(stderr, _("No boot environments found "
1118                             "on this system.\n"));
1119                 else {
1120                         (void) fprintf(stderr, _("%s does not exist or appear "
1121                             "to be a valid BE.\nPlease check that the name of "
1122                             "the BE provided is correct.\n"), be_name);
1123                 }
1124                 break;
1125         default:
1126                 (void) fprintf(stderr, _("Unable to display Boot "
1127                     "Environment\n"));
1128                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1129         }
1130 
1131         if (be_nodes != NULL)
1132                 be_free_list(be_nodes);
1133         return (err);
1134 }
1135 
1136 static int
1137 be_do_mount(int argc, char **argv)
1138 {
1139         nvlist_t        *be_attrs;
1140         boolean_t       shared_fs = B_FALSE;
1141         int             err = 1;
1142         int             c;
1143         int             mount_flags = 0;
1144         char            *obe_name;
1145         char            *mountpoint;
1146         char            *tmp_mp = NULL;
1147 
1148         while ((c = getopt(argc, argv, "s:")) != -1) {
1149                 switch (c) {
1150                 case 's':
1151                         shared_fs = B_TRUE;
1152 
1153                         mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1154 
1155                         if (strcmp(optarg, "rw") == 0) {
1156                                 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1157                         } else if (strcmp(optarg, "ro") != 0) {
1158                                 (void) fprintf(stderr, _("The -s flag "
1159                                     "requires an argument [ rw | ro ]\n"));
1160                                 usage();
1161                                 return (1);
1162                         }
1163 
1164                         break;
1165                 default:
1166                         usage();
1167                         return (1);
1168                 }
1169         }
1170 
1171         argc -= optind;
1172         argv += optind;
1173 
1174         if (argc < 1 || argc > 2) {
1175                 usage();
1176                 return (1);
1177         }
1178 
1179         obe_name = argv[0];
1180 
1181         if (argc == 2) {
1182                 mountpoint = argv[1];
1183                 if (mountpoint[0] != '/') {
1184                         (void) fprintf(stderr, _("Invalid mount point %s. "
1185                             "Mount point must start with a /.\n"), mountpoint);
1186                         return (1);
1187                 }
1188         } else {
1189                 const char *tmpdir = getenv("TMPDIR");
1190                 const char *tmpname = "tmp.XXXXXX";
1191                 int sz;
1192 
1193                 if (tmpdir == NULL)
1194                         tmpdir = "/tmp";
1195 
1196                 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1197                 if (sz < 0) {
1198                         (void) fprintf(stderr, _("internal error: "
1199                             "out of memory\n"));
1200                         return (1);
1201                 }
1202 
1203                 mountpoint = mkdtemp(tmp_mp);
1204         }
1205 
1206         if (be_nvl_alloc(&be_attrs) != 0)
1207                 return (1);
1208 
1209         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1210                 goto out;
1211 
1212         if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1213                 goto out;
1214 
1215         if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1216             mount_flags) != 0)
1217                 goto out;
1218 
1219         err = be_mount(be_attrs);
1220 
1221         switch (err) {
1222         case BE_SUCCESS:
1223                 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1224                 break;
1225         case BE_ERR_BE_NOENT:
1226                 err = 1;
1227                 (void) fprintf(stderr, _("%s does not exist or appear "
1228                     "to be a valid BE.\nPlease check that the name of "
1229                     "the BE provided is correct.\n"), obe_name);
1230                 break;
1231         case BE_ERR_MOUNTED:
1232                 (void) fprintf(stderr, _("%s is already mounted.\n"
1233                     "Please unmount the BE before mounting it again.\n"),
1234                     obe_name);
1235                 break;
1236         case BE_ERR_PERM:
1237         case BE_ERR_ACCESS:
1238                 err = 1;
1239                 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1240                 (void) fprintf(stderr, _("You have insufficient privileges to "
1241                     "execute this command.\n"));
1242                 break;
1243         default:
1244                 err = 1;
1245                 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1246                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1247         }
1248 
1249 out:
1250         if (tmp_mp != NULL)
1251                 free(tmp_mp);
1252         nvlist_free(be_attrs);
1253         return (err);
1254 }
1255 
1256 static int
1257 be_do_unmount(int argc, char **argv)
1258 {
1259         nvlist_t        *be_attrs;
1260         char            *obe_name;
1261         int             err = 1;
1262         int             c;
1263         int             unmount_flags = 0;
1264 
1265         while ((c = getopt(argc, argv, "f")) != -1) {
1266                 switch (c) {
1267                 case 'f':
1268                         unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1269                         break;
1270                 default:
1271                         usage();
1272                         return (1);
1273                 }
1274         }
1275 
1276         argc -= optind;
1277         argv += optind;
1278 
1279         if (argc != 1) {
1280                 usage();
1281                 return (1);
1282         }
1283 
1284         obe_name = argv[0];
1285 
1286         if (be_nvl_alloc(&be_attrs) != 0)
1287                 return (1);
1288 
1289 
1290         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1291                 goto out;
1292 
1293         if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1294             unmount_flags) != 0)
1295                 goto out;
1296 
1297         err = be_unmount(be_attrs);
1298 
1299         switch (err) {
1300         case BE_SUCCESS:
1301                 (void) printf(_("Unmounted successfully\n"));
1302                 break;
1303         case BE_ERR_BE_NOENT:
1304                 (void) fprintf(stderr, _("%s does not exist or appear "
1305                     "to be a valid BE.\nPlease check that the name of "
1306                     "the BE provided is correct.\n"), obe_name);
1307                 break;
1308         case BE_ERR_UMOUNT_CURR_BE:
1309                 (void) fprintf(stderr, _("%s is the currently active BE.\n"
1310                     "It cannot be unmounted unless another BE is the "
1311                     "currently active BE.\n"), obe_name);
1312                 break;
1313         case BE_ERR_UMOUNT_SHARED:
1314                 (void) fprintf(stderr, _("%s is a shared file system and it "
1315                     "cannot be unmounted.\n"), obe_name);
1316                 break;
1317         case BE_ERR_PERM:
1318         case BE_ERR_ACCESS:
1319                 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1320                 (void) fprintf(stderr, _("You have insufficient privileges to "
1321                     "execute this command.\n"));
1322                 break;
1323         default:
1324                 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1325                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1326         }
1327 
1328 out:
1329         nvlist_free(be_attrs);
1330         return (err);
1331 }
1332 
1333 static int
1334 be_do_rename(int argc, char **argv)
1335 {
1336         nvlist_t        *be_attrs;
1337         char            *obe_name;
1338         char            *nbe_name;
1339         int err = 1;
1340 
1341         argc -= optind;
1342         argv += optind;
1343 
1344         if (argc != 2) {
1345                 usage();
1346                 return (1);
1347         }
1348 
1349         obe_name = argv[0];
1350         nbe_name = argv[1];
1351 
1352         if (be_nvl_alloc(&be_attrs) != 0)
1353                 return (1);
1354 
1355         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1356                 goto out;
1357 
1358         if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1359                 goto out;
1360 
1361         err = be_rename(be_attrs);
1362 
1363         switch (err) {
1364         case BE_SUCCESS:
1365                 (void) printf(_("Renamed successfully\n"));
1366                 break;
1367         case BE_ERR_BE_NOENT:
1368                 (void) fprintf(stderr, _("%s does not exist or appear "
1369                     "to be a valid BE.\nPlease check that the name of "
1370                     "the BE provided is correct.\n"), obe_name);
1371                 break;
1372         case BE_ERR_PERM:
1373         case BE_ERR_ACCESS:
1374                 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1375                     obe_name);
1376                 (void) fprintf(stderr, _("You have insufficient privileges to "
1377                     "execute this command.\n"));
1378                 break;
1379         default:
1380                 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1381                     obe_name);
1382                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1383         }
1384 
1385 out:
1386         nvlist_free(be_attrs);
1387         return (err);
1388 }
1389 
1390 static int
1391 be_do_rollback(int argc, char **argv)
1392 {
1393         nvlist_t        *be_attrs;
1394         char            *obe_name;
1395         char            *snap_name;
1396         int             err = 1;
1397 
1398         argc -= optind;
1399         argv += optind;
1400 
1401         if (argc < 1 || argc > 2) {
1402                 usage();
1403                 return (1);
1404         }
1405 
1406         obe_name = argv[0];
1407         if (argc == 2)
1408                 snap_name = argv[1];
1409         else { /* argc == 1 */
1410                 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1411                         if (snap_name[1] == '\0') {
1412                                 usage();
1413                                 return (1);
1414                         }
1415 
1416                         snap_name[0] = '\0';
1417                         snap_name++;
1418                 } else {
1419                         usage();
1420                         return (1);
1421                 }
1422         }
1423 
1424         if (be_nvl_alloc(&be_attrs) != 0)
1425                 return (1);
1426 
1427         if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1428                 goto out;
1429 
1430         if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1431                 goto out;
1432 
1433         err = be_rollback(be_attrs);
1434 
1435         switch (err) {
1436         case BE_SUCCESS:
1437                 (void) printf(_("Rolled back successfully\n"));
1438                 break;
1439         case BE_ERR_BE_NOENT:
1440                 (void) fprintf(stderr, _("%s does not exist or appear "
1441                     "to be a valid BE.\nPlease check that the name of "
1442                     "the BE provided is correct.\n"), obe_name);
1443                 break;
1444         case BE_ERR_SS_NOENT:
1445                 (void) fprintf(stderr, _("%s does not exist or appear "
1446                     "to be a valid snapshot.\nPlease check that the name of "
1447                     "the snapshot provided is correct.\n"), snap_name);
1448                 break;
1449         case BE_ERR_PERM:
1450         case BE_ERR_ACCESS:
1451                 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1452                     "failed.\n"), obe_name, snap_name);
1453                 (void) fprintf(stderr, _("You have insufficient privileges to "
1454                     "execute this command.\n"));
1455                 break;
1456         default:
1457                 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1458                     "failed.\n"), obe_name, snap_name);
1459                 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1460         }
1461 
1462 out:
1463         nvlist_free(be_attrs);
1464         return (err);
1465 }