svn commit: r337368 - projects/bectl/sbin/bectl
Kyle Evans
kevans at FreeBSD.org
Mon Aug 6 03:32:27 UTC 2018
Author: kevans
Date: Mon Aug 6 03:32:25 2018
New Revision: 337368
URL: https://svnweb.freebsd.org/changeset/base/337368
Log:
bectl(8): bectl jail improvements
- Support passing arbitrary jail arguments via -o
- Split the related (and rewritten since the GSoC) jail bits out into a new
bectl_jail.c file, to reduce clutter in bectl.c
- Don't use RFC 1918 IP space [0]; we'll instead set no default IPv4 and let
the user pass in any address options they wish via -o
Reported by: rgrimes [0], Shawn Webb [0]
Added:
projects/bectl/sbin/bectl/bectl.h (contents, props changed)
projects/bectl/sbin/bectl/bectl_jail.c (contents, props changed)
Modified:
projects/bectl/sbin/bectl/Makefile
projects/bectl/sbin/bectl/bectl.8
projects/bectl/sbin/bectl/bectl.c
Modified: projects/bectl/sbin/bectl/Makefile
==============================================================================
--- projects/bectl/sbin/bectl/Makefile Mon Aug 6 02:10:52 2018 (r337367)
+++ projects/bectl/sbin/bectl/Makefile Mon Aug 6 03:32:25 2018 (r337368)
@@ -3,6 +3,8 @@
PROG= bectl
MAN= bectl.8
+SRCS= bectl.c bectl_jail.c
+
LIBADD+= be
LIBADD+= jail
LIBADD+= nvpair
Modified: projects/bectl/sbin/bectl/bectl.8
==============================================================================
--- projects/bectl/sbin/bectl/bectl.8 Mon Aug 6 02:10:52 2018 (r337367)
+++ projects/bectl/sbin/bectl/bectl.8 Mon Aug 6 03:32:25 2018 (r337368)
@@ -14,7 +14,7 @@
.\" @(#)be.1
.\" $FreeBSD$
.\"
-.Dd July 24, 2018
+.Dd August 5, 2018
.Dt BECTL 8
.Os FreeBSD
.Sh NAME
@@ -40,6 +40,7 @@ destroy
.Ao Ar beName | beName at snapshot Ac
.Nm
jail
+.Op Fl o Ar key Ns = Ns Ar value Oc Ns ...
.Ao Ar jailID | jailName Ac
.Ao Ar bootenv Ac
.Nm
@@ -123,10 +124,32 @@ Specifying
will automatically unmount without confirmation.
.Pp
.It Ic jail
+.Op Fl o Ar key Ns = Ns Ar value Oc Ns ...
.Ao Ar jailID | jailName Ac
.Ao Ar bootenv Ac
.Pp
Creates a jail of the given boot environment.
+Multiple
+.Fl o
+arguments may be specified.
+Al
+.Ar key ,
+.Ar value
+pairs are interpreted as jail parameters as described in
+.Xr jail 8 .
+The following default parameters are provided:
+.Bl -tag -width -indent
+.It Va allow.mount Ns = Ns Ar true
+.It Va allow.mount.devfs Ns = Ns Ar true
+.It Va enforce_statfs Ns = Ns Ar 1
+.It Va name Ns = Ns Ar bootenv
+.It Va host.hostname Ns = Ns Ar bootenv
+.It Va path
+Set to a path in /tmp generated by
+.Xr libbe 8 .
+.El
+.pp
+All default parameters may be overwritten.
.Pp
.It Ic list
.Op Fl a
Modified: projects/bectl/sbin/bectl/bectl.c
==============================================================================
--- projects/bectl/sbin/bectl/bectl.c Mon Aug 6 02:10:52 2018 (r337367)
+++ projects/bectl/sbin/bectl/bectl.c Mon Aug 6 03:32:25 2018 (r337368)
@@ -27,10 +27,8 @@
*/
#include <sys/param.h>
-#include <sys/jail.h>
#include <sys/mount.h>
#include <errno.h>
-#include <jail.h>
#include <libutil.h>
#include <stdbool.h>
#include <stdio.h>
@@ -43,6 +41,8 @@
#include <be.h>
+#include "bectl.h"
+
#define HEADER_BE "BE"
#define HEADER_BEPLUS "BE/Dataset/Snapshot"
#define HEADER_ACTIVE "Active"
@@ -71,7 +71,6 @@ static int bectl_cmd_destroy(int argc, char *argv[]);
static int bectl_cmd_export(int argc, char *argv[]);
static int bectl_cmd_import(int argc, char *argv[]);
static int bectl_cmd_add(int argc, char *argv[]);
-static int bectl_cmd_jail(int argc, char *argv[]);
static const char *get_origin_props(nvlist_t *dsprops, nvlist_t **originprops);
static void print_padding(const char *fval, int colsz, struct printc *pc);
static int print_snapshots(const char *dsname, struct printc *pc);
@@ -80,14 +79,11 @@ static void print_headers(nvlist_t *props, struct prin
static int bectl_cmd_list(int argc, char *argv[]);
static int bectl_cmd_mount(int argc, char *argv[]);
static int bectl_cmd_rename(int argc, char *argv[]);
-static int bectl_search_jail_paths(const char *mnt);
-static int bectl_locate_jail(const char *ident);
-static int bectl_cmd_unjail(int argc, char *argv[]);
static int bectl_cmd_unmount(int argc, char *argv[]);
-static libbe_handle_t *be;
+libbe_handle_t *be;
-static int
+int
usage(bool explicit)
{
FILE *fp;
@@ -102,7 +98,7 @@ usage(bool explicit)
"\tbectl export sourceBe\n"
"\tbectl import targetBe\n"
"\tbectl add (path)*\n"
- "\tbectl jail bootenv\n"
+ "\tbectl jail [ -o key=value ]... bootenv\n"
"\tbectl list [-a] [-D] [-H] [-s]\n"
"\tbectl mount beName [mountpoint]\n"
"\tbectl rename origBeName newBeName\n"
@@ -379,58 +375,6 @@ bectl_cmd_destroy(int argc, char *argv[])
return (err);
}
-
-static int
-bectl_cmd_jail(int argc, char *argv[])
-{
- char *bootenv;
- char mnt_loc[BE_MAXPATHLEN];
- int err, jid;
-
- /* struct jail be_jail = { 0 }; */
-
- if (argc == 1) {
- fprintf(stderr, "bectl jail: missing boot environment name\n");
- return (usage(false));
- }
- if (argc > 2) {
- fprintf(stderr, "bectl jail: too many arguments\n");
- return (usage(false));
- }
-
- bootenv = argv[1];
-
- /*
- * XXX TODO: if its already mounted, perhaps there should be a flag to
- * indicate its okay to proceed??
- */
- if ((err = be_mount(be, bootenv, NULL, 0, mnt_loc)) != BE_ERR_SUCCESS) {
- fprintf(stderr, "could not mount bootenv\n");
- return (1);
- }
-
- /* XXX TODO: Make the IP/hostname configurable? */
- jid = jail_setv(JAIL_CREATE | JAIL_ATTACH,
- "name", bootenv,
- "path", mnt_loc,
- "host.hostname", bootenv,
- "persist", "true",
- "ip4.addr", "10.20.30.40",
- "allow.mount", "true",
- "allow.mount.devfs", "true",
- "enforce_statfs", "1",
- NULL);
- if (jid == -1) {
- fprintf(stderr, "unable to create jail. error: %d\n", errno);
- return (1);
- }
-
- /* We're attached within the jail... good bye! */
- chdir("/");
- execl("/bin/sh", "/bin/sh", NULL);
- return (0);
-}
-
/*
* Given a set of dataset properties (for a BE dataset), populate originprops
* with the origin's properties.
@@ -850,105 +794,6 @@ bectl_cmd_rename(int argc, char *argv[])
return (0);
}
-
-static int
-bectl_search_jail_paths(const char *mnt)
-{
- char jailpath[MAXPATHLEN + 1];
- int jid;
-
- jid = 0;
- (void)mnt;
- while ((jid = jail_getv(0, "lastjid", &jid, "path", &jailpath,
- NULL)) != -1) {
- if (strcmp(jailpath, mnt) == 0)
- return (jid);
- }
-
- return (-1);
-}
-
-/*
- * Locate a jail based on an arbitrary identifier. This may be either a name,
- * a jid, or a BE name. Returns the jid or -1 on failure.
- */
-static int
-bectl_locate_jail(const char *ident)
-{
- nvlist_t *belist, *props;
- char *mnt;
- int jid;
-
- /* Try the easy-match first */
- jid = jail_getid(ident);
- if (jid != -1)
- return (jid);
-
- /* Attempt to try it as a BE name, first */
- if (be_prop_list_alloc(&belist) != 0)
- return (-1);
-
- if (be_get_bootenv_props(be, belist) != 0)
- return (-1);
-
- if (nvlist_lookup_nvlist(belist, ident, &props) == 0) {
- /* We'll attempt to resolve the jid by way of mountpoint */
- if (nvlist_lookup_string(props, "mountpoint", &mnt) == 0) {
- jid = bectl_search_jail_paths(mnt);
- be_prop_list_free(belist);
- return (jid);
- }
-
- be_prop_list_free(belist);
- }
-
- return (-1);
-}
-
-static int
-bectl_cmd_unjail(int argc, char *argv[])
-{
- char path[MAXPATHLEN + 1];
- char *cmd, *name, *target;
- int jid;
-
- /* Store alias used */
- cmd = argv[0];
-
- if (argc != 2) {
- fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd);
- return (usage(false));
- }
-
- target = argv[1];
-
- /* Locate the jail */
- if ((jid = bectl_locate_jail(target)) == -1) {
- fprintf(stderr, "bectl %s: failed to locate BE by '%s'\n", cmd, target);
- return (1);
- }
-
- bzero(&path, MAXPATHLEN + 1);
- name = jail_getname(jid);
- if (jail_getv(0, "name", name, "path", path, NULL) != jid) {
- free(name);
- fprintf(stderr, "bectl %s: failed to get path for jail requested by '%s'\n", cmd, target);
- return (1);
- }
-
- free(name);
-
- if (be_mounted_at(be, path, NULL) != 0) {
- fprintf(stderr, "bectl %s: jail requested by '%s' not a BE\n", cmd, target);
- return (1);
- }
-
- jail_remove(jid);
- unmount(path, 0);
-
- return (0);
-}
-
static int
bectl_cmd_unmount(int argc, char *argv[])
Added: projects/bectl/sbin/bectl/bectl.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/bectl/sbin/bectl/bectl.h Mon Aug 6 03:32:25 2018 (r337368)
@@ -0,0 +1,35 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Kyle Evans <kevans at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int usage(bool explicit);
+
+int bectl_cmd_jail(int argc, char *argv[]);
+int bectl_cmd_unjail(int argc, char *argv[]);
+
+extern libbe_handle_t *be;
Added: projects/bectl/sbin/bectl/bectl_jail.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/bectl/sbin/bectl/bectl_jail.c Mon Aug 6 03:32:25 2018 (r337368)
@@ -0,0 +1,312 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Kyle Evans <kevans at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/jail.h>
+#include <sys/mount.h>
+#include <err.h>
+#include <jail.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <be.h>
+
+#include "bectl.h"
+
+static void jailparam_grow(void);
+static void jailparam_add(const char *name, const char *val);
+static bool jailparam_addarg(char *arg);
+
+static int bectl_search_jail_paths(const char *mnt);
+static int bectl_locate_jail(const char *ident);
+
+/* We'll start with 8 parameters initially and grow as needed. */
+#define INIT_PARAMCOUNT 8
+
+static struct jailparam *jp;
+static int jpcnt;
+static int jpused;
+static char mnt_loc[BE_MAXPATHLEN + 1];
+
+static void
+jailparam_grow(void)
+{
+
+ jpcnt *= 2;
+ jp = realloc(jp, jpcnt * sizeof(*jp));
+ if (jp == NULL)
+ err(2, "realloc");
+}
+
+static void
+jailparam_add(const char *name, const char *val)
+{
+ int i;
+
+ for (i = 0; i < jpused; ++i) {
+ if (strcmp(name, jp[i].jp_name) == 0)
+ break;
+ }
+
+ if (i < jpused)
+ jailparam_free(&jp[i], 1);
+ else if (jpused == jpcnt)
+ /* The next slot isn't allocated yet */
+ jailparam_grow();
+
+ if (jailparam_init(&jp[i], name) != 0)
+ return;
+ if (jailparam_import(&jp[i], val) != 0)
+ return;
+ ++jpused;
+}
+
+static bool
+jailparam_addarg(char *arg)
+{
+ char *name, *val;
+
+ if (arg == NULL)
+ return (false);
+ name = arg;
+ if ((val = strchr(arg, '=')) == NULL) {
+ fprintf(stderr, "bectl jail: malformed jail option '%s'\n",
+ arg);
+ return (false);
+ }
+
+ *val++ = '\0';
+ if (strcmp(name, "path") == 0) {
+ if (strlen(val) > BE_MAXPATHLEN) {
+ fprintf(stderr,
+ "bectl jail: skipping too long path assignment '%s' (max length = %d)\n",
+ val, BE_MAXPATHLEN);
+ return (false);
+ }
+ strcpy(mnt_loc, val);
+ }
+ jailparam_add(name, val);
+ return (true);
+}
+
+int
+bectl_cmd_jail(int argc, char *argv[])
+{
+ char *bootenv, *mountpoint;
+ int jid, opt;
+ bool default_hostname, default_name;
+
+ default_hostname = default_name = true;
+ jpcnt = INIT_PARAMCOUNT;
+ jp = malloc(jpcnt * sizeof(*jp));
+ if (jp == NULL)
+ err(2, "malloc");
+
+ jailparam_add("persist", "true");
+ jailparam_add("allow.mount", "true");
+ jailparam_add("allow.mount.devfs", "true");
+ jailparam_add("enforce_statfs", "1");
+
+ while ((opt = getopt(argc, argv, "o:")) != -1) {
+ switch (opt) {
+ case 'o':
+ if (jailparam_addarg(optarg)) {
+ /*
+ * optarg has been modified to null terminate
+ * at the assignment operator.
+ */
+ if (strcmp(optarg, "name") == 0)
+ default_name = false;
+ if (strcmp(optarg, "host.hostname") == 0)
+ default_hostname = false;
+ }
+ break;
+ default:
+ fprintf(stderr, "bectl jail: unknown option '-%c'\n",
+ optopt);
+ return (usage(false));
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* struct jail be_jail = { 0 }; */
+ if (argc < 1) {
+ fprintf(stderr, "bectl jail: missing boot environment name\n");
+ return (usage(false));
+ }
+ if (argc > 2) {
+ fprintf(stderr, "bectl jail: too many arguments\n");
+ return (usage(false));
+ }
+
+ bootenv = argv[0];
+
+ /*
+ * XXX TODO: if its already mounted, perhaps there should be a flag to
+ * indicate its okay to proceed??
+ */
+ if (*mnt_loc == '\0')
+ mountpoint = NULL;
+ else
+ mountpoint = mnt_loc;
+ if (be_mount(be, bootenv, mountpoint, 0, mnt_loc) != BE_ERR_SUCCESS) {
+ fprintf(stderr, "could not mount bootenv\n");
+ return (1);
+ }
+
+ if (default_name)
+ jailparam_add("name", bootenv);
+ if (default_hostname)
+ jailparam_add("host.hostname", bootenv);
+ /*
+ * This is our indicator that path was not set by the user, so we'll use
+ * the path that libbe generated for us.
+ */
+ if (mountpoint == NULL)
+ jailparam_add("path", mnt_loc);
+ jid = jailparam_set(jp, jpused, JAIL_CREATE | JAIL_ATTACH);
+ if (jid == -1) {
+ fprintf(stderr, "unable to create jail. error: %d\n", errno);
+ return (1);
+ }
+
+ jailparam_free(jp, jpused);
+ free(jp);
+
+ /* We're attached within the jail... good bye! */
+ chdir("/");
+ execl("/bin/sh", "/bin/sh", NULL);
+ return (0);
+}
+
+static int
+bectl_search_jail_paths(const char *mnt)
+{
+ char jailpath[MAXPATHLEN + 1];
+ int jid;
+
+ jid = 0;
+ (void)mnt;
+ while ((jid = jail_getv(0, "lastjid", &jid, "path", &jailpath,
+ NULL)) != -1) {
+ if (strcmp(jailpath, mnt) == 0)
+ return (jid);
+ }
+
+ return (-1);
+}
+
+/*
+ * Locate a jail based on an arbitrary identifier. This may be either a name,
+ * a jid, or a BE name. Returns the jid or -1 on failure.
+ */
+static int
+bectl_locate_jail(const char *ident)
+{
+ nvlist_t *belist, *props;
+ char *mnt;
+ int jid;
+
+ /* Try the easy-match first */
+ jid = jail_getid(ident);
+ if (jid != -1)
+ return (jid);
+
+ /* Attempt to try it as a BE name, first */
+ if (be_prop_list_alloc(&belist) != 0)
+ return (-1);
+
+ if (be_get_bootenv_props(be, belist) != 0)
+ return (-1);
+
+ if (nvlist_lookup_nvlist(belist, ident, &props) == 0) {
+ /* We'll attempt to resolve the jid by way of mountpoint */
+ if (nvlist_lookup_string(props, "mountpoint", &mnt) == 0) {
+ jid = bectl_search_jail_paths(mnt);
+ be_prop_list_free(belist);
+ return (jid);
+ }
+
+ be_prop_list_free(belist);
+ }
+
+ return (-1);
+}
+
+int
+bectl_cmd_unjail(int argc, char *argv[])
+{
+ char path[MAXPATHLEN + 1];
+ char *cmd, *name, *target;
+ int jid;
+
+ /* Store alias used */
+ cmd = argv[0];
+
+ if (argc != 2) {
+ fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd);
+ return (usage(false));
+ }
+
+ target = argv[1];
+
+ /* Locate the jail */
+ if ((jid = bectl_locate_jail(target)) == -1) {
+ fprintf(stderr, "bectl %s: failed to locate BE by '%s'\n", cmd,
+ target);
+ return (1);
+ }
+
+ bzero(&path, MAXPATHLEN + 1);
+ name = jail_getname(jid);
+ if (jail_getv(0, "name", name, "path", path, NULL) != jid) {
+ free(name);
+ fprintf(stderr,
+ "bectl %s: failed to get path for jail requested by '%s'\n",
+ cmd, target);
+ return (1);
+ }
+
+ free(name);
+
+ if (be_mounted_at(be, path, NULL) != 0) {
+ fprintf(stderr, "bectl %s: jail requested by '%s' not a BE\n",
+ cmd, target);
+ return (1);
+ }
+
+ jail_remove(jid);
+ unmount(path, 0);
+
+ return (0);
+}
More information about the svn-src-projects
mailing list