]> git.wh0rd.org Git - 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 "$@"