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