grml_chroot: fix broken mount argument handling
[grml-scripts.git] / usr_sbin / grml-chroot
1 #!/bin/bash
2 # Filename:      grml-chroot
3 # Purpose:       Program to chroot into another system
4 # Authors:       grml-team (grml.org), (c) Michael Gebetsroither <gebi@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 ################################################################################
8
9 PROG_NAME_=$(basename "$0")
10 DEST_=""
11 MOUNTED_=""     # all mounted destinations
12
13
14 function die
15 {
16     echo "Error: $*" >&2
17     exit 1
18 }
19
20 function printUsage
21 {
22     cat <<EOT
23 Usage: "$PROG_NAME_" NEWROOT [COMMAND....]
24
25 $PROG_NAME_ is a chroot wrapper with proc/sys/pts/dev filesystem handling
26
27 EOT
28 }
29
30 function storeMounts
31 {
32     local to_append_="$1"
33     if [[ $MOUNTED_ == "" ]]; then
34         MOUNTED_="$to_append_"
35     else
36         MOUNTED_="$MOUNTED_ $to_append_"
37     fi
38 }
39
40 function mountit
41 {
42     local type_="$1" # type _or_ src
43     local dest_="$2"
44     local options_="$3"
45
46     local all_options_=()
47
48     if [[ $options_ == "--bind" ]]; then
49         all_options_+=(--bind "$type_")
50     else
51         all_options_+=(-t "$type_" none)
52     fi
53     mount "${all_options_[@]}" "${DEST_}/$dest_" && storeMounts "$dest_"
54 }
55
56 function umount_all
57 {
58     local reverse
59     reverse=$(echo "$MOUNTED_" | awk '{ for (i=NF; i>1; i--) printf("%s ",$i); print $1; }')
60     for i in $reverse; do
61         umount "${DEST_}/$i"
62     done
63 }
64
65
66 ###
67 ### __MAIN
68 ###
69
70 while getopts "h" opt; do
71     case "$opt" in
72         h) printUsage; exit 0 ;;
73         ?) printUsage; exit 64 ;;
74     esac
75 done
76 shift $((OPTIND - 1))
77
78 if (( $# < 1 )); then
79     printUsage
80     die "Wrong number of arguments."
81 fi
82
83 if ! command -v awk >/dev/null 2>&1 ; then
84   die "No awk binary found, required for execution."
85 fi
86
87 DEST_="$1"; shift
88
89 if [ ! -d "$DEST_" ]; then
90     die "Target chroot does not exist: $DEST_"
91 fi
92
93
94
95 if [ -f "$DEST_"/proc/cmdline ] ; then
96     echo "Looks like $DEST_ already has filesystems mounted, skipping."
97 else
98     mountit "proc"  "proc"
99     mountit "sysfs" "sys"
100     mountit "/dev"   "dev"   "--bind"
101     mountit "devpts" "dev/pts"
102     if [ -d /sys/firmware/efi/efivars ] ; then
103       mountit "efivarfs" "sys/firmware/efi/efivars"
104     fi
105     if [ -d "$DEST_"/run/udev ] && [ -d /run/udev ] ; then
106       mountit "/run/udev" "/run/udev" "--bind"
107     fi
108 fi
109
110 WROTE_DEBIAN_CHROOT=""
111 if [ ! -f "$DEST_"/etc/debian_chroot ]; then
112     WROTE_DEBIAN_CHROOT="yes"
113     echo "Writing /etc/debian_chroot ..."
114     cat "$DEST_"/etc/hostname > "$DEST_"/etc/debian_chroot
115 fi
116
117 if (( $# < 1 )); then
118     chroot "$DEST_"
119     RC=$?
120 else
121     chroot "$DEST_" "$@"
122     RC=$?
123 fi
124 umount_all
125
126 if [ -n "$WROTE_DEBIAN_CHROOT" ]; then
127     rm "$DEST_"/etc/debian_chroot
128 fi
129
130 exit $RC