summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2021-08-21 18:48:47 -0400
committerAndrew Cady <d@jerkface.net>2021-08-21 18:48:47 -0400
commit62775e2d68b310725560b85da99c85632b525874 (patch)
treeb3107608d10a857ffe4eb6237fe2dd5b8033f62a
initialHEADmaster
-rwxr-xr-xforkroot120
1 files changed, 120 insertions, 0 deletions
diff --git a/forkroot b/forkroot
new file mode 100755
index 0000000..1ab4244
--- /dev/null
+++ b/forkroot
@@ -0,0 +1,120 @@
1#!/bin/bash
2die() { printf 'Error: %s\n' "$*"; exit 1; }
3if [ $UID != 0 ]
4then
5 exec sudo -- "$0" "$@" || die 'You are not root.'
6fi
7
8help()
9{
10 printf '%s\n' "Usage: $0 [-h|--help] [--] <target directory>"
11}
12
13unset force delete verbose
14while [ $# -gt 0 ]
15do
16 case "$1" in
17 -h|--help) help; exit;;
18 --force) force=y ;;
19 --delete-after) delete=y ;;
20 -v) verbose=y ;;
21 --) shift; break ;;
22 -*) die unknown option ;;
23 *) break;
24 esac
25 shift
26done
27
28[ $# = 1 ] || die 'You must specify a target directory to create.'
29
30target=$1
31root=$target/root
32mkdir "$target" || die 'creating target directory'
33
34btrfs subvolume snapshot / "$root"
35
36verbosely()
37{
38 (
39 if [ "$verbose" ]
40 then set -x
41 fi
42 "$@"
43 )
44}
45
46bind_it()
47{
48 verbosely mount --bind "$mountpoint" "$root"/"$mountpoint"
49}
50
51copy_mountpoint()
52{
53 [ "$1" -a "$2" ] || return
54
55 [ -d "$2" ] && return
56 [ -d "${2%/*}" ] || copy_mountpoint "${1%/*}" "${2%/*}"
57 mkdir -p "$2"
58 chown --reference "$1" "$2"
59 chmod --reference "$1" "$2"
60}
61
62mounts=$(tempfile)
63cat /proc/mounts > "$mounts"
64
65while read mountdev mountpoint fstype fsoptions _
66do
67 case "$mountpoint" in
68 /sys |/proc |/dev |/usr | /usr/local) bind_it; continue ;;
69 /sys/*|/proc/*|/dev/* ) continue ;;
70 esac
71 case "$PWD" in
72 "$mountpoint"/*) bind_it; continue ;;
73 esac
74
75 case "$fstype" in
76 tmpfs)
77 case "$mountpoint" in
78 /run/*) copy_mountpoint "$mountpoint" "$root"/"$mountpoint" ;;
79 esac
80 mount "$mountdev" -t "$fstype" -o "$fsoptions" "$root"/"$mountpoint" ;;
81 esac
82done < "$mounts"
83
84tac "$mounts" |
85while read mountdev mountpoint fstype fsoptions _
86do
87 case "$mountpoint" in "$root"/*) verbosely umount -l "$mountpoint";; esac
88done
89
90chroot "$root" /bin/bash
91
92confirm()
93{
94 cat <<EOF
95The following command will execute:
96
97
98
99 $*
100
101
102
103The data will be permanently lost.
104
105EOF
106 read -p "Continue? [y/N]> " line
107 case "$line" in
108 [yY]) "$@"; return ;;
109 esac
110}
111
112if [ "$delete" -a "$force" ]
113then
114 btrfs subvolume delete "$target"/root
115 rmdir "$target"
116elif [ "$delete" ]
117then
118 confirm btrfs subvolume delete "$target"/root
119 rmdir "$target"
120fi