OILS / regtest / aports / enter-bwrap.sh View on Github | oils.pub

134 lines, 61 significant
1#!/bin/sh
2#
3# Enter an Alpine rootfs with bwrap, not chroot.
4#
5# This is an ALTERNATIVE to 'enter-chroot'. It's not a "hook", like
6# regtest/enter-hook-{bwrap,chroot}
7
8set -e
9
10rootfs_dir=${1:-}
11if test -z "$rootfs_dir"; then
12 # $this_dir idiom
13 rootfs_dir=$(cd $(dirname "$0"); pwd)
14fi
15
16user=${2:-root}
17
18# abuild rootbld has --unshare-ipc, etc. but has OPTION for --unshare-net.
19# It doesn't use --unshare-all. Don't use that; specify everything explicitly
20bwrap_flags=${3:-}
21
22shift 3
23
24# Awk script that is nicer than:
25# getent passwd "$user"
26
27temp_prefix="/tmp/$$"
28
29uid_file=$temp_prefix.uid.txt
30gid_file=$temp_prefix.gid.txt
31home_file=$temp_prefix.home.txt
32shell_file=$temp_prefix.shell.txt
33
34awk -F : \
35 -v user=$user \
36 -v uid_file=$uid_file \
37 -v gid_file=$gid_file \
38 -v home_file=$home_file \
39 -v shell_file=$shell_file \
40 '
41 $1 == user {
42 #printf("FOUND User %s in the rootfs\n", user);
43 print $3 > uid_file
44 print $4 > gid_file
45 print $6 > home_file
46 print $7 > shell_file
47 found = 1
48 exit # jumps to the END block
49 }
50
51 END {
52 if (found == 0) {
53 printf("User %s not found in the rootfs\n", user);
54 exit 1
55 }
56 }
57 ' $rootfs_dir/etc/passwd
58
59# Note: there is a slurp operator in bash/ksh $(<file)
60uid=$(cat $uid_file)
61gid=$(cat $gid_file)
62user_home=$(cat $home_file)
63user_shell=$(cat $shell_file)
64
65# Clean up
66rm $temp_prefix*
67
68if false; then
69 echo uid=$uid
70 echo gid=$gid
71 echo home=$user_home
72 echo shell=$user_shell
73fi
74
75if true; then
76
77# This is a ROOTLESS alternative to the method in:
78# https://github.com/oils-for-unix/alpine-chroot-install/blob/master/alpine-chroot-install#L192
79#
80# $_sudo chroot . /usr/bin/env -i su -l "$user" \
81# sh -c ". /etc/profile; . /env.sh; cd '$oldpwd' 2>/dev/null; \"\$@\"" \
82# -- "${@:-sh}"
83#
84# - No sudo; bwrap is rootless
85# - No chroot; bwrap has --bind $rootfs_dir /
86# - No env -i; bwrap has --clearenv
87# - No su -l; we run sh -l
88# - this is not POSIX, but I think all shells we acre about support it (dash,
89# busybox ash, bash)
90# - No su $user, we get the uid with awk, and pass --uid $uid to bwrap
91# - No . /etc/profile - sh -l does that
92# - No env.sh, because we need a clean environment
93# - No cd, I think $sh -l reads that from $HOME
94#
95# Note that we set $USER $LOGNAME $SHELL $HOME
96#
97# This s simpler, but the problem is when we have TWO UIDs - root uid=0 and udu
98# uid=1000. TODO: Experiment with chown everything as a user.
99
100# Note: overflow{uid,gid} are necessary for nested bwrap? They are just a file
101# containing 65534 (nobody)
102
103bwrap \
104 $bwrap_flags \
105 --unshare-user \
106 --uid $uid \
107 --gid $gid \
108 --clearenv \
109 --setenv USER $user \
110 --setenv LOGNAME $user \
111 --setenv SHELL $user_shell \
112 --setenv HOME $user_home \
113 --bind "$rootfs_dir" / \
114 --proc /proc \
115 --bind /proc/sys/kernel/overflowuid /proc/sys/kernel/overflowuid \
116 --bind /proc/sys/kernel/overflowgid /proc/sys/kernel/overflowgid \
117 --dev /dev \
118 -- \
119 $user_shell -l -c ' "$@" ' dummy0 "${@:-sh}"
120
121else
122 # this requires root, because su requires root
123
124bwrap \
125 $bwrap_flags \
126 --bind "$rootfs_dir" / \
127 --proc /proc \
128 --bind /proc/sys/kernel/overflowuid /proc/sys/kernel/overflowuid \
129 --bind /proc/sys/kernel/overflowgid /proc/sys/kernel/overflowgid \
130 --dev /dev \
131 -- \
132 /usr/bin/env -i -- \
133 su -l "$user" -- -c '. /etc/profile; . /env.sh; "$@"' dummy0 "${@:-sh}"
134fi