1b179da01SKyle Evans /*- 2b179da01SKyle Evans * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35952343eSKyle Evans * 45952343eSKyle Evans * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> 55952343eSKyle Evans * All rights reserved. 65952343eSKyle Evans * 75952343eSKyle Evans * Redistribution and use in source and binary forms, with or without 85952343eSKyle Evans * modification, are permitted provided that the following conditions 95952343eSKyle Evans * are met: 105952343eSKyle Evans * 1. Redistributions of source code must retain the above copyright 115952343eSKyle Evans * notice, this list of conditions and the following disclaimer. 125952343eSKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 135952343eSKyle Evans * notice, this list of conditions and the following disclaimer in the 145952343eSKyle Evans * documentation and/or other materials provided with the distribution. 155952343eSKyle Evans * 165952343eSKyle Evans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 175952343eSKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 185952343eSKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 195952343eSKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 205952343eSKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 215952343eSKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 225952343eSKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 235952343eSKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 245952343eSKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 255952343eSKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 265952343eSKyle Evans * SUCH DAMAGE. 275952343eSKyle Evans */ 285952343eSKyle Evans 29b6e7c421SKyle Evans #include <sys/cdefs.h> 30b6e7c421SKyle Evans __FBSDID("$FreeBSD$"); 31b6e7c421SKyle Evans 325952343eSKyle Evans #include <sys/param.h> 335952343eSKyle Evans #include <sys/mount.h> 345952343eSKyle Evans #include <errno.h> 3583244ec1SKyle Evans #include <libutil.h> 365952343eSKyle Evans #include <stdbool.h> 375952343eSKyle Evans #include <stdio.h> 385952343eSKyle Evans #include <stdint.h> 395952343eSKyle Evans #include <stdlib.h> 405952343eSKyle Evans #include <string.h> 415952343eSKyle Evans #include <sysexits.h> 4283244ec1SKyle Evans #include <time.h> 435952343eSKyle Evans #include <unistd.h> 445952343eSKyle Evans 455952343eSKyle Evans #include <be.h> 465952343eSKyle Evans 47d694059fSKyle Evans #include "bectl.h" 48d694059fSKyle Evans 499e004b21SKyle Evans static int bectl_cmd_activate(int argc, char *argv[]); 50*490e13c1SKyle Evans static int bectl_cmd_check(int argc, char *argv[]); 519e004b21SKyle Evans static int bectl_cmd_create(int argc, char *argv[]); 529e004b21SKyle Evans static int bectl_cmd_destroy(int argc, char *argv[]); 539e004b21SKyle Evans static int bectl_cmd_export(int argc, char *argv[]); 549e004b21SKyle Evans static int bectl_cmd_import(int argc, char *argv[]); 553d1a1f2cSKyle Evans #if SOON 569e004b21SKyle Evans static int bectl_cmd_add(int argc, char *argv[]); 573d1a1f2cSKyle Evans #endif 589e004b21SKyle Evans static int bectl_cmd_mount(int argc, char *argv[]); 599e004b21SKyle Evans static int bectl_cmd_rename(int argc, char *argv[]); 609e004b21SKyle Evans static int bectl_cmd_unmount(int argc, char *argv[]); 615952343eSKyle Evans 62d694059fSKyle Evans libbe_handle_t *be; 635952343eSKyle Evans 64d694059fSKyle Evans int 655952343eSKyle Evans usage(bool explicit) 665952343eSKyle Evans { 6716a10da8SKyle Evans FILE *fp; 685952343eSKyle Evans 6916a10da8SKyle Evans fp = explicit ? stdout : stderr; 7052ee41b7SYuri Pankov fprintf(fp, "%s", 71d81df689SKyle Evans "usage:\tbectl {-h | -? | subcommand [args...]}\n" 723d1a1f2cSKyle Evans #if SOON 739e004b21SKyle Evans "\tbectl add (path)*\n" 743d1a1f2cSKyle Evans #endif 7552ee41b7SYuri Pankov "\tbectl activate [-t] beName\n" 76*490e13c1SKyle Evans "\tbectl check\n" 7752ee41b7SYuri Pankov "\tbectl create [-r] [-e {nonActiveBe | beName@snapshot}] beName\n" 7852ee41b7SYuri Pankov "\tbectl create [-r] beName@snapshot\n" 7952ee41b7SYuri Pankov "\tbectl destroy [-F] {beName | beName@snapshot}\n" 8052ee41b7SYuri Pankov "\tbectl export sourceBe\n" 8152ee41b7SYuri Pankov "\tbectl import targetBe\n" 8252ee41b7SYuri Pankov "\tbectl jail {-b | -U} [{-o key=value | -u key}]... " 8352ee41b7SYuri Pankov "{jailID | jailName}\n" 8452ee41b7SYuri Pankov "\t bootenv [utility [argument ...]]\n" 85f0298be0SKyle Evans "\tbectl list [-DHas] [{-c property | -C property}]\n" 869e004b21SKyle Evans "\tbectl mount beName [mountpoint]\n" 879e004b21SKyle Evans "\tbectl rename origBeName newBeName\n" 8852ee41b7SYuri Pankov "\tbectl {ujail | unjail} {jailID | jailName} bootenv\n" 899e004b21SKyle Evans "\tbectl {umount | unmount} [-f] beName\n"); 905952343eSKyle Evans 915952343eSKyle Evans return (explicit ? 0 : EX_USAGE); 925952343eSKyle Evans } 935952343eSKyle Evans 945952343eSKyle Evans 955952343eSKyle Evans /* 965952343eSKyle Evans * Represents a relationship between the command name and the parser action 975952343eSKyle Evans * that handles it. 985952343eSKyle Evans */ 995952343eSKyle Evans struct command_map_entry { 1005952343eSKyle Evans const char *command; 1015952343eSKyle Evans int (*fn)(int argc, char *argv[]); 102*490e13c1SKyle Evans /* True if libbe_print_on_error should be disabled */ 103*490e13c1SKyle Evans bool silent; 1045952343eSKyle Evans }; 1055952343eSKyle Evans 1065952343eSKyle Evans static struct command_map_entry command_map[] = 1075952343eSKyle Evans { 108*490e13c1SKyle Evans { "activate", bectl_cmd_activate,false }, 109*490e13c1SKyle Evans { "create", bectl_cmd_create, false }, 110*490e13c1SKyle Evans { "destroy", bectl_cmd_destroy, false }, 111*490e13c1SKyle Evans { "export", bectl_cmd_export, false }, 112*490e13c1SKyle Evans { "import", bectl_cmd_import, false }, 1133d1a1f2cSKyle Evans #if SOON 114*490e13c1SKyle Evans { "add", bectl_cmd_add, false }, 1153d1a1f2cSKyle Evans #endif 116*490e13c1SKyle Evans { "jail", bectl_cmd_jail, false }, 117*490e13c1SKyle Evans { "list", bectl_cmd_list, false }, 118*490e13c1SKyle Evans { "mount", bectl_cmd_mount, false }, 119*490e13c1SKyle Evans { "rename", bectl_cmd_rename, false }, 120*490e13c1SKyle Evans { "unjail", bectl_cmd_unjail, false }, 121*490e13c1SKyle Evans { "unmount", bectl_cmd_unmount, false }, 122*490e13c1SKyle Evans { "check", bectl_cmd_check, true }, 1235952343eSKyle Evans }; 1245952343eSKyle Evans 125*490e13c1SKyle Evans static struct command_map_entry * 126*490e13c1SKyle Evans get_cmd_info(const char *cmd) 1275952343eSKyle Evans { 128*490e13c1SKyle Evans size_t i; 1295952343eSKyle Evans 130*490e13c1SKyle Evans for (i = 0; i < nitems(command_map); ++i) { 131*490e13c1SKyle Evans if (strcmp(cmd, command_map[i].command) == 0) 132*490e13c1SKyle Evans return (&command_map[i]); 1335952343eSKyle Evans } 1345952343eSKyle Evans 135*490e13c1SKyle Evans return (NULL); 1365952343eSKyle Evans } 1375952343eSKyle Evans 1385952343eSKyle Evans 1395952343eSKyle Evans static int 1409e004b21SKyle Evans bectl_cmd_activate(int argc, char *argv[]) 1415952343eSKyle Evans { 1425952343eSKyle Evans int err, opt; 1435952343eSKyle Evans bool temp; 1445952343eSKyle Evans 1455952343eSKyle Evans temp = false; 1465952343eSKyle Evans while ((opt = getopt(argc, argv, "t")) != -1) { 1475952343eSKyle Evans switch (opt) { 1485952343eSKyle Evans case 't': 1495952343eSKyle Evans temp = true; 1505952343eSKyle Evans break; 1515952343eSKyle Evans default: 1522c848957SKyle Evans fprintf(stderr, "bectl activate: unknown option '-%c'\n", 1535952343eSKyle Evans optopt); 1545952343eSKyle Evans return (usage(false)); 1555952343eSKyle Evans } 1565952343eSKyle Evans } 1575952343eSKyle Evans 1585952343eSKyle Evans argc -= optind; 1595952343eSKyle Evans argv += optind; 1605952343eSKyle Evans 1615952343eSKyle Evans if (argc != 1) { 1622c848957SKyle Evans fprintf(stderr, "bectl activate: wrong number of arguments\n"); 1635952343eSKyle Evans return (usage(false)); 1645952343eSKyle Evans } 1655952343eSKyle Evans 1665952343eSKyle Evans 1675952343eSKyle Evans /* activate logic goes here */ 16816a10da8SKyle Evans if ((err = be_activate(be, argv[0], temp)) != 0) 16916a10da8SKyle Evans /* XXX TODO: more specific error msg based on err */ 1705952343eSKyle Evans printf("did not successfully activate boot environment %s\n", 1715952343eSKyle Evans argv[0]); 17216a10da8SKyle Evans else 1735952343eSKyle Evans printf("successfully activated boot environment %s\n", argv[0]); 1745952343eSKyle Evans 17516a10da8SKyle Evans if (temp) 1765952343eSKyle Evans printf("for next boot\n"); 1775952343eSKyle Evans 1785952343eSKyle Evans return (err); 1795952343eSKyle Evans } 1805952343eSKyle Evans 1815952343eSKyle Evans 18216a10da8SKyle Evans /* 18316a10da8SKyle Evans * TODO: when only one arg is given, and it contains an "@" the this should 18416a10da8SKyle Evans * create that snapshot 18516a10da8SKyle Evans */ 1865952343eSKyle Evans static int 1879e004b21SKyle Evans bectl_cmd_create(int argc, char *argv[]) 1885952343eSKyle Evans { 189d05fa0d9SKyle Evans char snapshot[BE_MAXPATHLEN]; 190d05fa0d9SKyle Evans char *atpos, *bootenv, *snapname; 1915952343eSKyle Evans int err, opt; 192a9c660b0SKyle Evans bool recursive; 1935952343eSKyle Evans 1945952343eSKyle Evans snapname = NULL; 195a9c660b0SKyle Evans recursive = false; 19625eeb3eaSKyle Evans while ((opt = getopt(argc, argv, "e:r")) != -1) { 1975952343eSKyle Evans switch (opt) { 1985952343eSKyle Evans case 'e': 1995952343eSKyle Evans snapname = optarg; 2005952343eSKyle Evans break; 201a9c660b0SKyle Evans case 'r': 202a9c660b0SKyle Evans recursive = true; 20325eeb3eaSKyle Evans break; 2045952343eSKyle Evans default: 2052c848957SKyle Evans fprintf(stderr, "bectl create: unknown option '-%c'\n", 2065952343eSKyle Evans optopt); 2075952343eSKyle Evans return (usage(false)); 2085952343eSKyle Evans } 2095952343eSKyle Evans } 2105952343eSKyle Evans 2115952343eSKyle Evans argc -= optind; 2125952343eSKyle Evans argv += optind; 2135952343eSKyle Evans 2145952343eSKyle Evans if (argc != 1) { 2152c848957SKyle Evans fprintf(stderr, "bectl create: wrong number of arguments\n"); 2165952343eSKyle Evans return (usage(false)); 2175952343eSKyle Evans } 2185952343eSKyle Evans 2195952343eSKyle Evans bootenv = *argv; 220d05fa0d9SKyle Evans 221d05fa0d9SKyle Evans err = BE_ERR_SUCCESS; 222a9c660b0SKyle Evans if ((atpos = strchr(bootenv, '@')) != NULL) { 223a9c660b0SKyle Evans /* 224a9c660b0SKyle Evans * This is the "create a snapshot variant". No new boot 225a9c660b0SKyle Evans * environment is to be created here. 226a9c660b0SKyle Evans */ 227a9c660b0SKyle Evans *atpos++ = '\0'; 228a9c660b0SKyle Evans err = be_snapshot(be, bootenv, atpos, recursive, NULL); 2295952343eSKyle Evans } else { 230d05fa0d9SKyle Evans if (snapname == NULL) 231d05fa0d9SKyle Evans /* Create from currently booted BE */ 232d05fa0d9SKyle Evans err = be_snapshot(be, be_active_path(be), NULL, 233d05fa0d9SKyle Evans recursive, snapshot); 234d05fa0d9SKyle Evans else if (strchr(snapname, '@') != NULL) 235d05fa0d9SKyle Evans /* Create from given snapshot */ 236d05fa0d9SKyle Evans strlcpy(snapshot, snapname, sizeof(snapshot)); 237d05fa0d9SKyle Evans else 238d05fa0d9SKyle Evans /* Create from given BE */ 239d05fa0d9SKyle Evans err = be_snapshot(be, snapname, NULL, recursive, 240d05fa0d9SKyle Evans snapshot); 241d05fa0d9SKyle Evans 242d05fa0d9SKyle Evans if (err == BE_ERR_SUCCESS) 243d05fa0d9SKyle Evans err = be_create_depth(be, bootenv, snapshot, 244d05fa0d9SKyle Evans recursive == true ? -1 : 0); 2455952343eSKyle Evans } 2465952343eSKyle Evans 2475952343eSKyle Evans switch (err) { 2485952343eSKyle Evans case BE_ERR_SUCCESS: 2495952343eSKyle Evans break; 2505952343eSKyle Evans default: 251a9c660b0SKyle Evans if (atpos != NULL) 252a9c660b0SKyle Evans fprintf(stderr, 253a9c660b0SKyle Evans "failed to create a snapshot '%s' of '%s'\n", 254a9c660b0SKyle Evans atpos, bootenv); 255a9c660b0SKyle Evans else if (snapname == NULL) 2565952343eSKyle Evans fprintf(stderr, 2575952343eSKyle Evans "failed to create bootenv %s\n", bootenv); 25816a10da8SKyle Evans else 2595952343eSKyle Evans fprintf(stderr, 2605952343eSKyle Evans "failed to create bootenv %s from snapshot %s\n", 2615952343eSKyle Evans bootenv, snapname); 2625952343eSKyle Evans } 2635952343eSKyle Evans 2645952343eSKyle Evans return (err); 2655952343eSKyle Evans } 2665952343eSKyle Evans 2675952343eSKyle Evans 2685952343eSKyle Evans static int 2699e004b21SKyle Evans bectl_cmd_export(int argc, char *argv[]) 2705952343eSKyle Evans { 2715952343eSKyle Evans char *bootenv; 2725952343eSKyle Evans 2735952343eSKyle Evans if (argc == 1) { 2742c848957SKyle Evans fprintf(stderr, "bectl export: missing boot environment name\n"); 2755952343eSKyle Evans return (usage(false)); 2765952343eSKyle Evans } 2775952343eSKyle Evans 2785952343eSKyle Evans if (argc > 2) { 2792c848957SKyle Evans fprintf(stderr, "bectl export: extra arguments provided\n"); 2805952343eSKyle Evans return (usage(false)); 2815952343eSKyle Evans } 2825952343eSKyle Evans 2835952343eSKyle Evans bootenv = argv[1]; 2845952343eSKyle Evans 2855952343eSKyle Evans if (isatty(STDOUT_FILENO)) { 2862c848957SKyle Evans fprintf(stderr, "bectl export: must redirect output\n"); 2875952343eSKyle Evans return (EX_USAGE); 2885952343eSKyle Evans } 2895952343eSKyle Evans 2905952343eSKyle Evans be_export(be, bootenv, STDOUT_FILENO); 2915952343eSKyle Evans 2925952343eSKyle Evans return (0); 2935952343eSKyle Evans } 2945952343eSKyle Evans 2955952343eSKyle Evans 2965952343eSKyle Evans static int 2979e004b21SKyle Evans bectl_cmd_import(int argc, char *argv[]) 2985952343eSKyle Evans { 2995952343eSKyle Evans char *bootenv; 3005952343eSKyle Evans int err; 3015952343eSKyle Evans 3025952343eSKyle Evans if (argc == 1) { 3032c848957SKyle Evans fprintf(stderr, "bectl import: missing boot environment name\n"); 3045952343eSKyle Evans return (usage(false)); 3055952343eSKyle Evans } 3065952343eSKyle Evans 3075952343eSKyle Evans if (argc > 2) { 3082c848957SKyle Evans fprintf(stderr, "bectl import: extra arguments provided\n"); 3095952343eSKyle Evans return (usage(false)); 3105952343eSKyle Evans } 3115952343eSKyle Evans 3125952343eSKyle Evans bootenv = argv[1]; 3135952343eSKyle Evans 3145952343eSKyle Evans if (isatty(STDIN_FILENO)) { 3152c848957SKyle Evans fprintf(stderr, "bectl import: input can not be from terminal\n"); 3165952343eSKyle Evans return (EX_USAGE); 3175952343eSKyle Evans } 3185952343eSKyle Evans 3195952343eSKyle Evans err = be_import(be, bootenv, STDIN_FILENO); 3205952343eSKyle Evans 3215952343eSKyle Evans return (err); 3225952343eSKyle Evans } 3235952343eSKyle Evans 3243d1a1f2cSKyle Evans #if SOON 3255952343eSKyle Evans static int 3269e004b21SKyle Evans bectl_cmd_add(int argc, char *argv[]) 3275952343eSKyle Evans { 3285952343eSKyle Evans 3295952343eSKyle Evans if (argc < 2) { 3302c848957SKyle Evans fprintf(stderr, "bectl add: must provide at least one path\n"); 3315952343eSKyle Evans return (usage(false)); 3325952343eSKyle Evans } 3335952343eSKyle Evans 3345952343eSKyle Evans for (int i = 1; i < argc; ++i) { 3355952343eSKyle Evans printf("arg %d: %s\n", i, argv[i]); 33616a10da8SKyle Evans /* XXX TODO catch err */ 3375952343eSKyle Evans be_add_child(be, argv[i], true); 3385952343eSKyle Evans } 3395952343eSKyle Evans 3405952343eSKyle Evans return (0); 3415952343eSKyle Evans } 3423d1a1f2cSKyle Evans #endif 3435952343eSKyle Evans 3445952343eSKyle Evans static int 3459e004b21SKyle Evans bectl_cmd_destroy(int argc, char *argv[]) 3465952343eSKyle Evans { 34777b4126cSKyle Evans nvlist_t *props; 34877b4126cSKyle Evans char *origin, *target, targetds[BE_MAXPATHLEN]; 34977b4126cSKyle Evans int err, flags, opt; 3505952343eSKyle Evans 35177b4126cSKyle Evans flags = 0; 35277b4126cSKyle Evans while ((opt = getopt(argc, argv, "Fo")) != -1) { 3535952343eSKyle Evans switch (opt) { 3545952343eSKyle Evans case 'F': 35577b4126cSKyle Evans flags |= BE_DESTROY_FORCE; 35677b4126cSKyle Evans break; 35777b4126cSKyle Evans case 'o': 35877b4126cSKyle Evans flags |= BE_DESTROY_ORIGIN; 3595952343eSKyle Evans break; 3605952343eSKyle Evans default: 3612c848957SKyle Evans fprintf(stderr, "bectl destroy: unknown option '-%c'\n", 3625952343eSKyle Evans optopt); 3635952343eSKyle Evans return (usage(false)); 3645952343eSKyle Evans } 3655952343eSKyle Evans } 3665952343eSKyle Evans 3675952343eSKyle Evans argc -= optind; 3685952343eSKyle Evans argv += optind; 3695952343eSKyle Evans 3705952343eSKyle Evans if (argc != 1) { 3712c848957SKyle Evans fprintf(stderr, "bectl destroy: wrong number of arguments\n"); 3725952343eSKyle Evans return (usage(false)); 3735952343eSKyle Evans } 3745952343eSKyle Evans 3755952343eSKyle Evans target = argv[0]; 3765952343eSKyle Evans 37777b4126cSKyle Evans /* We'll emit a notice if there's an origin to be cleaned up */ 37877b4126cSKyle Evans if ((flags & BE_DESTROY_ORIGIN) == 0 && strchr(target, '@') == NULL) { 37977b4126cSKyle Evans if (be_root_concat(be, target, targetds) != 0) 38077b4126cSKyle Evans goto destroy; 38177b4126cSKyle Evans if (be_prop_list_alloc(&props) != 0) 38277b4126cSKyle Evans goto destroy; 38377b4126cSKyle Evans if (be_get_dataset_props(be, targetds, props) != 0) { 38477b4126cSKyle Evans be_prop_list_free(props); 38577b4126cSKyle Evans goto destroy; 38677b4126cSKyle Evans } 38777b4126cSKyle Evans if (nvlist_lookup_string(props, "origin", &origin) == 0) 38877b4126cSKyle Evans fprintf(stderr, "bectl destroy: leaving origin '%s' intact\n", 38977b4126cSKyle Evans origin); 39077b4126cSKyle Evans be_prop_list_free(props); 39177b4126cSKyle Evans } 39277b4126cSKyle Evans 39377b4126cSKyle Evans destroy: 39477b4126cSKyle Evans err = be_destroy(be, target, flags); 3955952343eSKyle Evans 3965952343eSKyle Evans return (err); 3975952343eSKyle Evans } 3985952343eSKyle Evans 3995952343eSKyle Evans static int 4009e004b21SKyle Evans bectl_cmd_mount(int argc, char *argv[]) 4015952343eSKyle Evans { 4025952343eSKyle Evans char result_loc[BE_MAXPATHLEN]; 40316a10da8SKyle Evans char *bootenv, *mountpoint; 4040a603a6eSKyle Evans int err, mntflags; 4055952343eSKyle Evans 4060a603a6eSKyle Evans /* XXX TODO: Allow shallow */ 4070a603a6eSKyle Evans mntflags = BE_MNT_DEEP; 4085952343eSKyle Evans if (argc < 2) { 4092c848957SKyle Evans fprintf(stderr, "bectl mount: missing argument(s)\n"); 4105952343eSKyle Evans return (usage(false)); 4115952343eSKyle Evans } 4125952343eSKyle Evans 4135952343eSKyle Evans if (argc > 3) { 4142c848957SKyle Evans fprintf(stderr, "bectl mount: too many arguments\n"); 4155952343eSKyle Evans return (usage(false)); 4165952343eSKyle Evans } 4175952343eSKyle Evans 4185952343eSKyle Evans bootenv = argv[1]; 4195952343eSKyle Evans mountpoint = ((argc == 3) ? argv[2] : NULL); 4205952343eSKyle Evans 4210a603a6eSKyle Evans err = be_mount(be, bootenv, mountpoint, mntflags, result_loc); 4225952343eSKyle Evans 4235952343eSKyle Evans switch (err) { 4245952343eSKyle Evans case BE_ERR_SUCCESS: 4255952343eSKyle Evans printf("successfully mounted %s at %s\n", bootenv, result_loc); 4265952343eSKyle Evans break; 4275952343eSKyle Evans default: 4285952343eSKyle Evans fprintf(stderr, 4295952343eSKyle Evans (argc == 3) ? "failed to mount bootenv %s at %s\n" : 4305952343eSKyle Evans "failed to mount bootenv %s at temporary path %s\n", 4315952343eSKyle Evans bootenv, mountpoint); 4325952343eSKyle Evans } 4335952343eSKyle Evans 4345952343eSKyle Evans return (err); 4355952343eSKyle Evans } 4365952343eSKyle Evans 4375952343eSKyle Evans 4385952343eSKyle Evans static int 4399e004b21SKyle Evans bectl_cmd_rename(int argc, char *argv[]) 4405952343eSKyle Evans { 44116a10da8SKyle Evans char *dest, *src; 4425952343eSKyle Evans int err; 4435952343eSKyle Evans 4445952343eSKyle Evans if (argc < 3) { 4452c848957SKyle Evans fprintf(stderr, "bectl rename: missing argument\n"); 4465952343eSKyle Evans return (usage(false)); 4475952343eSKyle Evans } 4485952343eSKyle Evans 4495952343eSKyle Evans if (argc > 3) { 4502c848957SKyle Evans fprintf(stderr, "bectl rename: too many arguments\n"); 4515952343eSKyle Evans return (usage(false)); 4525952343eSKyle Evans } 4535952343eSKyle Evans 4545952343eSKyle Evans src = argv[1]; 4555952343eSKyle Evans dest = argv[2]; 4565952343eSKyle Evans 4575952343eSKyle Evans err = be_rename(be, src, dest); 4585952343eSKyle Evans 4595952343eSKyle Evans switch (err) { 4605952343eSKyle Evans case BE_ERR_SUCCESS: 4615952343eSKyle Evans break; 4625952343eSKyle Evans default: 4635952343eSKyle Evans fprintf(stderr, "failed to rename bootenv %s to %s\n", 4645952343eSKyle Evans src, dest); 4655952343eSKyle Evans } 4665952343eSKyle Evans 4675952343eSKyle Evans return (0); 4685952343eSKyle Evans } 4695952343eSKyle Evans 470ad765da4SKyle Evans static int 4719e004b21SKyle Evans bectl_cmd_unmount(int argc, char *argv[]) 4725952343eSKyle Evans { 47316a10da8SKyle Evans char *bootenv, *cmd; 4745952343eSKyle Evans int err, flags, opt; 4755952343eSKyle Evans 4765952343eSKyle Evans /* Store alias used */ 4775952343eSKyle Evans cmd = argv[0]; 4785952343eSKyle Evans 4795952343eSKyle Evans flags = 0; 4805952343eSKyle Evans while ((opt = getopt(argc, argv, "f")) != -1) { 4815952343eSKyle Evans switch (opt) { 4825952343eSKyle Evans case 'f': 4835952343eSKyle Evans flags |= BE_MNT_FORCE; 4845952343eSKyle Evans break; 4855952343eSKyle Evans default: 4862c848957SKyle Evans fprintf(stderr, "bectl %s: unknown option '-%c'\n", 4875952343eSKyle Evans cmd, optopt); 4885952343eSKyle Evans return (usage(false)); 4895952343eSKyle Evans } 4905952343eSKyle Evans } 4915952343eSKyle Evans 4925952343eSKyle Evans argc -= optind; 4935952343eSKyle Evans argv += optind; 4945952343eSKyle Evans 4955952343eSKyle Evans if (argc != 1) { 4962c848957SKyle Evans fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd); 4975952343eSKyle Evans return (usage(false)); 4985952343eSKyle Evans } 4995952343eSKyle Evans 5005952343eSKyle Evans bootenv = argv[0]; 5015952343eSKyle Evans 5025952343eSKyle Evans err = be_unmount(be, bootenv, flags); 5035952343eSKyle Evans 5045952343eSKyle Evans switch (err) { 5055952343eSKyle Evans case BE_ERR_SUCCESS: 5065952343eSKyle Evans break; 5075952343eSKyle Evans default: 5085952343eSKyle Evans fprintf(stderr, "failed to unmount bootenv %s\n", bootenv); 5095952343eSKyle Evans } 5105952343eSKyle Evans 5115952343eSKyle Evans return (err); 5125952343eSKyle Evans } 5135952343eSKyle Evans 514*490e13c1SKyle Evans static int 515*490e13c1SKyle Evans bectl_cmd_check(int argc, char *argv[] __unused) 516*490e13c1SKyle Evans { 517*490e13c1SKyle Evans 518*490e13c1SKyle Evans /* The command is left as argv[0] */ 519*490e13c1SKyle Evans if (argc != 1) { 520*490e13c1SKyle Evans fprintf(stderr, "bectl check: wrong number of arguments\n"); 521*490e13c1SKyle Evans return (usage(false)); 522*490e13c1SKyle Evans } 523*490e13c1SKyle Evans 524*490e13c1SKyle Evans return (0); 525*490e13c1SKyle Evans } 5265952343eSKyle Evans 5275952343eSKyle Evans int 5285952343eSKyle Evans main(int argc, char *argv[]) 5295952343eSKyle Evans { 530*490e13c1SKyle Evans struct command_map_entry *cmd; 531b29bf2f8SKyle Evans const char *command; 532cc624025SKyle Evans char *root; 533*490e13c1SKyle Evans int rc; 5345952343eSKyle Evans 535*490e13c1SKyle Evans cmd = NULL; 536cc624025SKyle Evans root = NULL; 5378369ba42SKyle Evans if (argc < 2) 5385952343eSKyle Evans return (usage(false)); 5395952343eSKyle Evans 540cc624025SKyle Evans if (strcmp(argv[1], "-r") == 0) { 541cc624025SKyle Evans if (argc < 4) 542cc624025SKyle Evans return (usage(false)); 543cc624025SKyle Evans root = strdup(argv[2]); 544cc624025SKyle Evans command = argv[3]; 545cc624025SKyle Evans argc -= 3; 546cc624025SKyle Evans argv += 3; 547cc624025SKyle Evans } else { 5485952343eSKyle Evans command = argv[1]; 549cc624025SKyle Evans argc -= 1; 550cc624025SKyle Evans argv += 1; 551cc624025SKyle Evans } 5525952343eSKyle Evans 5535952343eSKyle Evans /* Handle command aliases */ 55416a10da8SKyle Evans if (strcmp(command, "umount") == 0) 5555952343eSKyle Evans command = "unmount"; 5565952343eSKyle Evans 55716a10da8SKyle Evans if (strcmp(command, "ujail") == 0) 5585952343eSKyle Evans command = "unjail"; 5595952343eSKyle Evans 56016a10da8SKyle Evans if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0)) 5615952343eSKyle Evans return (usage(true)); 5625952343eSKyle Evans 563*490e13c1SKyle Evans if ((cmd = get_cmd_info(command)) == NULL) { 5645952343eSKyle Evans fprintf(stderr, "unknown command: %s\n", command); 5655952343eSKyle Evans return (usage(false)); 5665952343eSKyle Evans } 5675952343eSKyle Evans 568cc624025SKyle Evans if ((be = libbe_init(root)) == NULL) 5695952343eSKyle Evans return (-1); 5705952343eSKyle Evans 571*490e13c1SKyle Evans libbe_print_on_error(be, !cmd->silent); 5725952343eSKyle Evans 573*490e13c1SKyle Evans rc = cmd->fn(argc, argv); 5745952343eSKyle Evans 5755952343eSKyle Evans libbe_close(be); 5765952343eSKyle Evans return (rc); 5775952343eSKyle Evans } 578