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