-
Notifications
You must be signed in to change notification settings - Fork 3
/
mer-android-chroot
executable file
·361 lines (301 loc) · 10.1 KB
/
mer-android-chroot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#!/bin/bash
# mer-android-chroot
usage()
{
cat <<EOF
usage: $0 [-v] [-u <user>] [-m <all|none|root|home>] [-r <SDK root path>] [<command> <args> ..]
$0 -h
This is the Mer android building chroot SDK.
For information see http://wiki.merproject.org/wiki/Android_SDK
If command is not present,
used to enter the SDK and begin working. The SDK bash shell
is a login shell. See below for .profile handling. May be
used in multiple terminals and simply enters the chroot
If command is present,
used to execute an arbitrary command from within the SDK
chroot environment. The environment variable MERSDKUBU is set
to 1 to allow SDK detection.
Options:
-u System user to link into SDK (not needed if using sudo)
-m Devices to bind mount from host: none, all (default)
root, home
-r The root of the SDK to use - normally derived from the
pathname of $0
-v Be verbose about what's happening
-V Print version
-h Show this help
Profile
Entering the SDK runs the user's normal .profile and any (SDK)
system profile entries. It will not execute the host's system
profile entries.
The environment variable MERSDKUBU is set to 1 to allow .profile
to detect the SDK.
## If the user has a ~/.mersdkubu.profile then it is sourced after the
normal .profile handling (this allows the common use case of
setting a profile to be handled).
Hooks
If the user specified has a .mersdkuburc in their $HOME, it will
be sourced to allow hook functions to be defined. Hooks are run
as root. No commands should be executed immediately.
These hooks are usually used to define symbolic links from any
/parentroot/data type filesystems into the SDK root to setup
system specific shared caches or filesystem layouts etc
EOF
return 0
}
## verbose if not doing an exec
inform() {
[[ $QUIET ]] && return
echo "$@"
}
if [[ $EUID -ne 0 ]]; then
exec sudo $0 "$@"
echo "$0 must be run as root and sudo failed; exiting"
exit 1
fi
if cmp -s /proc/$PPID/mountinfo /proc/self/mountinfo; then
# Propagation switch was introduced by util-linux-2.27, let's check here:
unshare --help | grep -F -q \
-- --propagation && UNSHARE_EXTRA_OPT="--propagation unchanged"
# Leave the propagation unchanged when launched within SDK, otherwise an
# attempt to alter it (even default behaviour) results in "Invalid argument"
exec unshare $UNSHARE_EXTRA_OPT -m -- "$0" "$@"
echo "$0 must be run in private namespace and unshare failed; exiting"
exit 1
fi
# Use the SUDO value if present
user=$SUDO_USER || true;
bind_mount_root="yes";
bind_mount_home="yes";
QUIET=yes
version=@VERSION@
while getopts "u:m:r:vhV" opt; do
case $opt in
u ) user=$OPTARG;;
m )
case $OPTARG in
all) ;;
home)
bind_mount_root="no";;
root)
bind_mount_home="no";;
none)
bind_mount_root="no";
bind_mount_home="no";;
*) echo "Only 'none', 'all' or 'home' are permitted for -m"
usage
exit 1;;
esac ;;
r ) uburoot=$OPTARG;;
c ) command=t;;
h|\? ) usage
exit 1;;
v ) QUIET= ;;
V ) echo $version; exit 0 ;;
: ) echo "Option -$OPTARG requires an argument." >&2
usage
exit 1;;
* ) usage
exit 1;;
esac
done
shift $(($OPTIND - 1))
if [[ -z "${uburoot}" ]] ; then
echo "You must specify the Ubuntu rootfs using the -r option"
exit 1
else
uburoot=$(readlink -f $uburoot)
fi
inform set root to $uburoot
if [[ ! -f ${uburoot}/etc/debian_version ]] ; then
echo "${uburoot} does not look like an Ubuntu rootfs"
echo "if you are sure it is, you may mark it by running"
echo "echo 'MerSDK' | sudo tee ${uburoot}/etc/debian_version"
exit 1
fi
sdkparent="$(df -P "$uburoot/" | tail -1 | awk '{print $NF}')"
if [ -z "$sdkparent" ] ; then
echo "Unable to determine mount point of filesystem containing \"$uburoot\""
exit 1
fi
if [[ -z $user ]] ; then
echo "$0 expects to be run as root using sudo"
echo "User could not be obtained from \$SUDO_USER, if running as root,"
echo "please use -u <user>"
echo
usage
exit 1
fi
# From now on, exit if variables not set
set -u
# Make sure normal users can use any dirs we make
umask 022
################################################################
# Mount
# In order to deal with varying status of adoption of changes to FHS among
# distributions a list of alternate paths is considered for binding.
mount_bind() {
maybe_symlinks="$*"
src=""
dsts=""
for dir in $maybe_symlinks; do
if [[ -d $dir ]]; then
src="$dir"
break
fi
done
if [[ -z "$src" ]]; then
echo "mount_bind $*: None of these exists on your host - please report this bug"
return
fi
for dir in $maybe_symlinks; do
if [[ -e ${uburoot}$dir && ! -L ${uburoot}$dir ]]; then
dsts="$dsts $dir"
fi
done
if [[ -z "$dsts" ]]; then
echo "mount_bind $*: No non-symlink target in SDK root - please report this bug"
return
fi
for dst in $dsts; do
mount --bind $src ${uburoot}$dst
done
}
prepare_mountpoints() {
# Make parent mountpoint not shared with parent namespace
mount --make-slave "$sdkparent/"
inform "Mounting system directories..."
mount_bind /proc
mount_bind /proc/sys/fs/binfmt_misc
mount_bind /sys
mount_bind /dev
mount_bind /dev/pts
mount_bind /dev/shm /run/shm
mount_bind /var/lib/dbus
mount_bind /var/run/dbus
if [[ $bind_mount_root == "yes" ]] ; then
inform "Mounting / as /parentroot"
mkdir -p ${uburoot}/parentroot
mount --rbind / ${uburoot}/parentroot/
fi
mkdir -p ${uburoot}/lib/modules/$(uname -r)
mount_bind /lib/modules/$(uname -r)
}
umount_spare() {
# for some reason these seem to escape the unshare -m
umount ${uburoot}/proc/sys/fs/binfmt_misc || :
umount ${uburoot}/dev/pts || :
umount ${uburoot}/dev/shm ${uburoot}/run/shm || :
umount ${uburoot}/var/run/dbus || :
umount ${uburoot}/sys || :
umount ${uburoot}/dev || :
umount ${uburoot}/proc || :
if [[ $bind_mount_home == yes ]] ; then
if mountpoint -q ${uburoot}/$HOMEDIR ; then
umount ${uburoot}/$HOMEDIR
fi
fi
}
prepare_user() {
# remove mer user if present
sed -i -e "/^mer:/d" ${uburoot}/etc/passwd
# Remove ${user} if present
sed -i -e "/^${user}:/d" ${uburoot}/etc/passwd
# Use getent to get ${user}'s record from /etc/passwd
# Use awk to make sure the shell is set to /bin/bash
getent passwd $user | awk 'BEGIN { FS = ":" } { OFS = ":"} { $7="/bin/bash"; print }'>> ${uburoot}/etc/passwd
group=$(getent passwd $user | cut -f4 -d:)
sed -i -e "/^[^:]*:[^:]*:${group}:/d" ${uburoot}/etc/group
getent group $group >> ${uburoot}/etc/group
HOMEDIR=$(getent passwd $user | cut -f6 -d:)
# sync passwd and shadow
pwconv --root ${uburoot}
install --owner $user --group $(id -gn $user) -d ${uburoot}${HOMEDIR}
if [[ $bind_mount_home == "yes" ]] ; then
inform "Mounting home directory: ${HOMEDIR}"
# For some reason, inside an SDK, we can't remount a bound $HOME
local proot=""
{ [[ -h /parentroot ]] || ! [[ -e /parentroot ]]; } || proot=/parentroot
inform "mount --rbind ${proot}${HOMEDIR} ${uburoot}${HOMEDIR}"
mount --rbind ${proot}${HOMEDIR} ${uburoot}${HOMEDIR}
fi
cat > ${uburoot}/etc/sudoers.d/$user <<EOF
$user ALL=NOPASSWD: ALL
# With newer sudo versions we need to disable pam_acct_mgmt since it
# does't work for our use case and there's no use for it in the ubuntu-chroot.
Defaults !pam_acct_mgmt
EOF
chmod 0440 ${uburoot}/etc/sudoers.d/$user
}
prepare_etc() {
# Symlink to parentroot to support dynamic resolv.conf on host
rm -f ${uburoot}/etc/resolv.conf
resolv=$(readlink -fn /etc/resolv.conf) # some systems use symlinks to /var/run/...
ln -s /parentroot/$resolv ${uburoot}/etc/resolv.conf
# Fixup old SDKs with broken /etc/mtab since this won't be fixed
# by any package updates
if [[ ! -L ${uburoot}/etc/mtab ]]; then
echo "The /etc/mtab file in the SDK is not a symbolic link - forcing it to link to /proc/self/mounts to fix https://bugs.merproject.org/show_bug.cgi?id=385"
rm -f ${uburoot}/etc/mtab
ln -s /proc/self/mounts ${uburoot}/etc/mtab
fi
}
################
setup_user_hooks(){
# Access any user hooks
[[ -e $HOMEDIR/.mersdkuburc ]] && . $HOMEDIR/.mersdkuburc
}
run_user_hook() {
hook=$1
[[ $(type -t $hook) == "function" ]] && {
inform "User hook $hook"
$hook
}
}
################################################################
do_it_all() {
retval=0
cwd=$(pwd)
prepare_mountpoints # host / and data and /proc and similar
prepare_user # in /etc/passwd
setup_user_hooks # (after prepare so HOMEDIR is known)
prepare_etc # resolv.conf and ssl certs
run_user_hook mount_sdk
run_user_hook enter_sdk
if grep --quiet \
--invert-match \
--word-regexp "wheezy\|jessie\|bullseye\|sid" \
"${uburoot}"/etc/debian_version ; then
# This is for ubuntu 12.04+ (arg quoting for sudo is different)
echo Unknown ubuntu version >&2
exit 1
fi
if [ $# -eq 0 ] ; then
set -- /usr/bin/env \
bash --init-file \
/parentroot/usr/share/ubu-chroot/mer-ubusdk-bash-setup -i
else
cat >&2 <<EOF
Warning: If you want to pass multiple shell commands use sh -c
EOF
fi
pty=
if setarch x86_64 chroot "${uburoot}" /bin/su -h |grep -q -- --pty ; then
pty=--pty
fi
setarch x86_64 chroot "${uburoot}" \
/usr/bin/env su ${pty} --shell=/bin/bash --login $user -- \
-c "$(cat <<EOF
[ -d "$cwd" ] && cd "$cwd"
export MERSDKUBU=1
exec $(printf -- "%q " "${@}")
EOF
)"
retval="$?"
inform exited
run_user_hook leave_sdk
umount_spare
exit $retval
}
# This allows us to update this script in place even whilst running.
do_it_all "$@"