1b179da01SKyle Evans /*-
24d846d26SWarner 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
285952343eSKyle Evans #include <sys/param.h>
295952343eSKyle Evans #include <sys/mount.h>
305952343eSKyle Evans #include <errno.h>
3183244ec1SKyle Evans #include <libutil.h>
325952343eSKyle Evans #include <stdbool.h>
335952343eSKyle Evans #include <stdio.h>
345952343eSKyle Evans #include <stdint.h>
355952343eSKyle Evans #include <stdlib.h>
365952343eSKyle Evans #include <string.h>
375952343eSKyle Evans #include <sysexits.h>
3883244ec1SKyle Evans #include <time.h>
395952343eSKyle Evans #include <unistd.h>
405952343eSKyle Evans
415952343eSKyle Evans #include <be.h>
425952343eSKyle Evans
43d694059fSKyle Evans #include "bectl.h"
44d694059fSKyle Evans
459e004b21SKyle Evans static int bectl_cmd_activate(int argc, char *argv[]);
46490e13c1SKyle Evans static int bectl_cmd_check(int argc, char *argv[]);
479e004b21SKyle Evans static int bectl_cmd_create(int argc, char *argv[]);
489e004b21SKyle Evans static int bectl_cmd_destroy(int argc, char *argv[]);
499e004b21SKyle Evans static int bectl_cmd_export(int argc, char *argv[]);
509e004b21SKyle Evans static int bectl_cmd_import(int argc, char *argv[]);
513d1a1f2cSKyle Evans #if SOON
529e004b21SKyle Evans static int bectl_cmd_add(int argc, char *argv[]);
533d1a1f2cSKyle Evans #endif
549e004b21SKyle Evans static int bectl_cmd_mount(int argc, char *argv[]);
559e004b21SKyle Evans static int bectl_cmd_rename(int argc, char *argv[]);
569e004b21SKyle Evans static int bectl_cmd_unmount(int argc, char *argv[]);
575952343eSKyle Evans
58d694059fSKyle Evans libbe_handle_t *be;
595952343eSKyle Evans
60d694059fSKyle Evans int
usage(bool explicit)615952343eSKyle Evans usage(bool explicit)
625952343eSKyle Evans {
6316a10da8SKyle Evans FILE *fp;
645952343eSKyle Evans
6516a10da8SKyle Evans fp = explicit ? stdout : stderr;
6652ee41b7SYuri Pankov fprintf(fp, "%s",
67e819534fSDag-Erling Smørgrav "Usage:\tbectl {-h | subcommand [args...]}\n"
683d1a1f2cSKyle Evans #if SOON
694163bae0SKyle Evans "\tbectl [-r beroot] add (path)*\n"
703d1a1f2cSKyle Evans #endif
714163bae0SKyle Evans "\tbectl [-r beroot] activate [-t] beName\n"
724163bae0SKyle Evans "\tbectl [-r beroot] activate [-T]\n"
734163bae0SKyle Evans "\tbectl [-r beroot] check\n"
744163bae0SKyle Evans "\tbectl [-r beroot] create [-r] [-e {nonActiveBe | beName@snapshot}] beName\n"
754163bae0SKyle Evans "\tbectl [-r beroot] create [-r] beName@snapshot\n"
764163bae0SKyle Evans "\tbectl [-r beroot] destroy [-Fo] {beName | beName@snapshot}\n"
774163bae0SKyle Evans "\tbectl [-r beroot] export sourceBe\n"
784163bae0SKyle Evans "\tbectl [-r beroot] import targetBe\n"
794163bae0SKyle Evans "\tbectl [-r beroot] jail [-bU] [{-o key=value | -u key}]... beName\n"
80b1ea63e2SRobert Wing "\t [utility [argument ...]]\n"
814163bae0SKyle Evans "\tbectl [-r beroot] list [-aDHs] [{-c property | -C property}]\n"
824163bae0SKyle Evans "\tbectl [-r beroot] mount beName [mountpoint]\n"
834163bae0SKyle Evans "\tbectl [-r beroot] rename origBeName newBeName\n"
844163bae0SKyle Evans "\tbectl [-r beroot] {ujail | unjail} {jailID | jailName | beName}\n"
854163bae0SKyle Evans "\tbectl [-r beroot] {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[]);
98490e13c1SKyle Evans /* True if libbe_print_on_error should be disabled */
99490e13c1SKyle Evans bool silent;
1005952343eSKyle Evans };
1015952343eSKyle Evans
1025952343eSKyle Evans static struct command_map_entry command_map[] =
1035952343eSKyle Evans {
104490e13c1SKyle Evans { "activate", bectl_cmd_activate,false },
105490e13c1SKyle Evans { "create", bectl_cmd_create, false },
106490e13c1SKyle Evans { "destroy", bectl_cmd_destroy, false },
107490e13c1SKyle Evans { "export", bectl_cmd_export, false },
108490e13c1SKyle Evans { "import", bectl_cmd_import, false },
1093d1a1f2cSKyle Evans #if SOON
110490e13c1SKyle Evans { "add", bectl_cmd_add, false },
1113d1a1f2cSKyle Evans #endif
112490e13c1SKyle Evans { "jail", bectl_cmd_jail, false },
113490e13c1SKyle Evans { "list", bectl_cmd_list, false },
114490e13c1SKyle Evans { "mount", bectl_cmd_mount, false },
115490e13c1SKyle Evans { "rename", bectl_cmd_rename, false },
116490e13c1SKyle Evans { "unjail", bectl_cmd_unjail, false },
117*a46217ceSDag-Erling Smørgrav { "ujail", bectl_cmd_unjail, false },
118490e13c1SKyle Evans { "unmount", bectl_cmd_unmount, false },
119*a46217ceSDag-Erling Smørgrav { "umount", bectl_cmd_unmount, false },
120490e13c1SKyle Evans { "check", bectl_cmd_check, true },
1215952343eSKyle Evans };
1225952343eSKyle Evans
123490e13c1SKyle Evans static struct command_map_entry *
get_cmd_info(const char * cmd)124490e13c1SKyle Evans get_cmd_info(const char *cmd)
1255952343eSKyle Evans {
126490e13c1SKyle Evans size_t i;
1275952343eSKyle Evans
128490e13c1SKyle Evans for (i = 0; i < nitems(command_map); ++i) {
129490e13c1SKyle Evans if (strcmp(cmd, command_map[i].command) == 0)
130490e13c1SKyle Evans return (&command_map[i]);
1315952343eSKyle Evans }
1325952343eSKyle Evans
133490e13c1SKyle Evans return (NULL);
1345952343eSKyle Evans }
1355952343eSKyle Evans
1365952343eSKyle Evans static int
bectl_cmd_activate(int argc,char * argv[])1379e004b21SKyle Evans bectl_cmd_activate(int argc, char *argv[])
1385952343eSKyle Evans {
1395952343eSKyle Evans int err, opt;
140e307eb94SToomas Soome bool temp, reset;
1415952343eSKyle Evans
1425952343eSKyle Evans temp = false;
143e307eb94SToomas Soome reset = false;
144e307eb94SToomas Soome while ((opt = getopt(argc, argv, "tT")) != -1) {
1455952343eSKyle Evans switch (opt) {
1465952343eSKyle Evans case 't':
147e307eb94SToomas Soome if (reset)
148e307eb94SToomas Soome return (usage(false));
1495952343eSKyle Evans temp = true;
1505952343eSKyle Evans break;
151e307eb94SToomas Soome case 'T':
152e307eb94SToomas Soome if (temp)
153e307eb94SToomas Soome return (usage(false));
154e307eb94SToomas Soome reset = true;
155e307eb94SToomas Soome break;
1565952343eSKyle Evans default:
1572c848957SKyle Evans fprintf(stderr, "bectl activate: unknown option '-%c'\n",
1585952343eSKyle Evans optopt);
1595952343eSKyle Evans return (usage(false));
1605952343eSKyle Evans }
1615952343eSKyle Evans }
1625952343eSKyle Evans
1635952343eSKyle Evans argc -= optind;
1645952343eSKyle Evans argv += optind;
1655952343eSKyle Evans
166e307eb94SToomas Soome if (argc != 1 && (!reset || argc != 0)) {
1672c848957SKyle Evans fprintf(stderr, "bectl activate: wrong number of arguments\n");
1685952343eSKyle Evans return (usage(false));
1695952343eSKyle Evans }
1705952343eSKyle Evans
171e307eb94SToomas Soome if (reset) {
172e307eb94SToomas Soome if ((err = be_deactivate(be, NULL, reset)) == 0)
173e307eb94SToomas Soome printf("Temporary activation removed\n");
174e307eb94SToomas Soome else
175e307eb94SToomas Soome printf("Failed to remove temporary activation\n");
176e307eb94SToomas Soome return (err);
177e307eb94SToomas Soome }
1785952343eSKyle Evans
1795952343eSKyle Evans /* activate logic goes here */
18016a10da8SKyle Evans if ((err = be_activate(be, argv[0], temp)) != 0)
18116a10da8SKyle Evans /* XXX TODO: more specific error msg based on err */
18223614c2bSBenedict Reuschling printf("Did not successfully activate boot environment %s\n",
1835952343eSKyle Evans argv[0]);
18416a10da8SKyle Evans else
18523614c2bSBenedict Reuschling printf("Successfully activated boot environment %s\n", argv[0]);
1865952343eSKyle Evans
18716a10da8SKyle Evans if (temp)
1885952343eSKyle Evans printf("for next boot\n");
1895952343eSKyle Evans
1905952343eSKyle Evans return (err);
1915952343eSKyle Evans }
1925952343eSKyle Evans
1935952343eSKyle Evans
19416a10da8SKyle Evans /*
19516a10da8SKyle Evans * TODO: when only one arg is given, and it contains an "@" the this should
19616a10da8SKyle Evans * create that snapshot
19716a10da8SKyle Evans */
1985952343eSKyle Evans static int
bectl_cmd_create(int argc,char * argv[])1999e004b21SKyle Evans bectl_cmd_create(int argc, char *argv[])
2005952343eSKyle Evans {
201d05fa0d9SKyle Evans char snapshot[BE_MAXPATHLEN];
202d05fa0d9SKyle Evans char *atpos, *bootenv, *snapname;
2035952343eSKyle Evans int err, opt;
204a9c660b0SKyle Evans bool recursive;
2055952343eSKyle Evans
2065952343eSKyle Evans snapname = NULL;
207a9c660b0SKyle Evans recursive = false;
20825eeb3eaSKyle Evans while ((opt = getopt(argc, argv, "e:r")) != -1) {
2095952343eSKyle Evans switch (opt) {
2105952343eSKyle Evans case 'e':
2115952343eSKyle Evans snapname = optarg;
2125952343eSKyle Evans break;
213a9c660b0SKyle Evans case 'r':
214a9c660b0SKyle Evans recursive = true;
21525eeb3eaSKyle Evans break;
2165952343eSKyle Evans default:
2172c848957SKyle Evans fprintf(stderr, "bectl create: unknown option '-%c'\n",
2185952343eSKyle Evans optopt);
2195952343eSKyle Evans return (usage(false));
2205952343eSKyle Evans }
2215952343eSKyle Evans }
2225952343eSKyle Evans
2235952343eSKyle Evans argc -= optind;
2245952343eSKyle Evans argv += optind;
2255952343eSKyle Evans
2265952343eSKyle Evans if (argc != 1) {
2272c848957SKyle Evans fprintf(stderr, "bectl create: wrong number of arguments\n");
2285952343eSKyle Evans return (usage(false));
2295952343eSKyle Evans }
2305952343eSKyle Evans
2315952343eSKyle Evans bootenv = *argv;
232d05fa0d9SKyle Evans
233d05fa0d9SKyle Evans err = BE_ERR_SUCCESS;
234dadb9c70SKyle Evans if ((atpos = strchr(bootenv, '@')) != NULL) {
235a9c660b0SKyle Evans /*
236a9c660b0SKyle Evans * This is the "create a snapshot variant". No new boot
237a9c660b0SKyle Evans * environment is to be created here.
238a9c660b0SKyle Evans */
239a9c660b0SKyle Evans *atpos++ = '\0';
240a9c660b0SKyle Evans err = be_snapshot(be, bootenv, atpos, recursive, NULL);
2415952343eSKyle Evans } else {
242d05fa0d9SKyle Evans if (snapname == NULL)
243d05fa0d9SKyle Evans /* Create from currently booted BE */
244d05fa0d9SKyle Evans err = be_snapshot(be, be_active_path(be), NULL,
245d05fa0d9SKyle Evans recursive, snapshot);
246d05fa0d9SKyle Evans else if (strchr(snapname, '@') != NULL)
247d05fa0d9SKyle Evans /* Create from given snapshot */
248d05fa0d9SKyle Evans strlcpy(snapshot, snapname, sizeof(snapshot));
249d05fa0d9SKyle Evans else
250d05fa0d9SKyle Evans /* Create from given BE */
251d05fa0d9SKyle Evans err = be_snapshot(be, snapname, NULL, recursive,
252d05fa0d9SKyle Evans snapshot);
253d05fa0d9SKyle Evans
254d05fa0d9SKyle Evans if (err == BE_ERR_SUCCESS)
255d05fa0d9SKyle Evans err = be_create_depth(be, bootenv, snapshot,
256d05fa0d9SKyle Evans recursive == true ? -1 : 0);
2575952343eSKyle Evans }
2585952343eSKyle Evans
2595952343eSKyle Evans switch (err) {
2605952343eSKyle Evans case BE_ERR_SUCCESS:
2615952343eSKyle Evans break;
2620e6549c8SRobert Wing case BE_ERR_INVALIDNAME:
2630e6549c8SRobert Wing fprintf(stderr,
2640e6549c8SRobert Wing "bectl create: boot environment name must not contain spaces\n");
2650e6549c8SRobert Wing break;
2665952343eSKyle Evans default:
267a9c660b0SKyle Evans if (atpos != NULL)
268a9c660b0SKyle Evans fprintf(stderr,
26923614c2bSBenedict Reuschling "Failed to create a snapshot '%s' of '%s'\n",
270a9c660b0SKyle Evans atpos, bootenv);
271a9c660b0SKyle Evans else if (snapname == NULL)
2725952343eSKyle Evans fprintf(stderr,
27323614c2bSBenedict Reuschling "Failed to create bootenv %s\n", bootenv);
27416a10da8SKyle Evans else
2755952343eSKyle Evans fprintf(stderr,
27623614c2bSBenedict Reuschling "Failed to create bootenv %s from snapshot %s\n",
2775952343eSKyle Evans bootenv, snapname);
2785952343eSKyle Evans }
2795952343eSKyle Evans
2805952343eSKyle Evans return (err);
2815952343eSKyle Evans }
2825952343eSKyle Evans
2835952343eSKyle Evans
2845952343eSKyle Evans static int
bectl_cmd_export(int argc,char * argv[])2859e004b21SKyle Evans bectl_cmd_export(int argc, char *argv[])
2865952343eSKyle Evans {
2875952343eSKyle Evans char *bootenv;
2885952343eSKyle Evans
2895952343eSKyle Evans if (argc == 1) {
2902c848957SKyle Evans fprintf(stderr, "bectl export: missing boot environment name\n");
2915952343eSKyle Evans return (usage(false));
2925952343eSKyle Evans }
2935952343eSKyle Evans
2945952343eSKyle Evans if (argc > 2) {
2952c848957SKyle Evans fprintf(stderr, "bectl export: extra arguments provided\n");
2965952343eSKyle Evans return (usage(false));
2975952343eSKyle Evans }
2985952343eSKyle Evans
2995952343eSKyle Evans bootenv = argv[1];
3005952343eSKyle Evans
3015952343eSKyle Evans if (isatty(STDOUT_FILENO)) {
3022c848957SKyle Evans fprintf(stderr, "bectl export: must redirect output\n");
3035952343eSKyle Evans return (EX_USAGE);
3045952343eSKyle Evans }
3055952343eSKyle Evans
3065952343eSKyle Evans be_export(be, bootenv, STDOUT_FILENO);
3075952343eSKyle Evans
3085952343eSKyle Evans return (0);
3095952343eSKyle Evans }
3105952343eSKyle Evans
3115952343eSKyle Evans
3125952343eSKyle Evans static int
bectl_cmd_import(int argc,char * argv[])3139e004b21SKyle Evans bectl_cmd_import(int argc, char *argv[])
3145952343eSKyle Evans {
3155952343eSKyle Evans char *bootenv;
3165952343eSKyle Evans int err;
3175952343eSKyle Evans
3185952343eSKyle Evans if (argc == 1) {
3192c848957SKyle Evans fprintf(stderr, "bectl import: missing boot environment name\n");
3205952343eSKyle Evans return (usage(false));
3215952343eSKyle Evans }
3225952343eSKyle Evans
3235952343eSKyle Evans if (argc > 2) {
3242c848957SKyle Evans fprintf(stderr, "bectl import: extra arguments provided\n");
3255952343eSKyle Evans return (usage(false));
3265952343eSKyle Evans }
3275952343eSKyle Evans
3285952343eSKyle Evans bootenv = argv[1];
3295952343eSKyle Evans
3305952343eSKyle Evans if (isatty(STDIN_FILENO)) {
3312c848957SKyle Evans fprintf(stderr, "bectl import: input can not be from terminal\n");
3325952343eSKyle Evans return (EX_USAGE);
3335952343eSKyle Evans }
3345952343eSKyle Evans
3355952343eSKyle Evans err = be_import(be, bootenv, STDIN_FILENO);
3365952343eSKyle Evans
3375952343eSKyle Evans return (err);
3385952343eSKyle Evans }
3395952343eSKyle Evans
3403d1a1f2cSKyle Evans #if SOON
3415952343eSKyle Evans static int
bectl_cmd_add(int argc,char * argv[])3429e004b21SKyle Evans bectl_cmd_add(int argc, char *argv[])
3435952343eSKyle Evans {
3445952343eSKyle Evans
3455952343eSKyle Evans if (argc < 2) {
3462c848957SKyle Evans fprintf(stderr, "bectl add: must provide at least one path\n");
3475952343eSKyle Evans return (usage(false));
3485952343eSKyle Evans }
3495952343eSKyle Evans
3505952343eSKyle Evans for (int i = 1; i < argc; ++i) {
3515952343eSKyle Evans printf("arg %d: %s\n", i, argv[i]);
35216a10da8SKyle Evans /* XXX TODO catch err */
3535952343eSKyle Evans be_add_child(be, argv[i], true);
3545952343eSKyle Evans }
3555952343eSKyle Evans
3565952343eSKyle Evans return (0);
3575952343eSKyle Evans }
3583d1a1f2cSKyle Evans #endif
3595952343eSKyle Evans
3605952343eSKyle Evans static int
bectl_cmd_destroy(int argc,char * argv[])3619e004b21SKyle Evans bectl_cmd_destroy(int argc, char *argv[])
3625952343eSKyle Evans {
36377b4126cSKyle Evans nvlist_t *props;
3642a58b312SMartin Matuska char *target, targetds[BE_MAXPATHLEN];
3652a58b312SMartin Matuska const char *origin;
36677b4126cSKyle Evans int err, flags, opt;
3675952343eSKyle Evans
36877b4126cSKyle Evans flags = 0;
36977b4126cSKyle Evans while ((opt = getopt(argc, argv, "Fo")) != -1) {
3705952343eSKyle Evans switch (opt) {
3715952343eSKyle Evans case 'F':
37277b4126cSKyle Evans flags |= BE_DESTROY_FORCE;
37377b4126cSKyle Evans break;
37477b4126cSKyle Evans case 'o':
37577b4126cSKyle Evans flags |= BE_DESTROY_ORIGIN;
3765952343eSKyle Evans break;
3775952343eSKyle Evans default:
3782c848957SKyle Evans fprintf(stderr, "bectl destroy: unknown option '-%c'\n",
3795952343eSKyle Evans optopt);
3805952343eSKyle Evans return (usage(false));
3815952343eSKyle Evans }
3825952343eSKyle Evans }
3835952343eSKyle Evans
3845952343eSKyle Evans argc -= optind;
3855952343eSKyle Evans argv += optind;
3865952343eSKyle Evans
3875952343eSKyle Evans if (argc != 1) {
3882c848957SKyle Evans fprintf(stderr, "bectl destroy: wrong number of arguments\n");
3895952343eSKyle Evans return (usage(false));
3905952343eSKyle Evans }
3915952343eSKyle Evans
3925952343eSKyle Evans target = argv[0];
3935952343eSKyle Evans
39477b4126cSKyle Evans /* We'll emit a notice if there's an origin to be cleaned up */
39577b4126cSKyle Evans if ((flags & BE_DESTROY_ORIGIN) == 0 && strchr(target, '@') == NULL) {
3968338f584SKyle Evans flags |= BE_DESTROY_AUTOORIGIN;
39777b4126cSKyle Evans if (be_root_concat(be, target, targetds) != 0)
39877b4126cSKyle Evans goto destroy;
39977b4126cSKyle Evans if (be_prop_list_alloc(&props) != 0)
40077b4126cSKyle Evans goto destroy;
40177b4126cSKyle Evans if (be_get_dataset_props(be, targetds, props) != 0) {
40277b4126cSKyle Evans be_prop_list_free(props);
40377b4126cSKyle Evans goto destroy;
40477b4126cSKyle Evans }
4058338f584SKyle Evans if (nvlist_lookup_string(props, "origin", &origin) == 0 &&
4068338f584SKyle Evans !be_is_auto_snapshot_name(be, origin))
40777b4126cSKyle Evans fprintf(stderr, "bectl destroy: leaving origin '%s' intact\n",
40877b4126cSKyle Evans origin);
40977b4126cSKyle Evans be_prop_list_free(props);
41077b4126cSKyle Evans }
41177b4126cSKyle Evans
41277b4126cSKyle Evans destroy:
41377b4126cSKyle Evans err = be_destroy(be, target, flags);
4145952343eSKyle Evans
4155952343eSKyle Evans return (err);
4165952343eSKyle Evans }
4175952343eSKyle Evans
4185952343eSKyle Evans static int
bectl_cmd_mount(int argc,char * argv[])4199e004b21SKyle Evans bectl_cmd_mount(int argc, char *argv[])
4205952343eSKyle Evans {
4215952343eSKyle Evans char result_loc[BE_MAXPATHLEN];
42216a10da8SKyle Evans char *bootenv, *mountpoint;
4230a603a6eSKyle Evans int err, mntflags;
4245952343eSKyle Evans
4250a603a6eSKyle Evans /* XXX TODO: Allow shallow */
4260a603a6eSKyle Evans mntflags = BE_MNT_DEEP;
4275952343eSKyle Evans if (argc < 2) {
4282c848957SKyle Evans fprintf(stderr, "bectl mount: missing argument(s)\n");
4295952343eSKyle Evans return (usage(false));
4305952343eSKyle Evans }
4315952343eSKyle Evans
4325952343eSKyle Evans if (argc > 3) {
4332c848957SKyle Evans fprintf(stderr, "bectl mount: too many arguments\n");
4345952343eSKyle Evans return (usage(false));
4355952343eSKyle Evans }
4365952343eSKyle Evans
4375952343eSKyle Evans bootenv = argv[1];
4385952343eSKyle Evans mountpoint = ((argc == 3) ? argv[2] : NULL);
4395952343eSKyle Evans
4400a603a6eSKyle Evans err = be_mount(be, bootenv, mountpoint, mntflags, result_loc);
4415952343eSKyle Evans
4425952343eSKyle Evans switch (err) {
4435952343eSKyle Evans case BE_ERR_SUCCESS:
444760987ecSRobert Wing printf("%s\n", result_loc);
4455952343eSKyle Evans break;
4465952343eSKyle Evans default:
4475952343eSKyle Evans fprintf(stderr,
44823614c2bSBenedict Reuschling (argc == 3) ? "Failed to mount bootenv %s at %s\n" :
44923614c2bSBenedict Reuschling "Failed to mount bootenv %s at temporary path %s\n",
4505952343eSKyle Evans bootenv, mountpoint);
4515952343eSKyle Evans }
4525952343eSKyle Evans
4535952343eSKyle Evans return (err);
4545952343eSKyle Evans }
4555952343eSKyle Evans
4565952343eSKyle Evans
4575952343eSKyle Evans static int
bectl_cmd_rename(int argc,char * argv[])4589e004b21SKyle Evans bectl_cmd_rename(int argc, char *argv[])
4595952343eSKyle Evans {
46016a10da8SKyle Evans char *dest, *src;
4615952343eSKyle Evans int err;
4625952343eSKyle Evans
4635952343eSKyle Evans if (argc < 3) {
4642c848957SKyle Evans fprintf(stderr, "bectl rename: missing argument\n");
4655952343eSKyle Evans return (usage(false));
4665952343eSKyle Evans }
4675952343eSKyle Evans
4685952343eSKyle Evans if (argc > 3) {
4692c848957SKyle Evans fprintf(stderr, "bectl rename: too many arguments\n");
4705952343eSKyle Evans return (usage(false));
4715952343eSKyle Evans }
4725952343eSKyle Evans
4735952343eSKyle Evans src = argv[1];
4745952343eSKyle Evans dest = argv[2];
4755952343eSKyle Evans
4765952343eSKyle Evans err = be_rename(be, src, dest);
4775952343eSKyle Evans switch (err) {
4785952343eSKyle Evans case BE_ERR_SUCCESS:
4795952343eSKyle Evans break;
4805952343eSKyle Evans default:
48123614c2bSBenedict Reuschling fprintf(stderr, "Failed to rename bootenv %s to %s\n",
4825952343eSKyle Evans src, dest);
4835952343eSKyle Evans }
4845952343eSKyle Evans
485dadb9c70SKyle Evans return (err);
4865952343eSKyle Evans }
4875952343eSKyle Evans
488ad765da4SKyle Evans static int
bectl_cmd_unmount(int argc,char * argv[])4899e004b21SKyle Evans bectl_cmd_unmount(int argc, char *argv[])
4905952343eSKyle Evans {
49116a10da8SKyle Evans char *bootenv, *cmd;
4925952343eSKyle Evans int err, flags, opt;
4935952343eSKyle Evans
4945952343eSKyle Evans /* Store alias used */
4955952343eSKyle Evans cmd = argv[0];
4965952343eSKyle Evans
4975952343eSKyle Evans flags = 0;
4985952343eSKyle Evans while ((opt = getopt(argc, argv, "f")) != -1) {
4995952343eSKyle Evans switch (opt) {
5005952343eSKyle Evans case 'f':
5015952343eSKyle Evans flags |= BE_MNT_FORCE;
5025952343eSKyle Evans break;
5035952343eSKyle Evans default:
5042c848957SKyle Evans fprintf(stderr, "bectl %s: unknown option '-%c'\n",
5055952343eSKyle Evans cmd, optopt);
5065952343eSKyle Evans return (usage(false));
5075952343eSKyle Evans }
5085952343eSKyle Evans }
5095952343eSKyle Evans
5105952343eSKyle Evans argc -= optind;
5115952343eSKyle Evans argv += optind;
5125952343eSKyle Evans
5135952343eSKyle Evans if (argc != 1) {
5142c848957SKyle Evans fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd);
5155952343eSKyle Evans return (usage(false));
5165952343eSKyle Evans }
5175952343eSKyle Evans
5185952343eSKyle Evans bootenv = argv[0];
5195952343eSKyle Evans
5205952343eSKyle Evans err = be_unmount(be, bootenv, flags);
5215952343eSKyle Evans
5225952343eSKyle Evans switch (err) {
5235952343eSKyle Evans case BE_ERR_SUCCESS:
5245952343eSKyle Evans break;
5255952343eSKyle Evans default:
52623614c2bSBenedict Reuschling fprintf(stderr, "Failed to unmount bootenv %s\n", bootenv);
5275952343eSKyle Evans }
5285952343eSKyle Evans
5295952343eSKyle Evans return (err);
5305952343eSKyle Evans }
5315952343eSKyle Evans
532490e13c1SKyle Evans static int
bectl_cmd_check(int argc,char * argv[]__unused)533490e13c1SKyle Evans bectl_cmd_check(int argc, char *argv[] __unused)
534490e13c1SKyle Evans {
535490e13c1SKyle Evans
536490e13c1SKyle Evans /* The command is left as argv[0] */
537490e13c1SKyle Evans if (argc != 1) {
538490e13c1SKyle Evans fprintf(stderr, "bectl check: wrong number of arguments\n");
539490e13c1SKyle Evans return (usage(false));
540490e13c1SKyle Evans }
541490e13c1SKyle Evans
542490e13c1SKyle Evans return (0);
543490e13c1SKyle Evans }
5445952343eSKyle Evans
5455952343eSKyle Evans int
main(int argc,char * argv[])5465952343eSKyle Evans main(int argc, char *argv[])
5475952343eSKyle Evans {
548490e13c1SKyle Evans struct command_map_entry *cmd;
549b29bf2f8SKyle Evans const char *command;
550e819534fSDag-Erling Smørgrav char *root = NULL;
551e819534fSDag-Erling Smørgrav int opt, rc;
5525952343eSKyle Evans
553e819534fSDag-Erling Smørgrav while ((opt = getopt(argc, argv, "hr:")) != -1) {
554e819534fSDag-Erling Smørgrav switch (opt) {
555e819534fSDag-Erling Smørgrav case 'h':
556e819534fSDag-Erling Smørgrav exit(usage(true));
557e819534fSDag-Erling Smørgrav case 'r':
558e819534fSDag-Erling Smørgrav root = strdup(optarg);
559e819534fSDag-Erling Smørgrav break;
560e819534fSDag-Erling Smørgrav default:
561e819534fSDag-Erling Smørgrav exit(usage(false));
562cc624025SKyle Evans }
563e819534fSDag-Erling Smørgrav }
564e819534fSDag-Erling Smørgrav
565e819534fSDag-Erling Smørgrav argc -= optind;
566e819534fSDag-Erling Smørgrav argv += optind;
567e819534fSDag-Erling Smørgrav
568e819534fSDag-Erling Smørgrav if (argc == 0)
569e819534fSDag-Erling Smørgrav exit(usage(false));
570e819534fSDag-Erling Smørgrav
571e819534fSDag-Erling Smørgrav command = *argv;
572e819534fSDag-Erling Smørgrav optreset = 1;
573e819534fSDag-Erling Smørgrav optind = 1;
5745952343eSKyle Evans
575490e13c1SKyle Evans if ((cmd = get_cmd_info(command)) == NULL) {
57623614c2bSBenedict Reuschling fprintf(stderr, "Unknown command: %s\n", command);
5775952343eSKyle Evans return (usage(false));
5785952343eSKyle Evans }
5795952343eSKyle Evans
5804c91d6bcSGleb Smirnoff if ((be = libbe_init(root)) == NULL) {
5812a58b312SMartin Matuska if (!cmd->silent)
5824c91d6bcSGleb Smirnoff fprintf(stderr, "libbe_init(\"%s\") failed.\n",
5834c91d6bcSGleb Smirnoff root != NULL ? root : "");
5845952343eSKyle Evans return (-1);
5854c91d6bcSGleb Smirnoff }
5865952343eSKyle Evans
587490e13c1SKyle Evans libbe_print_on_error(be, !cmd->silent);
5885952343eSKyle Evans
589490e13c1SKyle Evans rc = cmd->fn(argc, argv);
5905952343eSKyle Evans
5915952343eSKyle Evans libbe_close(be);
5925952343eSKyle Evans return (rc);
5935952343eSKyle Evans }
594