8
error() { echo "$@" 1>&2; }
12
Usage: ${0##*/} [ options ] file cmd [ args ]
14
mount a file to a temporary mount point and then
15
invoke the provided cmd with args
17
the temporary mountpoint will be put in an a environment variable
20
if any of the arguments are the literal string '_MOUNTPOINT_', then
21
they will be replaced with the mount point. Example:
22
${0##*/} my.img chroot _MOUNTPOINT_ /bin/sh
25
-v | --verbose increase verbosity
26
--read-only use read-only mount.
27
-p | --proc bind mount /proc
28
-s | --sys bind mount /sys
29
-d | --dev bind mount /dev
30
--system-mounts bind mount /sys, /proc, /dev
31
--system-resolvconf copy host's resolvconf into /etc/resolvconf
35
# umount_r(mp) : unmount any filesystems under r
36
# this is useful to unmount a chroot that had sys, proc ... mounted
40
[ -n "$p" ] || continue
41
tac /proc/mounts | sh -c '
43
while read s mp t opt a b ; do
44
[ "${mp}" = "${p}" -o "${mp#${p}/}" != "${mp}" ] ||
46
umount "$mp" || exit 1
48
exit 0' umount_r "${p%/}"
49
[ $? -eq 0 ] || return
53
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
55
if [ -n "$UMOUNT" ]; then
57
error "WARNING: unmounting filesystems failed!"
59
if [ -n "$QEMU_DISCONNECT" ]; then
61
out=$(qemu-nbd --disconnect "$QEMU_DISCONNECT" 2>&1) || {
62
error "warning: failed: qemu-nbd --disconnect $QEMU_DISCONNECT"
66
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] ||
67
rm --one-file-system -Rf "${TEMP_D}" ||
68
error "removal of temp dir failed!"
72
local level="$1"; shift;
73
[ "${level}" -gt "${VERBOSITY}" ] && return
77
mount_callback_umount() {
78
local img_in="$1" dev="" out="" mp="" ret="" img="" ro=""
79
local opts="" bmounts="" system_resolvconf=false
82
long_opts="dev,help,proc,read-only,sys,system-mounts,system-resolvconf,verbose"
83
getopt_out=$(getopt --name "${0##*/}" \
84
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
85
eval set -- "${getopt_out}" ||
86
{ bad_Usage; return 1; }
88
while [ $# -ne 0 ]; do
91
-d|--dev) bmounts="${bmounts:+${bmounts} /dev}";;
92
-h|--help) Usage ; exit 0;;
93
-p|--proc) bmounts="${bmounts:+${bmounts} /proc}";;
94
-s|--sys) bmounts="${bmounts:+${bmounts} /sys}";;
95
--system-mounts) bmounts="/dev /proc /sys";;
96
--system-resolvconf) system_resolvconf=true;;
97
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
98
--opts) opts="${opts} $next"; shift;;
99
--read-only) ro="ro";;
105
[ $# -ge 2 ] || { bad_Usage "must provide image and cmd"; return 1; }
107
[ -n "$ro" ] && $system_resolvconf && {
108
error "--read-only is incompatible with system-resolvconf";
115
img=$(readlink -f "$img_in") ||
116
{ error "failed to get full path to $img_in"; return 1; }
118
[ "$(id -u)" = "0" ] ||
119
{ error "sorry, must be root"; return 1; }
121
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
122
{ error "failed to make tempdir"; return 1; }
127
mkdir "$mp" || return
129
local cmd="" arg="" found=false
132
if [ "${arg}" = "_MOUNTPOINT_" ]; then
133
debug 1 "replaced string _MOUNTPOINT_ in arguments arg ${#cmd[@]}"
136
cmd[${#cmd[@]}]="$arg"
139
if [ "${cmd[0]##*/}" = "bash" -o "${cmd[0]##*/}" = "sh" ] &&
140
[ ${#cmd[@]} -eq 0 ]; then
141
debug 1 "invoking shell ${cmd[0]}"
142
error "MOUNTPOINT=$mp"
146
command -v "qemu-nbd" >/dev/null 2>&1 && hasqemu=true
148
if out=$(set -f; mount -o loop${ro:+,$ro} $opts \
149
"$img" "$mp" 2>&1); then
150
debug 1 "mounted simple filesystem image '$img_in'"
154
error "simple mount of '$img_in' failed."
155
error "if this not a raw image, or it is partitioned"
156
error "you must have qemu-nbd (apt-get install qemu-utils)"
157
error "mount failed with: $out"
162
if [ -z "$UMOUNT" ]; then
163
if [ ! -e /sys/block/nbd0 ] && ! grep -q nbd /proc/modules; then
164
debug 1 "trying to load nbd module"
165
modprobe nbd >/dev/null 2>&1
166
udevadm settle >/dev/null 2>&1
168
[ -e /sys/block/nbd0 ] || {
169
error "no nbd kernel support, but simple mount failed"
174
for f in /sys/block/nbd*; do
175
[ -d "$f" -a ! -f "$f/pid" ] && nbd=${f##*/} && break
177
if [ -z "$nbd" ]; then
178
error "failed to find an nbd device"
183
if ! qemu-nbd --connect "$nbd" "$img"; then
184
error "failed to qemu-nbd connect $img to $nbd"
187
QEMU_DISCONNECT="$nbd"
189
local pfile="/sys/block/${nbd#/dev/}/pid"
190
if [ ! -f "$pfile" ]; then
191
debug 1 "waiting on pidfile for $nbd in $pfile"
193
while [ ! -f "$pfile" ] && i=$(($i+1)); do
194
if [ $i -eq 200 ]; then
195
error "giving up on pidfile $pfile for $nbd"
203
debug 1 "connected $img_in to $nbd. now udev-settling"
204
udevadm settle >/dev/null 2>&1
207
if [ -b "${nbd}p1" ]; then
210
if ( set -f; mount ${ro:+-o ${ro}} $opts "$mdev" "$mp" ) &&
212
debug 1 "mounted $mdev via qemu-nbd $nbd"
214
local pid="" pfile="/sys/block/${nbd#/dev/}/pid"
215
{ read pid < "$pfile" ; } >/dev/null 2>&1
216
[ -n "$pid" -a ! -d "/proc/$pid" ] ||
217
error "qemu-nbd process seems to have died. was '$pid'"
219
qemu-nbd --disconnect "$nbd" && QEMU_DISCONNECT=""
220
error "failed to mount $mdev"
227
for bindmp in $bmounts; do
228
[ -d "$mp${bindmp}" ] || mkdir "$mp${bindmp}" ||
229
{ error "failed mkdir $bindmp in mount"; return 1; }
230
mount --bind "$bindmp" "$mp/${bindmp}" ||
231
{ error "failed bind mount '$bindmp'"; return 1; }
234
if ${system_resolvconf}; then
235
local rcf="$mp/etc/resolv.conf"
236
debug 1 "replacing /etc/resolvconf"
237
if [ -e "$rcf" -o -L "$rcf" ]; then
238
local trcf="$rcf.${0##*/}.$$"
240
mv "$rcf" "$trcf" && ORIG_RESOLVCONF="$trcf" ||
241
{ error "failed mv $rcf"; return 1; }
243
cp "/etc/resolv.conf" "$rcf" ||
244
{ error "failed copy /etc/resolv.conf"; return 1; }
247
debug 1 "invoking: MOUNTPOINT=$mp" "${cmd[@]}"
248
MOUNTPOINT="$mp" "${cmd[@]}"
251
if ${system_resolvconf}; then
252
local rcf="$mp/etc/resolv.conf"
253
cmp --quiet "/etc/resolv.conf" "$rcf" >/dev/null ||
254
error "WARN: /etc/resolv.conf changed in image!"
256
{ [ -z "$ORIG_RESOLVCONF" ] || mv "$ORIG_RESOLVCONF" "$rcf"; } ||
257
{ error "failed to restore /etc/resolv.conf"; return 1; }
260
debug 1 "cmd returned $ret. unmounting $mp"
261
umount_r "$mp" || { error "failed umount $img"; return 1; }
265
if [ -n "$QEMU_DISCONNECT" ]; then
267
out=$(qemu-nbd --disconnect "$QEMU_DISCONNECT" 2>&1) &&
268
QEMU_DISCONNECT="" || {
269
error "failed to disconnect $QEMU_DISCONNECT";
277
mount_callback_umount "$@"
279
# vi: ts=4 noexpandtab