1b179da01SKyle Evans /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35952343eSKyle Evans * 45952343eSKyle Evans * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> 55952343eSKyle Evans * 65952343eSKyle Evans * Redistribution and use in source and binary forms, with or without 75952343eSKyle Evans * modification, are permitted provided that the following conditions 85952343eSKyle Evans * are met: 95952343eSKyle Evans * 1. Redistributions of source code must retain the above copyright 105952343eSKyle Evans * notice, this list of conditions and the following disclaimer. 115952343eSKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 125952343eSKyle Evans * notice, this list of conditions and the following disclaimer in the 135952343eSKyle Evans * documentation and/or other materials provided with the distribution. 145952343eSKyle Evans * 155952343eSKyle Evans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 165952343eSKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 175952343eSKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 185952343eSKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 195952343eSKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 205952343eSKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 215952343eSKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 225952343eSKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 235952343eSKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 245952343eSKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 255952343eSKyle Evans * SUCH DAMAGE. 265952343eSKyle Evans */ 275952343eSKyle Evans 28b6e7c421SKyle Evans #include <sys/cdefs.h> 29b6e7c421SKyle Evans __FBSDID("$FreeBSD$"); 30b6e7c421SKyle Evans 315952343eSKyle Evans #include <sys/param.h> 325952343eSKyle Evans #include <sys/mount.h> 335952343eSKyle Evans #include <errno.h> 3483244ec1SKyle Evans #include <libutil.h> 355952343eSKyle Evans #include <stdbool.h> 365952343eSKyle Evans #include <stdio.h> 375952343eSKyle Evans #include <stdint.h> 385952343eSKyle Evans #include <stdlib.h> 395952343eSKyle Evans #include <string.h> 405952343eSKyle Evans #include <sysexits.h> 4183244ec1SKyle Evans #include <time.h> 425952343eSKyle Evans #include <unistd.h> 435952343eSKyle Evans 445952343eSKyle Evans #include <be.h> 455952343eSKyle Evans 46d694059fSKyle Evans #include "bectl.h" 47d694059fSKyle Evans 489e004b21SKyle Evans static int bectl_cmd_activate(int argc, char *argv[]); 49490e13c1SKyle Evans static int bectl_cmd_check(int argc, char *argv[]); 509e004b21SKyle Evans static int bectl_cmd_create(int argc, char *argv[]); 519e004b21SKyle Evans static int bectl_cmd_destroy(int argc, char *argv[]); 529e004b21SKyle Evans static int bectl_cmd_export(int argc, char *argv[]); 539e004b21SKyle Evans static int bectl_cmd_import(int argc, char *argv[]); 543d1a1f2cSKyle Evans #if SOON 559e004b21SKyle Evans static int bectl_cmd_add(int argc, char *argv[]); 563d1a1f2cSKyle Evans #endif 579e004b21SKyle Evans static int bectl_cmd_mount(int argc, char *argv[]); 589e004b21SKyle Evans static int bectl_cmd_rename(int argc, char *argv[]); 599e004b21SKyle Evans static int bectl_cmd_unmount(int argc, char *argv[]); 605952343eSKyle Evans 61d694059fSKyle Evans libbe_handle_t *be; 625952343eSKyle Evans 63d694059fSKyle Evans int 645952343eSKyle Evans usage(bool explicit) 655952343eSKyle Evans { 6616a10da8SKyle Evans FILE *fp; 675952343eSKyle Evans 6816a10da8SKyle Evans fp = explicit ? stdout : stderr; 6952ee41b7SYuri Pankov fprintf(fp, "%s", 7023614c2bSBenedict Reuschling "Usage:\tbectl {-h | -? | subcommand [args...]}\n" 713d1a1f2cSKyle Evans #if SOON 724163bae0SKyle Evans "\tbectl [-r beroot] add (path)*\n" 733d1a1f2cSKyle Evans #endif 744163bae0SKyle Evans "\tbectl [-r beroot] activate [-t] beName\n" 754163bae0SKyle Evans "\tbectl [-r beroot] activate [-T]\n" 764163bae0SKyle Evans "\tbectl [-r beroot] check\n" 774163bae0SKyle Evans "\tbectl [-r beroot] create [-r] [-e {nonActiveBe | beName@snapshot}] beName\n" 784163bae0SKyle Evans "\tbectl [-r beroot] create [-r] beName@snapshot\n" 794163bae0SKyle Evans "\tbectl [-r beroot] destroy [-Fo] {beName | beName@snapshot}\n" 804163bae0SKyle Evans "\tbectl [-r beroot] export sourceBe\n" 814163bae0SKyle Evans "\tbectl [-r beroot] import targetBe\n" 824163bae0SKyle Evans "\tbectl [-r beroot] jail [-bU] [{-o key=value | -u key}]... beName\n" 83b1ea63e2SRobert Wing "\t [utility [argument ...]]\n" 844163bae0SKyle Evans "\tbectl [-r beroot] list [-aDHs] [{-c property | -C property}]\n" 854163bae0SKyle Evans "\tbectl [-r beroot] mount beName [mountpoint]\n" 864163bae0SKyle Evans "\tbectl [-r beroot] rename origBeName newBeName\n" 874163bae0SKyle Evans "\tbectl [-r beroot] {ujail | unjail} {jailID | jailName | beName}\n" 884163bae0SKyle Evans "\tbectl [-r beroot] {umount | unmount} [-f] beName\n"); 895952343eSKyle Evans 905952343eSKyle Evans return (explicit ? 0 : EX_USAGE); 915952343eSKyle Evans } 925952343eSKyle Evans 935952343eSKyle Evans 945952343eSKyle Evans /* 955952343eSKyle Evans * Represents a relationship between the command name and the parser action 965952343eSKyle Evans * that handles it. 975952343eSKyle Evans */ 985952343eSKyle Evans struct command_map_entry { 995952343eSKyle Evans const char *command; 1005952343eSKyle Evans int (*fn)(int argc, char *argv[]); 101490e13c1SKyle Evans /* True if libbe_print_on_error should be disabled */ 102490e13c1SKyle Evans bool silent; 1035952343eSKyle Evans }; 1045952343eSKyle Evans 1055952343eSKyle Evans static struct command_map_entry command_map[] = 1065952343eSKyle Evans { 107490e13c1SKyle Evans { "activate", bectl_cmd_activate,false }, 108490e13c1SKyle Evans { "create", bectl_cmd_create, false }, 109490e13c1SKyle Evans { "destroy", bectl_cmd_destroy, false }, 110490e13c1SKyle Evans { "export", bectl_cmd_export, false }, 111490e13c1SKyle Evans { "import", bectl_cmd_import, false }, 1123d1a1f2cSKyle Evans #if SOON 113490e13c1SKyle Evans { "add", bectl_cmd_add, false }, 1143d1a1f2cSKyle Evans #endif 115490e13c1SKyle Evans { "jail", bectl_cmd_jail, false }, 116490e13c1SKyle Evans { "list", bectl_cmd_list, false }, 117490e13c1SKyle Evans { "mount", bectl_cmd_mount, false }, 118490e13c1SKyle Evans { "rename", bectl_cmd_rename, false }, 119490e13c1SKyle Evans { "unjail", bectl_cmd_unjail, false }, 120490e13c1SKyle Evans { "unmount", bectl_cmd_unmount, false }, 121490e13c1SKyle Evans { "check", bectl_cmd_check, true }, 1225952343eSKyle Evans }; 1235952343eSKyle Evans 124490e13c1SKyle Evans static struct command_map_entry * 125490e13c1SKyle Evans get_cmd_info(const char *cmd) 1265952343eSKyle Evans { 127490e13c1SKyle Evans size_t i; 1285952343eSKyle Evans 129490e13c1SKyle Evans for (i = 0; i < nitems(command_map); ++i) { 130490e13c1SKyle Evans if (strcmp(cmd, command_map[i].command) == 0) 131490e13c1SKyle Evans return (&command_map[i]); 1325952343eSKyle Evans } 1335952343eSKyle Evans 134490e13c1SKyle Evans return (NULL); 1355952343eSKyle Evans } 1365952343eSKyle Evans 1375952343eSKyle Evans static int 1389e004b21SKyle Evans bectl_cmd_activate(int argc, char *argv[]) 1395952343eSKyle Evans { 1405952343eSKyle Evans int err, opt; 141e307eb94SToomas Soome bool temp, reset; 1425952343eSKyle Evans 1435952343eSKyle Evans temp = false; 144e307eb94SToomas Soome reset = false; 145e307eb94SToomas Soome while ((opt = getopt(argc, argv, "tT")) != -1) { 1465952343eSKyle Evans switch (opt) { 1475952343eSKyle Evans case 't': 148e307eb94SToomas Soome if (reset) 149e307eb94SToomas Soome return (usage(false)); 1505952343eSKyle Evans temp = true; 1515952343eSKyle Evans break; 152e307eb94SToomas Soome case 'T': 153e307eb94SToomas Soome if (temp) 154e307eb94SToomas Soome return (usage(false)); 155e307eb94SToomas Soome reset = true; 156e307eb94SToomas Soome break; 1575952343eSKyle Evans default: 1582c848957SKyle Evans fprintf(stderr, "bectl activate: unknown option '-%c'\n", 1595952343eSKyle Evans optopt); 1605952343eSKyle Evans return (usage(false)); 1615952343eSKyle Evans } 1625952343eSKyle Evans } 1635952343eSKyle Evans 1645952343eSKyle Evans argc -= optind; 1655952343eSKyle Evans argv += optind; 1665952343eSKyle Evans 167e307eb94SToomas Soome if (argc != 1 && (!reset || argc != 0)) { 1682c848957SKyle Evans fprintf(stderr, "bectl activate: wrong number of arguments\n"); 1695952343eSKyle Evans return (usage(false)); 1705952343eSKyle Evans } 1715952343eSKyle Evans 172e307eb94SToomas Soome if (reset) { 173e307eb94SToomas Soome if ((err = be_deactivate(be, NULL, reset)) == 0) 174e307eb94SToomas Soome printf("Temporary activation removed\n"); 175e307eb94SToomas Soome else 176e307eb94SToomas Soome printf("Failed to remove temporary activation\n"); 177e307eb94SToomas Soome return (err); 178e307eb94SToomas Soome } 1795952343eSKyle Evans 1805952343eSKyle Evans /* activate logic goes here */ 18116a10da8SKyle Evans if ((err = be_activate(be, argv[0], temp)) != 0) 18216a10da8SKyle Evans /* XXX TODO: more specific error msg based on err */ 18323614c2bSBenedict Reuschling printf("Did not successfully activate boot environment %s\n", 1845952343eSKyle Evans argv[0]); 18516a10da8SKyle Evans else 18623614c2bSBenedict Reuschling printf("Successfully activated boot environment %s\n", argv[0]); 1875952343eSKyle Evans 18816a10da8SKyle Evans if (temp) 1895952343eSKyle Evans printf("for next boot\n"); 1905952343eSKyle Evans 1915952343eSKyle Evans return (err); 1925952343eSKyle Evans } 1935952343eSKyle Evans 1945952343eSKyle Evans 19516a10da8SKyle Evans /* 19616a10da8SKyle Evans * TODO: when only one arg is given, and it contains an "@" the this should 19716a10da8SKyle Evans * create that snapshot 19816a10da8SKyle Evans */ 1995952343eSKyle Evans static int 2009e004b21SKyle Evans bectl_cmd_create(int argc, char *argv[]) 2015952343eSKyle Evans { 202d05fa0d9SKyle Evans char snapshot[BE_MAXPATHLEN]; 203d05fa0d9SKyle Evans char *atpos, *bootenv, *snapname; 2045952343eSKyle Evans int err, opt; 205a9c660b0SKyle Evans bool recursive; 2065952343eSKyle Evans 2075952343eSKyle Evans snapname = NULL; 208a9c660b0SKyle Evans recursive = false; 20925eeb3eaSKyle Evans while ((opt = getopt(argc, argv, "e:r")) != -1) { 2105952343eSKyle Evans switch (opt) { 2115952343eSKyle Evans case 'e': 2125952343eSKyle Evans snapname = optarg; 2135952343eSKyle Evans break; 214a9c660b0SKyle Evans case 'r': 215a9c660b0SKyle Evans recursive = true; 21625eeb3eaSKyle Evans break; 2175952343eSKyle Evans default: 2182c848957SKyle Evans fprintf(stderr, "bectl create: unknown option '-%c'\n", 2195952343eSKyle Evans optopt); 2205952343eSKyle Evans return (usage(false)); 2215952343eSKyle Evans } 2225952343eSKyle Evans } 2235952343eSKyle Evans 2245952343eSKyle Evans argc -= optind; 2255952343eSKyle Evans argv += optind; 2265952343eSKyle Evans 2275952343eSKyle Evans if (argc != 1) { 2282c848957SKyle Evans fprintf(stderr, "bectl create: wrong number of arguments\n"); 2295952343eSKyle Evans return (usage(false)); 2305952343eSKyle Evans } 2315952343eSKyle Evans 2325952343eSKyle Evans bootenv = *argv; 233d05fa0d9SKyle Evans 234d05fa0d9SKyle Evans err = BE_ERR_SUCCESS; 235dadb9c70SKyle Evans if ((atpos = strchr(bootenv, '@')) != NULL) { 236a9c660b0SKyle Evans /* 237a9c660b0SKyle Evans * This is the "create a snapshot variant". No new boot 238a9c660b0SKyle Evans * environment is to be created here. 239a9c660b0SKyle Evans */ 240a9c660b0SKyle Evans *atpos++ = '\0'; 241a9c660b0SKyle Evans err = be_snapshot(be, bootenv, atpos, recursive, NULL); 2425952343eSKyle Evans } else { 243d05fa0d9SKyle Evans if (snapname == NULL) 244d05fa0d9SKyle Evans /* Create from currently booted BE */ 245d05fa0d9SKyle Evans err = be_snapshot(be, be_active_path(be), NULL, 246d05fa0d9SKyle Evans recursive, snapshot); 247d05fa0d9SKyle Evans else if (strchr(snapname, '@') != NULL) 248d05fa0d9SKyle Evans /* Create from given snapshot */ 249d05fa0d9SKyle Evans strlcpy(snapshot, snapname, sizeof(snapshot)); 250d05fa0d9SKyle Evans else 251d05fa0d9SKyle Evans /* Create from given BE */ 252d05fa0d9SKyle Evans err = be_snapshot(be, snapname, NULL, recursive, 253d05fa0d9SKyle Evans snapshot); 254d05fa0d9SKyle Evans 255d05fa0d9SKyle Evans if (err == BE_ERR_SUCCESS) 256d05fa0d9SKyle Evans err = be_create_depth(be, bootenv, snapshot, 257d05fa0d9SKyle Evans recursive == true ? -1 : 0); 2585952343eSKyle Evans } 2595952343eSKyle Evans 2605952343eSKyle Evans switch (err) { 2615952343eSKyle Evans case BE_ERR_SUCCESS: 2625952343eSKyle Evans break; 2630e6549c8SRobert Wing case BE_ERR_INVALIDNAME: 2640e6549c8SRobert Wing fprintf(stderr, 2650e6549c8SRobert Wing "bectl create: boot environment name must not contain spaces\n"); 2660e6549c8SRobert Wing break; 2675952343eSKyle Evans default: 268a9c660b0SKyle Evans if (atpos != NULL) 269a9c660b0SKyle Evans fprintf(stderr, 27023614c2bSBenedict Reuschling "Failed to create a snapshot '%s' of '%s'\n", 271a9c660b0SKyle Evans atpos, bootenv); 272a9c660b0SKyle Evans else if (snapname == NULL) 2735952343eSKyle Evans fprintf(stderr, 27423614c2bSBenedict Reuschling "Failed to create bootenv %s\n", bootenv); 27516a10da8SKyle Evans else 2765952343eSKyle Evans fprintf(stderr, 27723614c2bSBenedict Reuschling "Failed to create bootenv %s from snapshot %s\n", 2785952343eSKyle Evans bootenv, snapname); 2795952343eSKyle Evans } 2805952343eSKyle Evans 2815952343eSKyle Evans return (err); 2825952343eSKyle Evans } 2835952343eSKyle Evans 2845952343eSKyle Evans 2855952343eSKyle Evans static int 2869e004b21SKyle Evans bectl_cmd_export(int argc, char *argv[]) 2875952343eSKyle Evans { 2885952343eSKyle Evans char *bootenv; 2895952343eSKyle Evans 2905952343eSKyle Evans if (argc == 1) { 2912c848957SKyle Evans fprintf(stderr, "bectl export: missing boot environment name\n"); 2925952343eSKyle Evans return (usage(false)); 2935952343eSKyle Evans } 2945952343eSKyle Evans 2955952343eSKyle Evans if (argc > 2) { 2962c848957SKyle Evans fprintf(stderr, "bectl export: extra arguments provided\n"); 2975952343eSKyle Evans return (usage(false)); 2985952343eSKyle Evans } 2995952343eSKyle Evans 3005952343eSKyle Evans bootenv = argv[1]; 3015952343eSKyle Evans 3025952343eSKyle Evans if (isatty(STDOUT_FILENO)) { 3032c848957SKyle Evans fprintf(stderr, "bectl export: must redirect output\n"); 3045952343eSKyle Evans return (EX_USAGE); 3055952343eSKyle Evans } 3065952343eSKyle Evans 3075952343eSKyle Evans be_export(be, bootenv, STDOUT_FILENO); 3085952343eSKyle Evans 3095952343eSKyle Evans return (0); 3105952343eSKyle Evans } 3115952343eSKyle Evans 3125952343eSKyle Evans 3135952343eSKyle Evans static int 3149e004b21SKyle Evans bectl_cmd_import(int argc, char *argv[]) 3155952343eSKyle Evans { 3165952343eSKyle Evans char *bootenv; 3175952343eSKyle Evans int err; 3185952343eSKyle Evans 3195952343eSKyle Evans if (argc == 1) { 3202c848957SKyle Evans fprintf(stderr, "bectl import: missing boot environment name\n"); 3215952343eSKyle Evans return (usage(false)); 3225952343eSKyle Evans } 3235952343eSKyle Evans 3245952343eSKyle Evans if (argc > 2) { 3252c848957SKyle Evans fprintf(stderr, "bectl import: extra arguments provided\n"); 3265952343eSKyle Evans return (usage(false)); 3275952343eSKyle Evans } 3285952343eSKyle Evans 3295952343eSKyle Evans bootenv = argv[1]; 3305952343eSKyle Evans 3315952343eSKyle Evans if (isatty(STDIN_FILENO)) { 3322c848957SKyle Evans fprintf(stderr, "bectl import: input can not be from terminal\n"); 3335952343eSKyle Evans return (EX_USAGE); 3345952343eSKyle Evans } 3355952343eSKyle Evans 3365952343eSKyle Evans err = be_import(be, bootenv, STDIN_FILENO); 3375952343eSKyle Evans 3385952343eSKyle Evans return (err); 3395952343eSKyle Evans } 3405952343eSKyle Evans 3413d1a1f2cSKyle Evans #if SOON 3425952343eSKyle Evans static int 3439e004b21SKyle Evans bectl_cmd_add(int argc, char *argv[]) 3445952343eSKyle Evans { 3455952343eSKyle Evans 3465952343eSKyle Evans if (argc < 2) { 3472c848957SKyle Evans fprintf(stderr, "bectl add: must provide at least one path\n"); 3485952343eSKyle Evans return (usage(false)); 3495952343eSKyle Evans } 3505952343eSKyle Evans 3515952343eSKyle Evans for (int i = 1; i < argc; ++i) { 3525952343eSKyle Evans printf("arg %d: %s\n", i, argv[i]); 35316a10da8SKyle Evans /* XXX TODO catch err */ 3545952343eSKyle Evans be_add_child(be, argv[i], true); 3555952343eSKyle Evans } 3565952343eSKyle Evans 3575952343eSKyle Evans return (0); 3585952343eSKyle Evans } 3593d1a1f2cSKyle Evans #endif 3605952343eSKyle Evans 3615952343eSKyle Evans static int 3629e004b21SKyle Evans bectl_cmd_destroy(int argc, char *argv[]) 3635952343eSKyle Evans { 36477b4126cSKyle Evans nvlist_t *props; 3652a58b312SMartin Matuska char *target, targetds[BE_MAXPATHLEN]; 3662a58b312SMartin Matuska const char *origin; 36777b4126cSKyle Evans int err, flags, opt; 3685952343eSKyle Evans 36977b4126cSKyle Evans flags = 0; 37077b4126cSKyle Evans while ((opt = getopt(argc, argv, "Fo")) != -1) { 3715952343eSKyle Evans switch (opt) { 3725952343eSKyle Evans case 'F': 37377b4126cSKyle Evans flags |= BE_DESTROY_FORCE; 37477b4126cSKyle Evans break; 37577b4126cSKyle Evans case 'o': 37677b4126cSKyle Evans flags |= BE_DESTROY_ORIGIN; 3775952343eSKyle Evans break; 3785952343eSKyle Evans default: 3792c848957SKyle Evans fprintf(stderr, "bectl destroy: unknown option '-%c'\n", 3805952343eSKyle Evans optopt); 3815952343eSKyle Evans return (usage(false)); 3825952343eSKyle Evans } 3835952343eSKyle Evans } 3845952343eSKyle Evans 3855952343eSKyle Evans argc -= optind; 3865952343eSKyle Evans argv += optind; 3875952343eSKyle Evans 3885952343eSKyle Evans if (argc != 1) { 3892c848957SKyle Evans fprintf(stderr, "bectl destroy: wrong number of arguments\n"); 3905952343eSKyle Evans return (usage(false)); 3915952343eSKyle Evans } 3925952343eSKyle Evans 3935952343eSKyle Evans target = argv[0]; 3945952343eSKyle Evans 39577b4126cSKyle Evans /* We'll emit a notice if there's an origin to be cleaned up */ 39677b4126cSKyle Evans if ((flags & BE_DESTROY_ORIGIN) == 0 && strchr(target, '@') == NULL) { 3978338f584SKyle Evans flags |= BE_DESTROY_AUTOORIGIN; 39877b4126cSKyle Evans if (be_root_concat(be, target, targetds) != 0) 39977b4126cSKyle Evans goto destroy; 40077b4126cSKyle Evans if (be_prop_list_alloc(&props) != 0) 40177b4126cSKyle Evans goto destroy; 40277b4126cSKyle Evans if (be_get_dataset_props(be, targetds, props) != 0) { 40377b4126cSKyle Evans be_prop_list_free(props); 40477b4126cSKyle Evans goto destroy; 40577b4126cSKyle Evans } 4068338f584SKyle Evans if (nvlist_lookup_string(props, "origin", &origin) == 0 && 4078338f584SKyle Evans !be_is_auto_snapshot_name(be, origin)) 40877b4126cSKyle Evans fprintf(stderr, "bectl destroy: leaving origin '%s' intact\n", 40977b4126cSKyle Evans origin); 41077b4126cSKyle Evans be_prop_list_free(props); 41177b4126cSKyle Evans } 41277b4126cSKyle Evans 41377b4126cSKyle Evans destroy: 41477b4126cSKyle Evans err = be_destroy(be, target, flags); 4155952343eSKyle Evans 4165952343eSKyle Evans return (err); 4175952343eSKyle Evans } 4185952343eSKyle Evans 4195952343eSKyle Evans static int 4209e004b21SKyle Evans bectl_cmd_mount(int argc, char *argv[]) 4215952343eSKyle Evans { 4225952343eSKyle Evans char result_loc[BE_MAXPATHLEN]; 42316a10da8SKyle Evans char *bootenv, *mountpoint; 4240a603a6eSKyle Evans int err, mntflags; 4255952343eSKyle Evans 4260a603a6eSKyle Evans /* XXX TODO: Allow shallow */ 4270a603a6eSKyle Evans mntflags = BE_MNT_DEEP; 4285952343eSKyle Evans if (argc < 2) { 4292c848957SKyle Evans fprintf(stderr, "bectl mount: missing argument(s)\n"); 4305952343eSKyle Evans return (usage(false)); 4315952343eSKyle Evans } 4325952343eSKyle Evans 4335952343eSKyle Evans if (argc > 3) { 4342c848957SKyle Evans fprintf(stderr, "bectl mount: too many arguments\n"); 4355952343eSKyle Evans return (usage(false)); 4365952343eSKyle Evans } 4375952343eSKyle Evans 4385952343eSKyle Evans bootenv = argv[1]; 4395952343eSKyle Evans mountpoint = ((argc == 3) ? argv[2] : NULL); 4405952343eSKyle Evans 4410a603a6eSKyle Evans err = be_mount(be, bootenv, mountpoint, mntflags, result_loc); 4425952343eSKyle Evans 4435952343eSKyle Evans switch (err) { 4445952343eSKyle Evans case BE_ERR_SUCCESS: 44523614c2bSBenedict Reuschling printf("Successfully mounted %s at %s\n", bootenv, result_loc); 4465952343eSKyle Evans break; 4475952343eSKyle Evans default: 4485952343eSKyle Evans fprintf(stderr, 44923614c2bSBenedict Reuschling (argc == 3) ? "Failed to mount bootenv %s at %s\n" : 45023614c2bSBenedict Reuschling "Failed to mount bootenv %s at temporary path %s\n", 4515952343eSKyle Evans bootenv, mountpoint); 4525952343eSKyle Evans } 4535952343eSKyle Evans 4545952343eSKyle Evans return (err); 4555952343eSKyle Evans } 4565952343eSKyle Evans 4575952343eSKyle Evans 4585952343eSKyle Evans static int 4599e004b21SKyle Evans bectl_cmd_rename(int argc, char *argv[]) 4605952343eSKyle Evans { 46116a10da8SKyle Evans char *dest, *src; 4625952343eSKyle Evans int err; 4635952343eSKyle Evans 4645952343eSKyle Evans if (argc < 3) { 4652c848957SKyle Evans fprintf(stderr, "bectl rename: missing argument\n"); 4665952343eSKyle Evans return (usage(false)); 4675952343eSKyle Evans } 4685952343eSKyle Evans 4695952343eSKyle Evans if (argc > 3) { 4702c848957SKyle Evans fprintf(stderr, "bectl rename: too many arguments\n"); 4715952343eSKyle Evans return (usage(false)); 4725952343eSKyle Evans } 4735952343eSKyle Evans 4745952343eSKyle Evans src = argv[1]; 4755952343eSKyle Evans dest = argv[2]; 4765952343eSKyle Evans 4775952343eSKyle Evans err = be_rename(be, src, dest); 4785952343eSKyle Evans switch (err) { 4795952343eSKyle Evans case BE_ERR_SUCCESS: 4805952343eSKyle Evans break; 4815952343eSKyle Evans default: 48223614c2bSBenedict Reuschling fprintf(stderr, "Failed to rename bootenv %s to %s\n", 4835952343eSKyle Evans src, dest); 4845952343eSKyle Evans } 4855952343eSKyle Evans 486dadb9c70SKyle Evans return (err); 4875952343eSKyle Evans } 4885952343eSKyle Evans 489ad765da4SKyle Evans static int 4909e004b21SKyle Evans bectl_cmd_unmount(int argc, char *argv[]) 4915952343eSKyle Evans { 49216a10da8SKyle Evans char *bootenv, *cmd; 4935952343eSKyle Evans int err, flags, opt; 4945952343eSKyle Evans 4955952343eSKyle Evans /* Store alias used */ 4965952343eSKyle Evans cmd = argv[0]; 4975952343eSKyle Evans 4985952343eSKyle Evans flags = 0; 4995952343eSKyle Evans while ((opt = getopt(argc, argv, "f")) != -1) { 5005952343eSKyle Evans switch (opt) { 5015952343eSKyle Evans case 'f': 5025952343eSKyle Evans flags |= BE_MNT_FORCE; 5035952343eSKyle Evans break; 5045952343eSKyle Evans default: 5052c848957SKyle Evans fprintf(stderr, "bectl %s: unknown option '-%c'\n", 5065952343eSKyle Evans cmd, optopt); 5075952343eSKyle Evans return (usage(false)); 5085952343eSKyle Evans } 5095952343eSKyle Evans } 5105952343eSKyle Evans 5115952343eSKyle Evans argc -= optind; 5125952343eSKyle Evans argv += optind; 5135952343eSKyle Evans 5145952343eSKyle Evans if (argc != 1) { 5152c848957SKyle Evans fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd); 5165952343eSKyle Evans return (usage(false)); 5175952343eSKyle Evans } 5185952343eSKyle Evans 5195952343eSKyle Evans bootenv = argv[0]; 5205952343eSKyle Evans 5215952343eSKyle Evans err = be_unmount(be, bootenv, flags); 5225952343eSKyle Evans 5235952343eSKyle Evans switch (err) { 5245952343eSKyle Evans case BE_ERR_SUCCESS: 5255952343eSKyle Evans break; 5265952343eSKyle Evans default: 52723614c2bSBenedict Reuschling fprintf(stderr, "Failed to unmount bootenv %s\n", bootenv); 5285952343eSKyle Evans } 5295952343eSKyle Evans 5305952343eSKyle Evans return (err); 5315952343eSKyle Evans } 5325952343eSKyle Evans 533490e13c1SKyle Evans static int 534490e13c1SKyle Evans bectl_cmd_check(int argc, char *argv[] __unused) 535490e13c1SKyle Evans { 536490e13c1SKyle Evans 537490e13c1SKyle Evans /* The command is left as argv[0] */ 538490e13c1SKyle Evans if (argc != 1) { 539490e13c1SKyle Evans fprintf(stderr, "bectl check: wrong number of arguments\n"); 540490e13c1SKyle Evans return (usage(false)); 541490e13c1SKyle Evans } 542490e13c1SKyle Evans 543490e13c1SKyle Evans return (0); 544490e13c1SKyle Evans } 5455952343eSKyle Evans 5465952343eSKyle Evans int 5475952343eSKyle Evans main(int argc, char *argv[]) 5485952343eSKyle Evans { 549490e13c1SKyle Evans struct command_map_entry *cmd; 550b29bf2f8SKyle Evans const char *command; 551cc624025SKyle Evans char *root; 552490e13c1SKyle Evans int rc; 5535952343eSKyle Evans 554490e13c1SKyle Evans cmd = NULL; 555cc624025SKyle Evans root = NULL; 5568369ba42SKyle Evans if (argc < 2) 5575952343eSKyle Evans return (usage(false)); 5585952343eSKyle Evans 559cc624025SKyle Evans if (strcmp(argv[1], "-r") == 0) { 560cc624025SKyle Evans if (argc < 4) 561cc624025SKyle Evans return (usage(false)); 562cc624025SKyle Evans root = strdup(argv[2]); 563cc624025SKyle Evans command = argv[3]; 564cc624025SKyle Evans argc -= 3; 565cc624025SKyle Evans argv += 3; 566cc624025SKyle Evans } else { 5675952343eSKyle Evans command = argv[1]; 568cc624025SKyle Evans argc -= 1; 569cc624025SKyle Evans argv += 1; 570cc624025SKyle Evans } 5715952343eSKyle Evans 5725952343eSKyle Evans /* Handle command aliases */ 57316a10da8SKyle Evans if (strcmp(command, "umount") == 0) 5745952343eSKyle Evans command = "unmount"; 5755952343eSKyle Evans 57616a10da8SKyle Evans if (strcmp(command, "ujail") == 0) 5775952343eSKyle Evans command = "unjail"; 5785952343eSKyle Evans 57916a10da8SKyle Evans if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0)) 5805952343eSKyle Evans return (usage(true)); 5815952343eSKyle Evans 582490e13c1SKyle Evans if ((cmd = get_cmd_info(command)) == NULL) { 58323614c2bSBenedict Reuschling fprintf(stderr, "Unknown command: %s\n", command); 5845952343eSKyle Evans return (usage(false)); 5855952343eSKyle Evans } 5865952343eSKyle Evans 5874c91d6bcSGleb Smirnoff if ((be = libbe_init(root)) == NULL) { 5882a58b312SMartin Matuska if (!cmd->silent) 5894c91d6bcSGleb Smirnoff fprintf(stderr, "libbe_init(\"%s\") failed.\n", 5904c91d6bcSGleb Smirnoff root != NULL ? root : ""); 5915952343eSKyle Evans return (-1); 5924c91d6bcSGleb Smirnoff } 5935952343eSKyle Evans 594490e13c1SKyle Evans libbe_print_on_error(be, !cmd->silent); 5955952343eSKyle Evans 596490e13c1SKyle Evans rc = cmd->fn(argc, argv); 5975952343eSKyle Evans 5985952343eSKyle Evans libbe_close(be); 5995952343eSKyle Evans return (rc); 6005952343eSKyle Evans } 601