]> git.wh0rd.org - home.git/blob - .bin/custom-chroot
c4036aaad85b710226e0d560e9e1b64dc0a49f75
[home.git] / .bin / custom-chroot
1 #!/bin/bash -e
2
3 bootstrap() {
4 [[ $(id -u) -eq 0 ]] || exec sudo env -uUNSHARE HOME="$HOME" "$0" "$@"
5
6 if [[ -z ${UNSHARE} ]] ; then
7 mount_args=
8 if type -P unshare >&/dev/null ; then
9 test_arg() { unshare "$@" -- true >&/dev/null && uargs+=( "$@" ) || :; }
10 uargs=( -m )
11 test_arg -u
12 test_arg -i
13 test_arg -p -f --mount-proc
14 test_arg --propagation=private
15 UNSHARE=true exec unshare "${uargs[@]}" -- "$0" "$@"
16 fi
17 else
18 mount_args='-n'
19 fi
20 unset UNSHARE
21 }
22
23 is_mounted() {
24 local dst=$1
25 grep -sq "${dst}" /proc/mounts
26 }
27
28 maybe_mount() {
29 local src=/$1 dst=${chroot}/${2:-$1}
30 [[ -d ${src} ]] || return 0
31 if ! mkdir -p "${dst}" ; then
32 [[ -w ${chroot} ]] && exit 1 || return 0
33 fi
34 is_mounted "${dst}" || mount ${mount_args} --bind "${src}" "${dst}"
35 }
36
37 get_type() {
38 case $(file "$1") in
39 *x86-64*) echo x86_64;;
40 *"Intel 80386"*) echo i386;;
41 *32-bit*PowerPC*) echo ppc;;
42 *64-bit*PowerPC*) echo ppc64;;
43 *32-bit*S/390*) echo s390;;
44 *64-bit*S/390*) echo s390x;;
45 *64-bit*MIPS*) echo mips64;;
46 *32-bit*MIPS*N32*)echo mips64;;
47 *32-bit*MIPS*) echo mips;;
48 *32-bit*PA-RISC*) echo parisc;;
49 *64-bit*PA-RISC*) echo parisc64;;
50 *32-bit*SPARC*) echo sparc;;
51 *64-bit*SPARC*) echo sparc64;;
52 esac
53 }
54
55 init_chroot() {
56 [[ -w . ]] || return 0
57
58 if [[ ! -L etc/mtab ]] ; then
59 ln -sfT /proc/mounts etc/mtab
60 fi
61 local f dst
62 local etc=(
63 hosts
64 locale.gen
65 localtime
66 resolv.conf
67 )
68 local home=(
69 .inputrc
70 .gdbinit
71 .gitconfig
72 .nanorc
73 )
74 for f in \
75 $(printf 'etc/%s ' "${etc[@]}") \
76 ; do
77 if [[ -e /${f} ]] ; then
78 cp "/${f}" "${f}"
79 fi
80 done
81 for f in "${home[@]}" ; do
82 df="root/${f}"
83 f="${HOME}/${f}"
84 if [[ -e ${f} ]] ; then
85 cp "${f}" "${df}"
86 fi
87 done
88
89 if [[ ! -d root/.git ]] ; then
90 f="${HOME}/.profile.d/aliases.sh"
91 if [[ -e ${f} ]] ; then
92 cat "${f}" > root/.bash_profile
93 fi
94 fi
95 }
96
97 usage() {
98 cat <<-EOF
99 Usage: ${0##*/} [options] [program to run]
100
101 Sets up common mount points and then chroots in and runs a program.
102 If no program is specified, then launch a login shell.
103
104 Options:
105 -u Unmount all paths in the chroot
106 -m <path> Add path to mount list
107 -d <dir> Use <dir> as chroot (defaults to ${0%/*})
108 -h This help screen
109 EOF
110 exit
111 }
112
113 main() {
114 bootstrap "$@"
115
116 local mounts=( proc sys tmp dev dev/shm run usr/portage usr/portage/distfiles usr/local/src )
117
118 local chroot=${0%/*}
119 case ${chroot} in
120 .) chroot=${PWD} ;;
121 ./*) chroot=${PWD}/${chroot#./} ;;
122 esac
123
124 local cmd
125 while [[ -n $1 ]] ; do
126 case $1 in
127 -u) cmd='umount' ;;
128 -m) mounts+=( "$2" ); shift ;;
129 -d) chroot=$(realpath "$2"); shift ;;
130 --help|-h) usage ;;
131 -*) echo "${0##*/}: unknown option $1"; exit 1 ;;
132 *) break ;;
133 esac
134 shift
135 done
136 cd "${chroot}"
137
138 case ${cmd} in
139 umount) exec "${0%/*}/umount-tree" -y "${chroot}" ;;
140 esac
141
142 local m
143 for m in "${mounts[@]}" ; do
144 maybe_mount "${m}"
145 done
146 # Handle special mounts that we don't want to just bind mount.
147 if ! is_mounted "${chroot}/dev/pts" ; then
148 mount -t devpts devpts "${chroot}/dev/pts" \
149 -o nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5
150 fi
151
152 init_chroot
153
154 local setarch
155 if type -P setarch &>/dev/null ; then
156 local bin_dst=$(get_type bin/bash)
157 if [[ -n ${bin_dst} ]] ; then
158 setarch="setarch ${bin_dst}"
159 fi
160 fi
161
162 # Doubtful these settings we want to leak into the chroot.
163 unset ROOT PORTAGE_CONFIGROOT LD_LIBRARY_PATH
164 unset LS_COLORS # format changes over time
165 [[ $# -eq 0 ]] && set -- env HOME=/root /bin/bash -l
166 exec \
167 ${setarch} \
168 chroot "${chroot}" \
169 "$@"
170 }
171
172 main "$@"