xref: /freebsd/sbin/bectl/bectl.c (revision 25eeb3ea9580fd7bcf90c16ce1fee170816c6585)
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[]);
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;
695952343eSKyle Evans 	fprintf(fp,
709e004b21SKyle Evans 	    "usage:\tbectl ( -h | -? | subcommand [args...] )\n"
719e004b21SKyle Evans 	    "\tbectl activate [-t] beName\n"
729e004b21SKyle Evans 	    "\tbectl create [-e nonActiveBe | -e beName@snapshot] beName\n"
739e004b21SKyle Evans 	    "\tbectl create beName@snapshot\n"
749e004b21SKyle Evans 	    "\tbectl destroy [-F] beName | beName@snapshot⟩\n"
759e004b21SKyle Evans 	    "\tbectl export sourceBe\n"
769e004b21SKyle Evans 	    "\tbectl import targetBe\n"
773d1a1f2cSKyle Evans #if SOON
789e004b21SKyle Evans 	    "\tbectl add (path)*\n"
793d1a1f2cSKyle Evans #endif
802a0b8dc2SKyle Evans 	    "\tbectl jail [ -o key=value | -u key ]... bootenv\n"
819e004b21SKyle Evans 	    "\tbectl list [-a] [-D] [-H] [-s]\n"
829e004b21SKyle Evans 	    "\tbectl mount beName [mountpoint]\n"
839e004b21SKyle Evans 	    "\tbectl rename origBeName newBeName\n"
84ad765da4SKyle Evans 	    "\tbectl { ujail | unjail } ⟨jailID | jailName | bootenv)\n"
859e004b21SKyle Evans 	    "\tbectl { umount | unmount } [-f] beName\n");
865952343eSKyle Evans 
875952343eSKyle Evans 	return (explicit ? 0 : EX_USAGE);
885952343eSKyle Evans }
895952343eSKyle Evans 
905952343eSKyle Evans 
915952343eSKyle Evans /*
925952343eSKyle Evans  * Represents a relationship between the command name and the parser action
935952343eSKyle Evans  * that handles it.
945952343eSKyle Evans  */
955952343eSKyle Evans struct command_map_entry {
965952343eSKyle Evans 	const char *command;
975952343eSKyle Evans 	int (*fn)(int argc, char *argv[]);
985952343eSKyle Evans };
995952343eSKyle Evans 
1005952343eSKyle Evans static struct command_map_entry command_map[] =
1015952343eSKyle Evans {
1029e004b21SKyle Evans 	{ "activate", bectl_cmd_activate },
1039e004b21SKyle Evans 	{ "create",   bectl_cmd_create   },
1049e004b21SKyle Evans 	{ "destroy",  bectl_cmd_destroy  },
1059e004b21SKyle Evans 	{ "export",   bectl_cmd_export   },
1069e004b21SKyle Evans 	{ "import",   bectl_cmd_import   },
1073d1a1f2cSKyle Evans #if SOON
1089e004b21SKyle Evans 	{ "add",      bectl_cmd_add      },
1093d1a1f2cSKyle Evans #endif
1109e004b21SKyle Evans 	{ "jail",     bectl_cmd_jail     },
1119e004b21SKyle Evans 	{ "list",     bectl_cmd_list     },
1129e004b21SKyle Evans 	{ "mount",    bectl_cmd_mount    },
1139e004b21SKyle Evans 	{ "rename",   bectl_cmd_rename   },
1149e004b21SKyle Evans 	{ "unjail",   bectl_cmd_unjail   },
1159e004b21SKyle Evans 	{ "unmount",  bectl_cmd_unmount  },
1165952343eSKyle Evans };
1175952343eSKyle Evans 
1185952343eSKyle Evans static int
119e9036018SKyle Evans get_cmd_index(const char *cmd, int *idx)
1205952343eSKyle Evans {
12116a10da8SKyle Evans 	int map_size;
1225952343eSKyle Evans 
12316a10da8SKyle Evans 	map_size = nitems(command_map);
1245952343eSKyle Evans 	for (int i = 0; i < map_size; ++i) {
1255952343eSKyle Evans 		if (strcmp(cmd, command_map[i].command) == 0) {
126e9036018SKyle Evans 			*idx = i;
1275952343eSKyle Evans 			return (0);
1285952343eSKyle Evans 		}
1295952343eSKyle Evans 	}
1305952343eSKyle Evans 
1315952343eSKyle Evans 	return (1);
1325952343eSKyle Evans }
1335952343eSKyle Evans 
1345952343eSKyle Evans 
1355952343eSKyle Evans static int
1369e004b21SKyle Evans bectl_cmd_activate(int argc, char *argv[])
1375952343eSKyle Evans {
1385952343eSKyle Evans 	int err, opt;
1395952343eSKyle Evans 	bool temp;
1405952343eSKyle Evans 
1415952343eSKyle Evans 	temp = false;
1425952343eSKyle Evans 	while ((opt = getopt(argc, argv, "t")) != -1) {
1435952343eSKyle Evans 		switch (opt) {
1445952343eSKyle Evans 		case 't':
1455952343eSKyle Evans 			temp = true;
1465952343eSKyle Evans 			break;
1475952343eSKyle Evans 		default:
1482c848957SKyle Evans 			fprintf(stderr, "bectl activate: unknown option '-%c'\n",
1495952343eSKyle Evans 			    optopt);
1505952343eSKyle Evans 			return (usage(false));
1515952343eSKyle Evans 		}
1525952343eSKyle Evans 	}
1535952343eSKyle Evans 
1545952343eSKyle Evans 	argc -= optind;
1555952343eSKyle Evans 	argv += optind;
1565952343eSKyle Evans 
1575952343eSKyle Evans 	if (argc != 1) {
1582c848957SKyle Evans 		fprintf(stderr, "bectl activate: wrong number of arguments\n");
1595952343eSKyle Evans 		return (usage(false));
1605952343eSKyle Evans 	}
1615952343eSKyle Evans 
1625952343eSKyle Evans 
1635952343eSKyle Evans 	/* activate logic goes here */
16416a10da8SKyle Evans 	if ((err = be_activate(be, argv[0], temp)) != 0)
16516a10da8SKyle Evans 		/* XXX TODO: more specific error msg based on err */
1665952343eSKyle Evans 		printf("did not successfully activate boot environment %s\n",
1675952343eSKyle Evans 		    argv[0]);
16816a10da8SKyle Evans 	else
1695952343eSKyle Evans 		printf("successfully activated boot environment %s\n", argv[0]);
1705952343eSKyle Evans 
17116a10da8SKyle Evans 	if (temp)
1725952343eSKyle Evans 		printf("for next boot\n");
1735952343eSKyle Evans 
1745952343eSKyle Evans 	return (err);
1755952343eSKyle Evans }
1765952343eSKyle Evans 
1775952343eSKyle Evans 
17816a10da8SKyle Evans /*
17916a10da8SKyle Evans  * TODO: when only one arg is given, and it contains an "@" the this should
18016a10da8SKyle Evans  * create that snapshot
18116a10da8SKyle Evans  */
1825952343eSKyle Evans static int
1839e004b21SKyle Evans bectl_cmd_create(int argc, char *argv[])
1845952343eSKyle Evans {
185a9c660b0SKyle Evans 	char *atpos, *bootenv, *snapname, *source;
1865952343eSKyle Evans 	int err, opt;
187a9c660b0SKyle Evans 	bool recursive;
1885952343eSKyle Evans 
1895952343eSKyle Evans 	snapname = NULL;
190a9c660b0SKyle Evans 	recursive = false;
191*25eeb3eaSKyle Evans 	while ((opt = getopt(argc, argv, "e:r")) != -1) {
1925952343eSKyle Evans 		switch (opt) {
1935952343eSKyle Evans 		case 'e':
1945952343eSKyle Evans 			snapname = optarg;
1955952343eSKyle Evans 			break;
196a9c660b0SKyle Evans 		case 'r':
197a9c660b0SKyle Evans 			recursive = true;
198*25eeb3eaSKyle Evans 			break;
1995952343eSKyle Evans 		default:
2002c848957SKyle Evans 			fprintf(stderr, "bectl create: unknown option '-%c'\n",
2015952343eSKyle Evans 			    optopt);
2025952343eSKyle Evans 			return (usage(false));
2035952343eSKyle Evans 		}
2045952343eSKyle Evans 	}
2055952343eSKyle Evans 
2065952343eSKyle Evans 	argc -= optind;
2075952343eSKyle Evans 	argv += optind;
2085952343eSKyle Evans 
2095952343eSKyle Evans 	if (argc != 1) {
2102c848957SKyle Evans 		fprintf(stderr, "bectl create: wrong number of arguments\n");
2115952343eSKyle Evans 		return (usage(false));
2125952343eSKyle Evans 	}
2135952343eSKyle Evans 
2145952343eSKyle Evans 	bootenv = *argv;
215a9c660b0SKyle Evans 	if ((atpos = strchr(bootenv, '@')) != NULL) {
216a9c660b0SKyle Evans 		/*
217a9c660b0SKyle Evans 		 * This is the "create a snapshot variant". No new boot
218a9c660b0SKyle Evans 		 * environment is to be created here.
219a9c660b0SKyle Evans 		 */
220a9c660b0SKyle Evans 		*atpos++ = '\0';
221a9c660b0SKyle Evans 		err = be_snapshot(be, bootenv, atpos, recursive, NULL);
222a9c660b0SKyle Evans 	} else if (snapname != NULL) {
22316a10da8SKyle Evans 		if (strchr(snapname, '@') != NULL)
2245952343eSKyle Evans 			err = be_create_from_existing_snap(be, bootenv,
2255952343eSKyle Evans 			    snapname);
22616a10da8SKyle Evans 		else
2275952343eSKyle Evans 			err = be_create_from_existing(be, bootenv, snapname);
2285952343eSKyle Evans 	} else {
2295952343eSKyle Evans 		if ((snapname = strchr(bootenv, '@')) != NULL) {
2305952343eSKyle Evans 			*(snapname++) = '\0';
231b29bf2f8SKyle Evans 			if ((err = be_snapshot(be, be_active_path(be),
23216a10da8SKyle Evans 			    snapname, true, NULL)) != BE_ERR_SUCCESS)
2335952343eSKyle Evans 				fprintf(stderr, "failed to create snapshot\n");
2345952343eSKyle Evans 			asprintf(&source, "%s@%s", be_active_path(be), snapname);
2355952343eSKyle Evans 			err = be_create_from_existing_snap(be, bootenv,
2365952343eSKyle Evans 			    source);
2375952343eSKyle Evans 			return (err);
23816a10da8SKyle Evans 		} else
2395952343eSKyle Evans 			err = be_create(be, bootenv);
2405952343eSKyle Evans 	}
2415952343eSKyle Evans 
2425952343eSKyle Evans 	switch (err) {
2435952343eSKyle Evans 	case BE_ERR_SUCCESS:
2445952343eSKyle Evans 		break;
2455952343eSKyle Evans 	default:
246a9c660b0SKyle Evans 		if (atpos != NULL)
247a9c660b0SKyle Evans 			fprintf(stderr,
248a9c660b0SKyle Evans 			    "failed to create a snapshot '%s' of '%s'\n",
249a9c660b0SKyle Evans 			    atpos, bootenv);
250a9c660b0SKyle Evans 		else if (snapname == NULL)
2515952343eSKyle Evans 			fprintf(stderr,
2525952343eSKyle Evans 			    "failed to create bootenv %s\n", bootenv);
25316a10da8SKyle Evans 		else
2545952343eSKyle Evans 			fprintf(stderr,
2555952343eSKyle Evans 			    "failed to create bootenv %s from snapshot %s\n",
2565952343eSKyle Evans 			    bootenv, snapname);
2575952343eSKyle Evans 	}
2585952343eSKyle Evans 
2595952343eSKyle Evans 	return (err);
2605952343eSKyle Evans }
2615952343eSKyle Evans 
2625952343eSKyle Evans 
2635952343eSKyle Evans static int
2649e004b21SKyle Evans bectl_cmd_export(int argc, char *argv[])
2655952343eSKyle Evans {
2665952343eSKyle Evans 	char *bootenv;
2675952343eSKyle Evans 
2685952343eSKyle Evans 	if (argc == 1) {
2692c848957SKyle Evans 		fprintf(stderr, "bectl export: missing boot environment name\n");
2705952343eSKyle Evans 		return (usage(false));
2715952343eSKyle Evans 	}
2725952343eSKyle Evans 
2735952343eSKyle Evans 	if (argc > 2) {
2742c848957SKyle Evans 		fprintf(stderr, "bectl export: extra arguments provided\n");
2755952343eSKyle Evans 		return (usage(false));
2765952343eSKyle Evans 	}
2775952343eSKyle Evans 
2785952343eSKyle Evans 	bootenv = argv[1];
2795952343eSKyle Evans 
2805952343eSKyle Evans 	if (isatty(STDOUT_FILENO)) {
2812c848957SKyle Evans 		fprintf(stderr, "bectl export: must redirect output\n");
2825952343eSKyle Evans 		return (EX_USAGE);
2835952343eSKyle Evans 	}
2845952343eSKyle Evans 
2855952343eSKyle Evans 	be_export(be, bootenv, STDOUT_FILENO);
2865952343eSKyle Evans 
2875952343eSKyle Evans 	return (0);
2885952343eSKyle Evans }
2895952343eSKyle Evans 
2905952343eSKyle Evans 
2915952343eSKyle Evans static int
2929e004b21SKyle Evans bectl_cmd_import(int argc, char *argv[])
2935952343eSKyle Evans {
2945952343eSKyle Evans 	char *bootenv;
2955952343eSKyle Evans 	int err;
2965952343eSKyle Evans 
2975952343eSKyle Evans 	if (argc == 1) {
2982c848957SKyle Evans 		fprintf(stderr, "bectl import: missing boot environment name\n");
2995952343eSKyle Evans 		return (usage(false));
3005952343eSKyle Evans 	}
3015952343eSKyle Evans 
3025952343eSKyle Evans 	if (argc > 2) {
3032c848957SKyle Evans 		fprintf(stderr, "bectl import: extra arguments provided\n");
3045952343eSKyle Evans 		return (usage(false));
3055952343eSKyle Evans 	}
3065952343eSKyle Evans 
3075952343eSKyle Evans 	bootenv = argv[1];
3085952343eSKyle Evans 
3095952343eSKyle Evans 	if (isatty(STDIN_FILENO)) {
3102c848957SKyle Evans 		fprintf(stderr, "bectl import: input can not be from terminal\n");
3115952343eSKyle Evans 		return (EX_USAGE);
3125952343eSKyle Evans 	}
3135952343eSKyle Evans 
3145952343eSKyle Evans 	err = be_import(be, bootenv, STDIN_FILENO);
3155952343eSKyle Evans 
3165952343eSKyle Evans 	return (err);
3175952343eSKyle Evans }
3185952343eSKyle Evans 
3193d1a1f2cSKyle Evans #if SOON
3205952343eSKyle Evans static int
3219e004b21SKyle Evans bectl_cmd_add(int argc, char *argv[])
3225952343eSKyle Evans {
3235952343eSKyle Evans 
3245952343eSKyle Evans 	if (argc < 2) {
3252c848957SKyle Evans 		fprintf(stderr, "bectl add: must provide at least one path\n");
3265952343eSKyle Evans 		return (usage(false));
3275952343eSKyle Evans 	}
3285952343eSKyle Evans 
3295952343eSKyle Evans 	for (int i = 1; i < argc; ++i) {
3305952343eSKyle Evans 		printf("arg %d: %s\n", i, argv[i]);
33116a10da8SKyle Evans 		/* XXX TODO catch err */
3325952343eSKyle Evans 		be_add_child(be, argv[i], true);
3335952343eSKyle Evans 	}
3345952343eSKyle Evans 
3355952343eSKyle Evans 	return (0);
3365952343eSKyle Evans }
3373d1a1f2cSKyle Evans #endif
3385952343eSKyle Evans 
3395952343eSKyle Evans static int
3409e004b21SKyle Evans bectl_cmd_destroy(int argc, char *argv[])
3415952343eSKyle Evans {
34216a10da8SKyle Evans 	char *target;
3435952343eSKyle Evans 	int opt, err;
3445952343eSKyle Evans 	bool force;
3455952343eSKyle Evans 
3465952343eSKyle Evans 	force = false;
3475952343eSKyle Evans 	while ((opt = getopt(argc, argv, "F")) != -1) {
3485952343eSKyle Evans 		switch (opt) {
3495952343eSKyle Evans 		case 'F':
3505952343eSKyle Evans 			force = true;
3515952343eSKyle Evans 			break;
3525952343eSKyle Evans 		default:
3532c848957SKyle Evans 			fprintf(stderr, "bectl destroy: unknown option '-%c'\n",
3545952343eSKyle Evans 			    optopt);
3555952343eSKyle Evans 			return (usage(false));
3565952343eSKyle Evans 		}
3575952343eSKyle Evans 	}
3585952343eSKyle Evans 
3595952343eSKyle Evans 	argc -= optind;
3605952343eSKyle Evans 	argv += optind;
3615952343eSKyle Evans 
3625952343eSKyle Evans 	if (argc != 1) {
3632c848957SKyle Evans 		fprintf(stderr, "bectl destroy: wrong number of arguments\n");
3645952343eSKyle Evans 		return (usage(false));
3655952343eSKyle Evans 	}
3665952343eSKyle Evans 
3675952343eSKyle Evans 	target = argv[0];
3685952343eSKyle Evans 
3695952343eSKyle Evans 	err = be_destroy(be, target, force);
3705952343eSKyle Evans 
3715952343eSKyle Evans 	return (err);
3725952343eSKyle Evans }
3735952343eSKyle Evans 
3745952343eSKyle Evans static int
3759e004b21SKyle Evans bectl_cmd_mount(int argc, char *argv[])
3765952343eSKyle Evans {
3775952343eSKyle Evans 	char result_loc[BE_MAXPATHLEN];
37816a10da8SKyle Evans 	char *bootenv, *mountpoint;
37916a10da8SKyle Evans 	int err;
3805952343eSKyle Evans 
3815952343eSKyle Evans 	if (argc < 2) {
3822c848957SKyle Evans 		fprintf(stderr, "bectl mount: missing argument(s)\n");
3835952343eSKyle Evans 		return (usage(false));
3845952343eSKyle Evans 	}
3855952343eSKyle Evans 
3865952343eSKyle Evans 	if (argc > 3) {
3872c848957SKyle Evans 		fprintf(stderr, "bectl mount: too many arguments\n");
3885952343eSKyle Evans 		return (usage(false));
3895952343eSKyle Evans 	}
3905952343eSKyle Evans 
3915952343eSKyle Evans 	bootenv = argv[1];
3925952343eSKyle Evans 	mountpoint = ((argc == 3) ? argv[2] : NULL);
3935952343eSKyle Evans 
3945952343eSKyle Evans 	err = be_mount(be, bootenv, mountpoint, 0, result_loc);
3955952343eSKyle Evans 
3965952343eSKyle Evans 	switch (err) {
3975952343eSKyle Evans 	case BE_ERR_SUCCESS:
3985952343eSKyle Evans 		printf("successfully mounted %s at %s\n", bootenv, result_loc);
3995952343eSKyle Evans 		break;
4005952343eSKyle Evans 	default:
4015952343eSKyle Evans 		fprintf(stderr,
4025952343eSKyle Evans 		    (argc == 3) ? "failed to mount bootenv %s at %s\n" :
4035952343eSKyle Evans 		    "failed to mount bootenv %s at temporary path %s\n",
4045952343eSKyle Evans 		    bootenv, mountpoint);
4055952343eSKyle Evans 	}
4065952343eSKyle Evans 
4075952343eSKyle Evans 	return (err);
4085952343eSKyle Evans }
4095952343eSKyle Evans 
4105952343eSKyle Evans 
4115952343eSKyle Evans static int
4129e004b21SKyle Evans bectl_cmd_rename(int argc, char *argv[])
4135952343eSKyle Evans {
41416a10da8SKyle Evans 	char *dest, *src;
4155952343eSKyle Evans 	int err;
4165952343eSKyle Evans 
4175952343eSKyle Evans 	if (argc < 3) {
4182c848957SKyle Evans 		fprintf(stderr, "bectl rename: missing argument\n");
4195952343eSKyle Evans 		return (usage(false));
4205952343eSKyle Evans 	}
4215952343eSKyle Evans 
4225952343eSKyle Evans 	if (argc > 3) {
4232c848957SKyle Evans 		fprintf(stderr, "bectl rename: too many arguments\n");
4245952343eSKyle Evans 		return (usage(false));
4255952343eSKyle Evans 	}
4265952343eSKyle Evans 
4275952343eSKyle Evans 	src = argv[1];
4285952343eSKyle Evans 	dest = argv[2];
4295952343eSKyle Evans 
4305952343eSKyle Evans 	err = be_rename(be, src, dest);
4315952343eSKyle Evans 
4325952343eSKyle Evans 	switch (err) {
4335952343eSKyle Evans 	case BE_ERR_SUCCESS:
4345952343eSKyle Evans 		break;
4355952343eSKyle Evans 	default:
4365952343eSKyle Evans 		fprintf(stderr, "failed to rename bootenv %s to %s\n",
4375952343eSKyle Evans 		    src, dest);
4385952343eSKyle Evans 	}
4395952343eSKyle Evans 
4405952343eSKyle Evans 	return (0);
4415952343eSKyle Evans }
4425952343eSKyle Evans 
443ad765da4SKyle Evans static int
4449e004b21SKyle Evans bectl_cmd_unmount(int argc, char *argv[])
4455952343eSKyle Evans {
44616a10da8SKyle Evans 	char *bootenv, *cmd;
4475952343eSKyle Evans 	int err, flags, opt;
4485952343eSKyle Evans 
4495952343eSKyle Evans 	/* Store alias used */
4505952343eSKyle Evans 	cmd = argv[0];
4515952343eSKyle Evans 
4525952343eSKyle Evans 	flags = 0;
4535952343eSKyle Evans 	while ((opt = getopt(argc, argv, "f")) != -1) {
4545952343eSKyle Evans 		switch (opt) {
4555952343eSKyle Evans 		case 'f':
4565952343eSKyle Evans 			flags |= BE_MNT_FORCE;
4575952343eSKyle Evans 			break;
4585952343eSKyle Evans 		default:
4592c848957SKyle Evans 			fprintf(stderr, "bectl %s: unknown option '-%c'\n",
4605952343eSKyle Evans 			    cmd, optopt);
4615952343eSKyle Evans 			return (usage(false));
4625952343eSKyle Evans 		}
4635952343eSKyle Evans 	}
4645952343eSKyle Evans 
4655952343eSKyle Evans 	argc -= optind;
4665952343eSKyle Evans 	argv += optind;
4675952343eSKyle Evans 
4685952343eSKyle Evans 	if (argc != 1) {
4692c848957SKyle Evans 		fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd);
4705952343eSKyle Evans 		return (usage(false));
4715952343eSKyle Evans 	}
4725952343eSKyle Evans 
4735952343eSKyle Evans 	bootenv = argv[0];
4745952343eSKyle Evans 
4755952343eSKyle Evans 	err = be_unmount(be, bootenv, flags);
4765952343eSKyle Evans 
4775952343eSKyle Evans 	switch (err) {
4785952343eSKyle Evans 	case BE_ERR_SUCCESS:
4795952343eSKyle Evans 		break;
4805952343eSKyle Evans 	default:
4815952343eSKyle Evans 		fprintf(stderr, "failed to unmount bootenv %s\n", bootenv);
4825952343eSKyle Evans 	}
4835952343eSKyle Evans 
4845952343eSKyle Evans 	return (err);
4855952343eSKyle Evans }
4865952343eSKyle Evans 
4875952343eSKyle Evans 
4885952343eSKyle Evans int
4895952343eSKyle Evans main(int argc, char *argv[])
4905952343eSKyle Evans {
491b29bf2f8SKyle Evans 	const char *command;
4925952343eSKyle Evans 	int command_index, rc;
4935952343eSKyle Evans 
4945952343eSKyle Evans 	if (argc < 2) {
4955952343eSKyle Evans 		fprintf(stderr, "missing command\n");
4965952343eSKyle Evans 		return (usage(false));
4975952343eSKyle Evans 	}
4985952343eSKyle Evans 
4995952343eSKyle Evans 	command = argv[1];
5005952343eSKyle Evans 
5015952343eSKyle Evans 	/* Handle command aliases */
50216a10da8SKyle Evans 	if (strcmp(command, "umount") == 0)
5035952343eSKyle Evans 		command = "unmount";
5045952343eSKyle Evans 
50516a10da8SKyle Evans 	if (strcmp(command, "ujail") == 0)
5065952343eSKyle Evans 		command = "unjail";
5075952343eSKyle Evans 
50816a10da8SKyle Evans 	if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0))
5095952343eSKyle Evans 		return (usage(true));
5105952343eSKyle Evans 
5115952343eSKyle Evans 	if (get_cmd_index(command, &command_index)) {
5125952343eSKyle Evans 		fprintf(stderr, "unknown command: %s\n", command);
5135952343eSKyle Evans 		return (usage(false));
5145952343eSKyle Evans 	}
5155952343eSKyle Evans 
5165952343eSKyle Evans 
51716a10da8SKyle Evans 	if ((be = libbe_init()) == NULL)
5185952343eSKyle Evans 		return (-1);
5195952343eSKyle Evans 
5205952343eSKyle Evans 	libbe_print_on_error(be, true);
5215952343eSKyle Evans 
52216a10da8SKyle Evans 	/* XXX TODO: can be simplified if offset by 2 instead of one */
5235952343eSKyle Evans 	rc = command_map[command_index].fn(argc-1, argv+1);
5245952343eSKyle Evans 
5255952343eSKyle Evans 	libbe_close(be);
5265952343eSKyle Evans 	return (rc);
5275952343eSKyle Evans }
528