aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2019-05-29 00:49:08 +0000
committerFelix Hanley <felix@userspace.com.au>2019-05-29 00:49:08 +0000
commitceddcd0860ca73d08490579406bfa78c0d377aa0 (patch)
tree231e0c46977307590c809fe7441b552c7be2b6a8
downloadjsh-ceddcd0860ca73d08490579406bfa78c0d377aa0.tar.gz
jsh-ceddcd0860ca73d08490579406bfa78c0d377aa0.tar.bz2
Initial import
-rw-r--r--LICENSE21
-rw-r--r--README.md32
-rwxr-xr-xjsh283
3 files changed, 336 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e9a100c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Felix Hanley
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e67c51f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+# jsh: Jail shell
+
+This is very much a work-in-progress and things are added as I need them or they break.
+
+**Do not use this script in production**
+
+```shell
+$ jsh help
+Usage: jsh [cmd]
+start <name> - Start jail <name>
+stop <name> - Stop jail <name>
+shell <name> - Start a shell in jail <name>
+create <name> [id] - Create jail <name>
+delete <name> - Delete jail <name>
+release - Release sub-commands
+template - Template sub-commands
+```
+
+```shell
+$ jsh release help
+Usage: release [cmd]
+sync - Download/unpack/update release
+fetch - Download distfiles for latest release
+extract - Unpack latest release
+update - Update latest release using freebsd-update
+```
+
+```shell
+$ jsh template help
+Usage: template [cmd]
+sync - Sync template for current release
+```
diff --git a/jsh b/jsh
new file mode 100755
index 0000000..be00932
--- /dev/null
+++ b/jsh
@@ -0,0 +1,283 @@
+#!/bin/sh
+# shellcheck disable=SC2039
+
+[ -z "${DEBUG}" ] || set -x
+set -e
+
+RELEASE="${RELEASE:-"$(sysctl -n kern.osrelease |sed -e 's/-p[0-9]*$//')"}"
+ZROOT=${ZROOT:-zroot/jails}
+JROOT=${JROOT:-/usr/local/jails}
+JARCH=${JARCH:-$(sysctl -n hw.machine_arch)}
+JDIST=".releases/$RELEASE"
+JTMPL=".templates/$RELEASE/root"
+JSKEL=".templates/$RELEASE/skel"
+DIST_SRC=${DIST_SRC:-http://mirror.internode.on.net/pub/FreeBSD/releases/${JARCH}/${RELEASE}}
+
+#JAIL_IP=${JAIL_IP:-172.16.0.%d}
+
+_err() {
+ _log "ERROR: $1"
+ exit 1
+}
+
+_log() {
+ printf "%s\n" "$1"
+}
+
+_create_zfs_datasets() {
+ _log "Creating global datasets..."
+ [ ! -d "$ZROOT" ] && zfs create -o compression=lz4 -o mountpoint="$JROOT" -p "$ZROOT"
+ [ ! -d "$ZROOT/$JDIST" ] && zfs create -p "$ZROOT/$JDIST"
+}
+
+_fetch_release() {
+ for f in base.txz lib32.txz
+ do
+ if [ ! -f "$JROOT/$JDIST/$f" ]
+ then
+ _log "Fetching $JDIST/$f..."
+ fetch -m -o "$JROOT/$JDIST/$f" "$DIST_SRC/$f"
+ fi
+ done
+}
+
+_extract_release() {
+ _template_create_zfs
+ for f in base.txz lib32.txz
+ do
+ if [ -f "$JROOT/$JDIST/$f" ]
+ then
+ _log "Extracting $JDIST/$f..."
+ tar -C "$JROOT/$JTMPL" -xkf "$JROOT/$JDIST/$f"
+ fi
+ done
+}
+
+_update_release() {
+ _log "Updating $JDIST/$f..."
+ env UNAME_r="$RELEASE" freebsd-update -b "$JROOT/$JTMPL" fetch install
+ env UNAME_r="$RELEASE" freebsd-update -b "$JROOT/$JTMPL" IDS
+}
+
+_template_create_zfs() {
+ [ ! -d "$ZROOT/$JTMPL" ] && zfs create -p "$ZROOT/$JTMPL"
+ [ ! -d "$ZROOT/$JSKEL" ] && zfs create -p "$ZROOT/$JSKEL"
+}
+
+_template_update() {
+ _template_create_zfs
+ [ -e "$JROOT/$JTMPL/var/empty" ] && chflags noschg "$JROOT/$JTMPL/var/empty"
+ cp /etc/resolv.conf "$JROOT/$JSKEL/etc/resolv.conf"
+ for d in etc usr/local tmp var root; do
+ if [ -d "$JROOT/$JTMPL/$d" ]; then
+ _log "Moving $JTMPL/$d..."
+ mkdir -p "$(dirname "$JROOT/$JSKEL/$d")"
+ mv "$JROOT/$JTMPL/$d" "$JROOT/$JSKEL/$d"
+ fi
+ done
+ [ -e "$JROOT/$JSKEL/var/empty" ] && chflags schg "$JROOT/$JSKEL/var/empty"
+
+ cd "$JROOT/$JTMPL"
+ mkdir -p s
+ for d in etc tmp var root; do
+ _log "Linking $JTMPL/$d..."
+ ln -sf "s/$d" "$d"
+ done
+ # usr/local is different
+ cd usr && ln -sf "../s/usr/local" "local"
+}
+
+_jail_new_overlay() {
+ local name=$1
+ [ -z "$name" ] && _err "Cannot create overlay: missing name"
+
+ _log "Creating overlay..."
+ [ ! -e "$ZROOT/$name" ] && zfs create -p "$ZROOT/$name"
+ [ ! -d "$ZROOT/$name/root" ] && mkdir -p "$JROOT/$name/root"
+ [ ! -d "$ZROOT/$name/overlay" ] && mkdir -p "$JROOT/$name/overlay"
+ rsync -auqv --partial "$JROOT/$JSKEL/" "$JROOT/$name/overlay"
+ sysrc -f "$JROOT/$name/overlay/etc/rc.conf" hostname="$name" >/dev/null
+}
+
+#_max_ip() {
+# return "$(jls ip4.addr | cut -d'.' -f4 | sort -n | tail -1)"
+#}
+
+_jail_new_config() {
+ local name="$1"
+ local ip="$2"
+ [ -z "$name" ] && _err "Cannot create jail config: missing name"
+ [ -z "$ip" ] && _err "Cannot set IP: missing IP address"
+ if grep -qv -e "^$name" /etc/jail.conf; then echo "$name { \$ip = $ip; }" >>/etc/jail.conf; fi
+
+ cat << EOF >"$JROOT/$name/fstab"
+$JROOT/$JTMPL $JROOT/$name/root nullfs ro 0 0
+$JROOT/$name/overlay $JROOT/$name/root/s nullfs rw 0 0
+EOF
+}
+
+_jail_start() {
+ local name="$1"; shift
+ [ -z "$name" ] && _err "Cannot start jail: missing name"
+
+ if jls -j "$name" >/dev/null 2>&1; then
+ _err "Jail $name already running"
+ fi
+ jail -c "$name"
+ [ "$1" == "-c" ] && _jail_shell "$name"
+}
+
+_jail_stop() {
+ local name="$1"
+ [ -z "$name" ] && _err "Cannot stop jail: missing name"
+
+ if [ "$(jls host.hostname jid |grep -c "^$name")" == "1" ]; then
+ jail -qr "$name"
+ else
+ _log "Jail $name is not running"
+ fi
+}
+
+_jail_shell() {
+ local name="$1"
+ [ -z "$name" ] && _err "Cannot start shell: missing name"
+ shift
+
+ if [ "$(jls host.hostname jid |grep -c "^$name")" != "1" ]; then
+ _err "Jail not running"
+ fi
+
+ if [ -z "$*" ]; then
+ /usr/sbin/jexec "$name" /bin/sh -
+ else
+ /usr/sbin/jexec "$name" "$@"
+ fi
+}
+
+_jail_list() {
+ ls -1I "$JROOT"
+}
+
+_jail_chroot() {
+ local name="$1"
+ [ -z "$name" ] && _err "Cannot start chroot: missing name"
+ local path="$JROOT/$name/root"
+ echo "--> $path"
+ env SHELL= chroot "$path"
+}
+
+_jail_delete() {
+ local name="$1"
+ [ -z "$name" ] && _err "Cannot drop jail: missing name"
+
+ if [ "$(jls host.hostname jid |grep -c "^$name")" == "1" ]; then
+ jail -qr "$name"
+ fi
+
+ zfs destroy -r "$ZROOT/$name"
+ sed -i.bak -e "/^$name/d" /etc/jail.conf
+}
+
+_cmd_template() {
+ local cmd="${1:-help}"
+ shift || true
+
+ case "$cmd" in
+ sync)
+ _template_update
+ ;;
+ *)
+ cat <<EOM
+Usage: template [cmd]
+sync - Sync template for current release
+EOM
+ ;;
+ esac
+}
+
+_cmd_release() {
+ local cmd="${1:-help}"
+ shift || true
+
+ case "$cmd" in
+ sync)
+ _create_zfs_datasets
+ _fetch_release
+ _extract_release
+ _update_release
+ ;;
+ fetch)
+ _fetch_release
+ ;;
+ extract)
+ _extract_release
+ ;;
+ update)
+ _update_release
+ ;;
+ *)
+ cat <<EOM
+Usage: release [cmd]
+sync - Download/unpack/update release
+fetch - Download distfiles for latest release
+extract - Unpack latest release
+update - Update latest release using freebsd-update
+EOM
+ ;;
+ esac
+}
+
+
+_main() {
+ local cmd="${1:-help}"
+ shift || true
+
+ case "$cmd" in
+ release)
+ _cmd_release "$@"
+ ;;
+ template)
+ _cmd_template "$@"
+ ;;
+ create|c)
+ _jail_new_overlay "$@"
+ _jail_new_config "$@"
+ ;;
+ delete)
+ _jail_delete "$@"
+ ;;
+ chroot)
+ _jail_chroot "$@"
+ ;;
+ list|ls)
+ _jail_list "$@"
+ ;;
+ start)
+ _jail_start "$@"
+ ;;
+ stop)
+ _jail_stop "$@"
+ ;;
+ restart)
+ _jail_stop "$@" && _jail_start "$@"
+ ;;
+ shell)
+ _jail_shell "$@"
+ ;;
+ *)
+ cat <<EOM
+Usage: jsh [cmd]
+start <name> - Start jail <name>
+stop <name> - Stop jail <name>
+shell <name> - Start a shell in jail <name>
+create <name> [id] - Create jail <name>
+delete <name> - Delete jail <name>
+release - Release sub-commands
+template - Template sub-commands
+EOM
+ ;;
+ esac
+}
+
+_main "$@"
+