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>