bectl.c revision 352348
1337414Skevans/*- 2337414Skevans * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3336668Skevans * 4336668Skevans * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> 5336668Skevans * All rights reserved. 6336668Skevans * 7336668Skevans * Redistribution and use in source and binary forms, with or without 8336668Skevans * modification, are permitted provided that the following conditions 9336668Skevans * are met: 10336668Skevans * 1. Redistributions of source code must retain the above copyright 11336668Skevans * notice, this list of conditions and the following disclaimer. 12336668Skevans * 2. Redistributions in binary form must reproduce the above copyright 13336668Skevans * notice, this list of conditions and the following disclaimer in the 14336668Skevans * documentation and/or other materials provided with the distribution. 15336668Skevans * 16336668Skevans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17336668Skevans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18336668Skevans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19336668Skevans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20336668Skevans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21336668Skevans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22336668Skevans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23336668Skevans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24336668Skevans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25336668Skevans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26336668Skevans * SUCH DAMAGE. 27336668Skevans */ 28336668Skevans 29337416Skevans#include <sys/cdefs.h> 30337416Skevans__FBSDID("$FreeBSD: stable/11/sbin/bectl/bectl.c 352348 2019-09-15 02:46:40Z kevans $"); 31337416Skevans 32336668Skevans#include <sys/param.h> 33336668Skevans#include <sys/mount.h> 34336668Skevans#include <errno.h> 35336747Skevans#include <libutil.h> 36336668Skevans#include <stdbool.h> 37336668Skevans#include <stdio.h> 38336668Skevans#include <stdint.h> 39336668Skevans#include <stdlib.h> 40336668Skevans#include <string.h> 41336668Skevans#include <sysexits.h> 42336747Skevans#include <time.h> 43336668Skevans#include <unistd.h> 44336668Skevans 45336668Skevans#include <be.h> 46336668Skevans 47337368Skevans#include "bectl.h" 48337368Skevans 49336694Skevansstatic int bectl_cmd_activate(int argc, char *argv[]); 50352348Skevansstatic int bectl_cmd_check(int argc, char *argv[]); 51336694Skevansstatic int bectl_cmd_create(int argc, char *argv[]); 52336694Skevansstatic int bectl_cmd_destroy(int argc, char *argv[]); 53336694Skevansstatic int bectl_cmd_export(int argc, char *argv[]); 54336694Skevansstatic int bectl_cmd_import(int argc, char *argv[]); 55337596Skevans#if SOON 56336694Skevansstatic int bectl_cmd_add(int argc, char *argv[]); 57337596Skevans#endif 58336694Skevansstatic int bectl_cmd_mount(int argc, char *argv[]); 59336694Skevansstatic int bectl_cmd_rename(int argc, char *argv[]); 60336694Skevansstatic int bectl_cmd_unmount(int argc, char *argv[]); 61336668Skevans 62337368Skevanslibbe_handle_t *be; 63336668Skevans 64337368Skevansint 65336668Skevansusage(bool explicit) 66336668Skevans{ 67336703Skevans FILE *fp; 68336668Skevans 69336703Skevans fp = explicit ? stdout : stderr; 70346429Skevans fprintf(fp, "%s", 71346429Skevans "usage:\tbectl {-h | -? | subcommand [args...]}\n" 72346429Skevans#if SOON 73346429Skevans "\tbectl add (path)*\n" 74346429Skevans#endif 75336694Skevans "\tbectl activate [-t] beName\n" 76352348Skevans "\tbectl check\n" 77346429Skevans "\tbectl create [-r] [-e {nonActiveBe | beName@snapshot}] beName\n" 78346429Skevans "\tbectl create [-r] beName@snapshot\n" 79346429Skevans "\tbectl destroy [-F] {beName | beName@snapshot}\n" 80336694Skevans "\tbectl export sourceBe\n" 81336694Skevans "\tbectl import targetBe\n" 82346429Skevans "\tbectl jail {-b | -U} [{-o key=value | -u key}]... " 83346429Skevans "{jailID | jailName}\n" 84346429Skevans "\t bootenv [utility [argument ...]]\n" 85352088Skevans "\tbectl list [-DHas] [{-c property | -C property}]\n" 86336694Skevans "\tbectl mount beName [mountpoint]\n" 87336694Skevans "\tbectl rename origBeName newBeName\n" 88346429Skevans "\tbectl {ujail | unjail} {jailID | jailName} bootenv\n" 89346429Skevans "\tbectl {umount | unmount} [-f] beName\n"); 90336668Skevans 91336668Skevans return (explicit ? 0 : EX_USAGE); 92336668Skevans} 93336668Skevans 94336668Skevans 95336668Skevans/* 96336668Skevans * Represents a relationship between the command name and the parser action 97336668Skevans * that handles it. 98336668Skevans */ 99336668Skevansstruct command_map_entry { 100336668Skevans const char *command; 101336668Skevans int (*fn)(int argc, char *argv[]); 102352348Skevans /* True if libbe_print_on_error should be disabled */ 103352348Skevans bool silent; 104336668Skevans}; 105336668Skevans 106336668Skevansstatic struct command_map_entry command_map[] = 107336668Skevans{ 108352348Skevans { "activate", bectl_cmd_activate,false }, 109352348Skevans { "create", bectl_cmd_create, false }, 110352348Skevans { "destroy", bectl_cmd_destroy, false }, 111352348Skevans { "export", bectl_cmd_export, false }, 112352348Skevans { "import", bectl_cmd_import, false }, 113337596Skevans#if SOON 114352348Skevans { "add", bectl_cmd_add, false }, 115337596Skevans#endif 116352348Skevans { "jail", bectl_cmd_jail, false }, 117352348Skevans { "list", bectl_cmd_list, false }, 118352348Skevans { "mount", bectl_cmd_mount, false }, 119352348Skevans { "rename", bectl_cmd_rename, false }, 120352348Skevans { "unjail", bectl_cmd_unjail, false }, 121352348Skevans { "unmount", bectl_cmd_unmount, false }, 122352348Skevans { "check", bectl_cmd_check, true }, 123336668Skevans}; 124336668Skevans 125352348Skevansstatic struct command_map_entry * 126352348Skevansget_cmd_info(const char *cmd) 127336668Skevans{ 128352348Skevans size_t i; 129336668Skevans 130352348Skevans for (i = 0; i < nitems(command_map); ++i) { 131352348Skevans if (strcmp(cmd, command_map[i].command) == 0) 132352348Skevans return (&command_map[i]); 133336668Skevans } 134336668Skevans 135352348Skevans return (NULL); 136336668Skevans} 137336668Skevans 138336668Skevans 139336668Skevansstatic int 140336694Skevansbectl_cmd_activate(int argc, char *argv[]) 141336668Skevans{ 142336668Skevans int err, opt; 143336668Skevans bool temp; 144336668Skevans 145336668Skevans temp = false; 146336668Skevans while ((opt = getopt(argc, argv, "t")) != -1) { 147336668Skevans switch (opt) { 148336668Skevans case 't': 149336668Skevans temp = true; 150336668Skevans break; 151336668Skevans default: 152336702Skevans fprintf(stderr, "bectl activate: unknown option '-%c'\n", 153336668Skevans optopt); 154336668Skevans return (usage(false)); 155336668Skevans } 156336668Skevans } 157336668Skevans 158336668Skevans argc -= optind; 159336668Skevans argv += optind; 160336668Skevans 161336668Skevans if (argc != 1) { 162336702Skevans fprintf(stderr, "bectl activate: wrong number of arguments\n"); 163336668Skevans return (usage(false)); 164336668Skevans } 165336668Skevans 166336668Skevans 167336668Skevans /* activate logic goes here */ 168336703Skevans if ((err = be_activate(be, argv[0], temp)) != 0) 169336703Skevans /* XXX TODO: more specific error msg based on err */ 170336668Skevans printf("did not successfully activate boot environment %s\n", 171336668Skevans argv[0]); 172336703Skevans else 173336668Skevans printf("successfully activated boot environment %s\n", argv[0]); 174336668Skevans 175336703Skevans if (temp) 176336668Skevans printf("for next boot\n"); 177336668Skevans 178336668Skevans return (err); 179336668Skevans} 180336668Skevans 181336668Skevans 182336703Skevans/* 183336703Skevans * TODO: when only one arg is given, and it contains an "@" the this should 184336703Skevans * create that snapshot 185336703Skevans */ 186336668Skevansstatic int 187336694Skevansbectl_cmd_create(int argc, char *argv[]) 188336668Skevans{ 189350344Skevans char snapshot[BE_MAXPATHLEN]; 190350344Skevans char *atpos, *bootenv, *snapname; 191336668Skevans int err, opt; 192346429Skevans bool recursive; 193336668Skevans 194336668Skevans snapname = NULL; 195346429Skevans recursive = false; 196346429Skevans while ((opt = getopt(argc, argv, "e:r")) != -1) { 197336668Skevans switch (opt) { 198336668Skevans case 'e': 199336668Skevans snapname = optarg; 200336668Skevans break; 201346429Skevans case 'r': 202346429Skevans recursive = true; 203346429Skevans break; 204336668Skevans default: 205336702Skevans fprintf(stderr, "bectl create: unknown option '-%c'\n", 206336668Skevans optopt); 207336668Skevans return (usage(false)); 208336668Skevans } 209336668Skevans } 210336668Skevans 211336668Skevans argc -= optind; 212336668Skevans argv += optind; 213336668Skevans 214336668Skevans if (argc != 1) { 215336702Skevans fprintf(stderr, "bectl create: wrong number of arguments\n"); 216336668Skevans return (usage(false)); 217336668Skevans } 218336668Skevans 219336668Skevans bootenv = *argv; 220350344Skevans 221350344Skevans err = BE_ERR_SUCCESS; 222346429Skevans if ((atpos = strchr(bootenv, '@')) != NULL) { 223346429Skevans /* 224346429Skevans * This is the "create a snapshot variant". No new boot 225346429Skevans * environment is to be created here. 226346429Skevans */ 227346429Skevans *atpos++ = '\0'; 228346429Skevans err = be_snapshot(be, bootenv, atpos, recursive, NULL); 229350344Skevans } else { 230350344Skevans if (snapname == NULL) 231350344Skevans /* Create from currently booted BE */ 232350344Skevans err = be_snapshot(be, be_active_path(be), NULL, 233350344Skevans recursive, snapshot); 234350344Skevans else if (strchr(snapname, '@') != NULL) 235350344Skevans /* Create from given snapshot */ 236350344Skevans strlcpy(snapshot, snapname, sizeof(snapshot)); 237336703Skevans else 238350344Skevans /* Create from given BE */ 239350344Skevans err = be_snapshot(be, snapname, NULL, recursive, 240350344Skevans snapshot); 241350344Skevans 242350344Skevans if (err == BE_ERR_SUCCESS) 243350344Skevans err = be_create_depth(be, bootenv, snapshot, 244350344Skevans recursive == true ? -1 : 0); 245336668Skevans } 246336668Skevans 247336668Skevans switch (err) { 248336668Skevans case BE_ERR_SUCCESS: 249336668Skevans break; 250336668Skevans default: 251346429Skevans if (atpos != NULL) 252336668Skevans fprintf(stderr, 253346429Skevans "failed to create a snapshot '%s' of '%s'\n", 254346429Skevans atpos, bootenv); 255346429Skevans else if (snapname == NULL) 256346429Skevans fprintf(stderr, 257336668Skevans "failed to create bootenv %s\n", bootenv); 258336703Skevans else 259336668Skevans fprintf(stderr, 260336668Skevans "failed to create bootenv %s from snapshot %s\n", 261336668Skevans bootenv, snapname); 262336668Skevans } 263336668Skevans 264336668Skevans return (err); 265336668Skevans} 266336668Skevans 267336668Skevans 268336668Skevansstatic int 269336694Skevansbectl_cmd_export(int argc, char *argv[]) 270336668Skevans{ 271336703Skevans char *bootenv; 272336668Skevans 273336668Skevans if (argc == 1) { 274336702Skevans fprintf(stderr, "bectl export: missing boot environment name\n"); 275336668Skevans return (usage(false)); 276336668Skevans } 277336668Skevans 278336668Skevans if (argc > 2) { 279336702Skevans fprintf(stderr, "bectl export: extra arguments provided\n"); 280336668Skevans return (usage(false)); 281336668Skevans } 282336668Skevans 283336668Skevans bootenv = argv[1]; 284336668Skevans 285336668Skevans if (isatty(STDOUT_FILENO)) { 286336702Skevans fprintf(stderr, "bectl export: must redirect output\n"); 287336668Skevans return (EX_USAGE); 288336668Skevans } 289336668Skevans 290336668Skevans be_export(be, bootenv, STDOUT_FILENO); 291336668Skevans 292336668Skevans return (0); 293336668Skevans} 294336668Skevans 295336668Skevans 296336668Skevansstatic int 297336694Skevansbectl_cmd_import(int argc, char *argv[]) 298336668Skevans{ 299336668Skevans char *bootenv; 300336668Skevans int err; 301336668Skevans 302336668Skevans if (argc == 1) { 303336702Skevans fprintf(stderr, "bectl import: missing boot environment name\n"); 304336668Skevans return (usage(false)); 305336668Skevans } 306336668Skevans 307336668Skevans if (argc > 2) { 308336702Skevans fprintf(stderr, "bectl import: extra arguments provided\n"); 309336668Skevans return (usage(false)); 310336668Skevans } 311336668Skevans 312336668Skevans bootenv = argv[1]; 313336668Skevans 314336668Skevans if (isatty(STDIN_FILENO)) { 315336702Skevans fprintf(stderr, "bectl import: input can not be from terminal\n"); 316336668Skevans return (EX_USAGE); 317336668Skevans } 318336668Skevans 319336668Skevans err = be_import(be, bootenv, STDIN_FILENO); 320336668Skevans 321336668Skevans return (err); 322336668Skevans} 323336668Skevans 324337596Skevans#if SOON 325336668Skevansstatic int 326336694Skevansbectl_cmd_add(int argc, char *argv[]) 327336668Skevans{ 328336668Skevans 329336668Skevans if (argc < 2) { 330336702Skevans fprintf(stderr, "bectl add: must provide at least one path\n"); 331336668Skevans return (usage(false)); 332336668Skevans } 333336668Skevans 334336668Skevans for (int i = 1; i < argc; ++i) { 335336668Skevans printf("arg %d: %s\n", i, argv[i]); 336336703Skevans /* XXX TODO catch err */ 337336668Skevans be_add_child(be, argv[i], true); 338336668Skevans } 339336668Skevans 340336668Skevans return (0); 341336668Skevans} 342337596Skevans#endif 343336668Skevans 344336668Skevansstatic int 345336694Skevansbectl_cmd_destroy(int argc, char *argv[]) 346336668Skevans{ 347346429Skevans nvlist_t *props; 348346429Skevans char *origin, *target, targetds[BE_MAXPATHLEN]; 349346429Skevans int err, flags, opt; 350336668Skevans 351346429Skevans flags = 0; 352346429Skevans while ((opt = getopt(argc, argv, "Fo")) != -1) { 353336668Skevans switch (opt) { 354336668Skevans case 'F': 355346429Skevans flags |= BE_DESTROY_FORCE; 356336668Skevans break; 357346429Skevans case 'o': 358346429Skevans flags |= BE_DESTROY_ORIGIN; 359346429Skevans break; 360336668Skevans default: 361336702Skevans fprintf(stderr, "bectl destroy: unknown option '-%c'\n", 362336668Skevans optopt); 363336668Skevans return (usage(false)); 364336668Skevans } 365336668Skevans } 366336668Skevans 367336668Skevans argc -= optind; 368336668Skevans argv += optind; 369336668Skevans 370336668Skevans if (argc != 1) { 371336702Skevans fprintf(stderr, "bectl destroy: wrong number of arguments\n"); 372336668Skevans return (usage(false)); 373336668Skevans } 374336668Skevans 375336668Skevans target = argv[0]; 376336668Skevans 377346429Skevans /* We'll emit a notice if there's an origin to be cleaned up */ 378346429Skevans if ((flags & BE_DESTROY_ORIGIN) == 0 && strchr(target, '@') == NULL) { 379346429Skevans if (be_root_concat(be, target, targetds) != 0) 380346429Skevans goto destroy; 381346429Skevans if (be_prop_list_alloc(&props) != 0) 382346429Skevans goto destroy; 383346429Skevans if (be_get_dataset_props(be, targetds, props) != 0) { 384346429Skevans be_prop_list_free(props); 385346429Skevans goto destroy; 386346429Skevans } 387346429Skevans if (nvlist_lookup_string(props, "origin", &origin) == 0) 388346429Skevans fprintf(stderr, "bectl destroy: leaving origin '%s' intact\n", 389346429Skevans origin); 390346429Skevans be_prop_list_free(props); 391346429Skevans } 392336668Skevans 393346429Skevansdestroy: 394346429Skevans err = be_destroy(be, target, flags); 395346429Skevans 396336668Skevans return (err); 397336668Skevans} 398336668Skevans 399337358Skevansstatic int 400336694Skevansbectl_cmd_mount(int argc, char *argv[]) 401336668Skevans{ 402336703Skevans char result_loc[BE_MAXPATHLEN]; 403336703Skevans char *bootenv, *mountpoint; 404346429Skevans int err, mntflags; 405336668Skevans 406346429Skevans /* XXX TODO: Allow shallow */ 407346429Skevans mntflags = BE_MNT_DEEP; 408336668Skevans if (argc < 2) { 409336702Skevans fprintf(stderr, "bectl mount: missing argument(s)\n"); 410336668Skevans return (usage(false)); 411336668Skevans } 412336668Skevans 413336668Skevans if (argc > 3) { 414336702Skevans fprintf(stderr, "bectl mount: too many arguments\n"); 415336668Skevans return (usage(false)); 416336668Skevans } 417336668Skevans 418336668Skevans bootenv = argv[1]; 419336668Skevans mountpoint = ((argc == 3) ? argv[2] : NULL); 420336668Skevans 421346429Skevans err = be_mount(be, bootenv, mountpoint, mntflags, result_loc); 422336668Skevans 423336668Skevans switch (err) { 424336668Skevans case BE_ERR_SUCCESS: 425336668Skevans printf("successfully mounted %s at %s\n", bootenv, result_loc); 426336668Skevans break; 427336668Skevans default: 428336668Skevans fprintf(stderr, 429336668Skevans (argc == 3) ? "failed to mount bootenv %s at %s\n" : 430336668Skevans "failed to mount bootenv %s at temporary path %s\n", 431336668Skevans bootenv, mountpoint); 432336668Skevans } 433336668Skevans 434336668Skevans return (err); 435336668Skevans} 436336668Skevans 437336668Skevans 438336668Skevansstatic int 439336694Skevansbectl_cmd_rename(int argc, char *argv[]) 440336668Skevans{ 441336703Skevans char *dest, *src; 442336668Skevans int err; 443336668Skevans 444336668Skevans if (argc < 3) { 445336702Skevans fprintf(stderr, "bectl rename: missing argument\n"); 446336668Skevans return (usage(false)); 447336668Skevans } 448336668Skevans 449336668Skevans if (argc > 3) { 450336702Skevans fprintf(stderr, "bectl rename: too many arguments\n"); 451336668Skevans return (usage(false)); 452336668Skevans } 453336668Skevans 454336668Skevans src = argv[1]; 455336668Skevans dest = argv[2]; 456336668Skevans 457336668Skevans err = be_rename(be, src, dest); 458336668Skevans 459336668Skevans switch (err) { 460336668Skevans case BE_ERR_SUCCESS: 461336668Skevans break; 462336668Skevans default: 463336668Skevans fprintf(stderr, "failed to rename bootenv %s to %s\n", 464336668Skevans src, dest); 465336668Skevans } 466336668Skevans 467336668Skevans return (0); 468336668Skevans} 469336668Skevans 470336730Skevansstatic int 471336694Skevansbectl_cmd_unmount(int argc, char *argv[]) 472336668Skevans{ 473336703Skevans char *bootenv, *cmd; 474336668Skevans int err, flags, opt; 475336668Skevans 476336668Skevans /* Store alias used */ 477336668Skevans cmd = argv[0]; 478336668Skevans 479336668Skevans flags = 0; 480336668Skevans while ((opt = getopt(argc, argv, "f")) != -1) { 481336668Skevans switch (opt) { 482336668Skevans case 'f': 483336668Skevans flags |= BE_MNT_FORCE; 484336668Skevans break; 485336668Skevans default: 486336702Skevans fprintf(stderr, "bectl %s: unknown option '-%c'\n", 487336668Skevans cmd, optopt); 488336668Skevans return (usage(false)); 489336668Skevans } 490336668Skevans } 491336668Skevans 492336668Skevans argc -= optind; 493336668Skevans argv += optind; 494336668Skevans 495336668Skevans if (argc != 1) { 496336702Skevans fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd); 497336668Skevans return (usage(false)); 498336668Skevans } 499336668Skevans 500336668Skevans bootenv = argv[0]; 501336668Skevans 502336668Skevans err = be_unmount(be, bootenv, flags); 503336668Skevans 504336668Skevans switch (err) { 505336668Skevans case BE_ERR_SUCCESS: 506336668Skevans break; 507336668Skevans default: 508336668Skevans fprintf(stderr, "failed to unmount bootenv %s\n", bootenv); 509336668Skevans } 510336668Skevans 511336668Skevans return (err); 512336668Skevans} 513336668Skevans 514352348Skevansstatic int 515352348Skevansbectl_cmd_check(int argc, char *argv[] __unused) 516352348Skevans{ 517336668Skevans 518352348Skevans /* The command is left as argv[0] */ 519352348Skevans if (argc != 1) { 520352348Skevans fprintf(stderr, "bectl check: wrong number of arguments\n"); 521352348Skevans return (usage(false)); 522352348Skevans } 523352348Skevans 524352348Skevans return (0); 525352348Skevans} 526352348Skevans 527336668Skevansint 528336668Skevansmain(int argc, char *argv[]) 529336668Skevans{ 530352348Skevans struct command_map_entry *cmd; 531336710Skevans const char *command; 532346429Skevans char *root; 533352348Skevans int rc; 534336668Skevans 535352348Skevans cmd = NULL; 536346429Skevans root = NULL; 537346429Skevans if (argc < 2) 538336668Skevans return (usage(false)); 539346429Skevans 540346429Skevans if (strcmp(argv[1], "-r") == 0) { 541346429Skevans if (argc < 4) 542346429Skevans return (usage(false)); 543346429Skevans root = strdup(argv[2]); 544346429Skevans command = argv[3]; 545346429Skevans argc -= 3; 546346429Skevans argv += 3; 547346429Skevans } else { 548346429Skevans command = argv[1]; 549346429Skevans argc -= 1; 550346429Skevans argv += 1; 551336668Skevans } 552336668Skevans 553336668Skevans /* Handle command aliases */ 554336703Skevans if (strcmp(command, "umount") == 0) 555336668Skevans command = "unmount"; 556336668Skevans 557336703Skevans if (strcmp(command, "ujail") == 0) 558336668Skevans command = "unjail"; 559336668Skevans 560336703Skevans if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0)) 561336668Skevans return (usage(true)); 562336668Skevans 563352348Skevans if ((cmd = get_cmd_info(command)) == NULL) { 564336668Skevans fprintf(stderr, "unknown command: %s\n", command); 565336668Skevans return (usage(false)); 566336668Skevans } 567336668Skevans 568346429Skevans if ((be = libbe_init(root)) == NULL) 569336668Skevans return (-1); 570336668Skevans 571352348Skevans libbe_print_on_error(be, !cmd->silent); 572336668Skevans 573352348Skevans rc = cmd->fn(argc, argv); 574336668Skevans 575336668Skevans libbe_close(be); 576336668Skevans return (rc); 577336668Skevans} 578