Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 6 Aug 2018 03:32:25 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r337368 - projects/bectl/sbin/bectl
Message-ID:  <201808060332.w763WPS3070135@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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@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@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@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);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808060332.w763WPS3070135>