grml-chroot: properly handle multiple chroots [Closes: issue659]
[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 function bailout
14 {
15   umount_all
16   die "Bailout"
17 }
18 trap bailout 1 2 3 3 6 9 14 15
19
20 function die
21 {
22     echo "Error: $@" >&2
23     exit 1
24 }
25
26 function isMounted
27 {
28     local dir="$1"
29     if cut -d\  -f 2 /proc/mounts | grep -q "$dir"; then
30         return 0
31     else
32         return 1
33     fi
34 }
35
36 function printUsage
37 {
38     cat <<EOT
39 Usage: "$PROG_NAME_" NEWROOT [COMMAND....]
40
41 $PROG_NAME_ is a chroot wrapper with proc/sys/pts/dev filesystem handling
42
43 EOT
44 }
45
46 function storeMounts
47 {
48     local to_append_="$1"
49     if [[ $MOUNTED_ == "" ]]; then
50         MOUNTED_="$to_append_"
51     else
52         MOUNTED_="$MOUNTED_ $to_append_"
53     fi
54 }
55
56 function mountit
57 {
58     local type_="$1" # type _or_ src
59     local dest_="$2"
60     local options_="$3"
61
62     local all_options_=""
63
64     if ! isMounted "${DEST_}/$dest_"; then
65       if [[ $options_ == "--bind" ]]; then
66         all_options_="--bind $type_"
67       else
68         all_options_="-t $type_ none"
69       fi
70       mount $all_options_ "${DEST_}/$dest_" && storeMounts "$dest_"
71     fi
72 }
73
74 function umount_all
75 {
76     for i in /proc /sys /dev; do
77         umount "${DEST_}/${i}"
78     done
79
80     rm -f "$DEST_"/etc/debian_chroot
81 }
82
83
84 ###
85 ### __MAIN
86 ###
87
88 while getopts "h" opt; do
89     case "$opt" in
90         h) printUsage; exit 0 ;;
91         ?) printUsage; exit 64 ;;
92     esac
93 done
94 shift $(($OPTIND - 1))
95
96 if (( $# < 1 )); then
97     printUsage
98     die "Wrong number of arguments."
99 fi
100
101 DEST_="$1"; shift
102
103 if [ ! -d "$DEST_" ]; then
104     die "Target chroot does not exist: $DEST_"
105 fi
106
107
108 mountit "proc"  "proc"
109 mountit "sysfs" "sys"
110 mountit "/dev"   "dev"   "--bind"
111
112 # do not write to /var/run of chroot if it's not present
113 if [ -d "$DEST_/tmp" ] ; then
114   STATEDIR="tmp/grml-chroot"
115   mkdir -p "$DEST_/$STATEDIR"
116   touch "$DEST_/$STATEDIR/$$"
117 fi
118
119 if [ ! -e "$DEST_"/etc/debian_chroot ]; then
120     echo "Writing /etc/debian_chroot ..."
121     cat "$DEST_"/etc/hostname > "$DEST_"/etc/debian_chroot
122 fi
123
124 if (( $# < 1 )); then
125     chroot "$DEST_"
126     RC=$?
127 else
128     chroot "$DEST_" "$@"
129     RC=$?
130 fi
131
132 if [ -z "$STATEDIR" ] ; then
133   umount_all
134 else
135   rm "$DEST_/$STATEDIR/$$"
136
137   if rmdir "$DEST_/$STATEDIR" 2>/dev/null; then
138     umount_all
139   fi
140 fi
141
142 exit $RC