-
Notifications
You must be signed in to change notification settings - Fork 2
/
chimera-chroot
executable file
·143 lines (118 loc) · 3.03 KB
/
chimera-chroot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/bin/sh
#
# Chimera Linux chroot script
#
# Copyright 2023-2024 q66 <[email protected]>
#
# License: BSD-2-Clause
#
readonly PROGNAME=$(basename "$0")
MOUNTED_PSEUDO=
ROOT_DIR=
RESOLV_SAVED=
RESOLV_REPLACED=
do_trymount() {
if mountpoint -q "${ROOT_DIR}/$1" > /dev/null 2>&1; then
return 0
fi
mount --rbind "/$1" "${ROOT_DIR}/$1" || die "Failed to mount ${1}fs"
mount --make-rslave "${ROOT_DIR}/$1" || die "Failed to make ${1} rslave"
MOUNTED_PSEUDO="${MOUNTED_PSEUDO} $1"
}
mount_pseudo() {
do_trymount dev
do_trymount proc
do_trymount sys
do_trymount tmp
}
umount_pseudo() {
sync
for mnt in ${MOUNTED_PSEUDO}; do
[ -n "$mnt" ] || continue
umount -R -f "${ROOT_DIR}/$mnt" > /dev/null 2>&1
done
}
replace_resolv() {
# do not touch if target /etc is missing or if we do not have resolv.conf
[ -d "${ROOT_DIR}/etc" -a -f /etc/resolv.conf ] || return 0
RESOLV_REPLACED="${ROOT_DIR}/etc/resolv.conf"
# save the existing one if needed
if [ -e "$RESOLV_REPLACED" -o -L "$RESOLV_REPLACED" ]; then
RESOLV_SAVED="${ROOT_DIR}/etc/resolv.conf.chimera-chroot.$$"
# make space, this should not do anything
rm -f "$RESOLV_SAVED" > /dev/null 2>&1
# try moving, on failure unset saved
if ! mv "$RESOLV_REPLACED" "$RESOLV_SAVED" > /dev/null 2>&1; then
RESOLV_SAVED=
RESOLV_REPLACED=
return 0
fi
fi
# now replace it
cp /etc/resolv.conf "$RESOLV_REPLACED" > /dev/null 2>&1
}
restore_resolv() {
# restore best we can
[ -n "$RESOLV_REPLACED" ] && \
rm -f "$RESOLV_REPLACED" > /dev/null 2>&1
[ -n "$RESOLV_SAVED" ] && \
mv "$RESOLV_SAVED" "$RESOLV_REPLACED" > /dev/null 2>&1
RESOLV_SAVED=
RESOLV_REPLACED=
}
msg() {
printf "\033[1m$@\n\033[m"
}
error_sig() {
restore_resolv
umount_pseudo
[ -n "$REPOSF" ] && rm -f "$REPOSF"
[ -n "$EREPOSF" ] && rm -f "$EREPOSF"
exit ${1:=0}
}
trap 'error_sig $? $LINENO' INT TERM 0
die() {
echo "ERROR: $@"
error_sig 1 $LINENO
}
usage() {
cat << EOF
Usage: $PROGNAME [opts] root [command] [args]...
This script chroots into the given root, much like the actual chroot
command. However, it also ensures that pseudo-filesystems are mounted
and other things necessary for remote installation manipulation.
Options:
-r Do not touch resolv.conf.
-h Print this message.
EOF
exit ${1:=1}
}
# ensure we run as root
if [ "$(id -u)" != "0" ]; then
die "Must run this as root."
fi
REPLACE_RESOLV=1
while getopts "rh" opt; do
case "$opt" in
r) REPLACE_RESOLV=0 ;;
h) usage 0 ;;
*) usage 1 ;;
esac
done
shift $((OPTIND - 1))
ROOT_DIR="$1"
shift
# ensure the target exists
[ -d "$ROOT_DIR" ] || die "root directory does not exist"
mount_pseudo
if [ "$REPLACE_RESOLV" -eq 1 ]; then
replace_resolv
fi
if [ -f "${ROOT_DIR}/etc/chimera-release" ]; then
export SHELL=/bin/sh
fi
PS1="(chroot) $PS1" chroot "$ROOT_DIR" "$@"
RC=$?
restore_resolv
umount_pseudo
exit $RC