4 # lxc: linux Container library
7 # Daniel Lezcano <daniel.lezcano@free.fr>
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 # Make sure the usual locations are in PATH
28 export PATH
=$PATH:/usr
/sbin
:/usr
/bin
:/sbin
:/bin
31 [ -e /proc
/self
/uid_map
] ||
{ echo no
; return; }
32 [ "$(wc -l /proc/self/uid_map | awk '{ print $1 }')" -eq 1 ] ||
{ echo yes; return; }
33 line
=$
(awk '{ print $1 " " $2 " " $3 }' /proc
/self
/uid_map
)
34 [ "$line" = "0 0 4294967295" ] && { echo no
; return; }
39 [ $
(am_in_userns
) = "yes" ] && in_userns
=1
62 $rootfs/usr/share/udhcpc \
70 mkdir
-p $tree ||
return 1
71 chmod 755 $tree ||
return 1
73 pushd $rootfs/dev
> /dev
/null ||
return 1
75 # minimal devices needed for busybox
76 if [ $in_userns -eq 1 ]; then
77 for dev
in tty console tty0 tty1 ram0 null urandom
; do
78 echo "lxc.mount.entry = /dev/$dev dev/$dev none bind,optional,create=file 0 0" >> $path/config
81 mknod
-m 666 tty c
5 0 || res
=1
82 mknod
-m 666 console c
5 1 || res
=1
83 mknod
-m 666 tty0 c
4 0 || res
=1
84 mknod
-m 666 tty1 c
4 0 || res
=1
85 mknod
-m 666 tty5 c
4 0 || res
=1
86 mknod
-m 600 ram0 b
1 0 || res
=1
87 mknod
-m 666 null c
1 3 || res
=1
88 mknod
-m 666 zero c
1 5 || res
=1
89 mknod
-m 666 urandom c
1 9 || res
=1
95 cat <<EOF >> $rootfs/etc/passwd
96 root:x:0:0:root:/root:/bin/sh
99 cat <<EOF >> $rootfs/etc/group
104 cat <<EOF >> $rootfs/etc/init.d/rcS
112 chmod 744 $rootfs/etc
/init.d
/rcS ||
return 1
114 # launch rcS first then make a console available
115 # and propose a shell on the tty, the last one is
117 cat <<EOF >> $rootfs/etc/inittab
118 ::sysinit:/etc/init.d/rcS
119 tty1::respawn:/bin/getty -L tty1 115200 vt100
120 console::askfirst:/bin/sh
122 # writable and readable for other
123 chmod 644 $rootfs/etc
/inittab ||
return 1
125 cat <<EOF >> $rootfs/usr/share/udhcpc/default.script
129 ip addr flush dev \$interface
133 # flush all the routes
134 if [ -n "\$router" ]; then
135 ip route del default 2> /dev/null
139 if [ -n "\$broadcast" ]; then
140 broadcast="broadcast \$broadcast"
143 # add a new ip address
144 ip addr add \$ip/\$mask \$broadcast dev \$interface
146 if [ -n "\$router" ]; then
147 ip route add default via \$router dev \$interface
150 [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf
152 echo nameserver \$i >> /etc/resolv.conf
159 chmod 744 $rootfs/usr
/share
/udhcpc
/default.
script
166 # copy dropbear binary
167 cp $
(which dropbear
) $rootfs/usr
/sbin
168 if [ $?
-ne 0 ]; then
169 echo "Failed to copy dropbear in the rootfs"
173 # make symlinks to various ssh utilities
175 $rootfs/usr/bin/dbclient \
176 $rootfs/usr/bin/scp \
177 $rootfs/usr/bin/ssh \
178 $rootfs/usr/sbin/dropbearkey \
179 $rootfs/usr/sbin/dropbearconvert \
181 echo $utils |
xargs -n1 ln -s /usr
/sbin
/dropbear
183 # add necessary config files
184 mkdir
$rootfs/etc
/dropbear
185 dropbearkey
-t rsa
-f $rootfs/etc
/dropbear
/dropbear_rsa_host_key
> /dev
/null
2>&1
186 dropbearkey
-t dss
-f $rootfs/etc
/dropbear
/dropbear_dss_host_key
> /dev
/null
2>&1
188 echo "'dropbear' ssh utility installed"
195 # tools to be installed
201 client_optional_utils
="\
211 # new folders used by ssh
214 $rootfs/var/empty/sshd \
215 $rootfs/var/lib/empty/sshd \
216 $rootfs/var/run/sshd \
219 # create folder structure
221 if [ $?
-ne 0 ]; then
226 for bin
in $server_utils $client_utils; do
227 tool_path
=`which $bin`
228 cp $tool_path $rootfs/$tool_path
229 if [ $?
-ne 0 ]; then
230 echo "Unable to copy $tool_path in the rootfs"
235 for bin
in $client_optional_utils; do
236 tool_path
=`which $bin`
237 if [ $?
-eq 0 ]; then
238 cp $tool_path $rootfs/$tool_path
243 cat <<EOF >> $rootfs/etc/passwd
244 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
247 cat <<EOF >> $rootfs/etc/group
251 # generate container keys
252 ssh-keygen
-t rsa
-N "" -f $rootfs/etc
/ssh
/ssh_host_rsa_key
>/dev
/null
2>&1
253 ssh-keygen
-t dsa
-N "" -f $rootfs/etc
/ssh
/ssh_host_dsa_key
>/dev
/null
2>&1
255 # by default setup root password with no password
256 cat <<EOF > $rootfs/etc/ssh/sshd_config
259 HostKey /etc/ssh/ssh_host_rsa_key
260 HostKey /etc/ssh/ssh_host_dsa_key
261 UsePrivilegeSeparation yes
262 KeyRegenerationInterval 3600
269 RSAAuthentication yes
270 PubkeyAuthentication yes
272 RhostsRSAAuthentication no
273 HostbasedAuthentication no
274 PermitEmptyPasswords yes
275 ChallengeResponseAuthentication no
278 echo "'OpenSSH' utility installed"
287 which busybox
>/dev
/null
2>&1
289 if [ $?
-ne 0 ]; then
290 echo "busybox executable is not accessible"
294 file -L $
(which busybox
) |
grep -q "statically linked"
295 if [ $?
-ne 0 ]; then
296 echo "warning : busybox is not statically linked."
297 echo "warning : The template script may not correctly"
298 echo "warning : setup the container environment."
301 # copy busybox in the rootfs
302 cp $
(which busybox
) $rootfs/bin
303 if [ $?
-ne 0 ]; then
304 echo "failed to copy busybox in the rootfs"
308 # symlink busybox for the commands it supports
309 # it would be nice to just use "chroot $rootfs busybox --install -s /bin"
310 # but that only works right in a chroot with busybox >= 1.19.0
311 pushd $rootfs/bin
> /dev
/null ||
return 1
312 .
/busybox
--help |
grep 'Currently defined functions:' -A300 | \
313 grep -v 'Currently defined functions:' |
tr , '\n' | \
314 xargs -n1 ln -s busybox
318 ln $rootfs/bin
/busybox
$rootfs/sbin
/init
320 # passwd exec must be setuid
321 chmod +s
$rootfs/bin
/passwd
322 touch $rootfs/etc
/shadow
324 # setting passwd for root
325 CHPASSWD_FILE
=$rootfs/root
/chpasswd.sh
327 cat <<EOF >$CHPASSWD_FILE
328 echo "setting root password to \"root\""
330 mount -n --bind /lib $rootfs/lib
331 if [ \$? -ne 0 ]; then
332 echo "Failed bind-mounting /lib at $rootfs/lib"
336 chroot $rootfs chpasswd <<EOFF 2>/dev/null
341 if [ \$? -ne 0 ]; then
342 echo "Failed to change root password"
350 lxc-unshare
-s MOUNT
-- /bin
/sh
< $CHPASSWD_FILE
362 grep -q "^lxc.rootfs" $path/config
2>/dev
/null ||
echo "lxc.rootfs = $rootfs" >> $path/config
363 cat <<EOF >> $path/config
364 lxc.haltsignal = SIGUSR1
365 lxc.rebootsignal = SIGTERM
369 lxc.cap.drop = sys_module mac_admin mac_override sys_time
371 # When using LXC with apparmor, uncomment the next line to run unconfined:
372 #lxc.aa_profile = unconfined
374 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
375 lxc.mount.entry = shm /dev/shm tmpfs defaults 0 0
384 for dir
in $libdirs; do
385 if [ -d "/$dir" ] && [ -d "$rootfs/$dir" ]; then
386 echo "lxc.mount.entry = /$dir $dir none ro,bind 0 0" >> $path/config
389 echo "lxc.mount.entry = /sys/kernel/security sys/kernel/security none ro,bind,optional 0 0" >>$path/config
396 if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then
397 chown
$LXC_MAPPED_UID $path/config
>/dev
/null
2>&1
398 chown
-R root
$path/rootfs
>/dev
/null
2>&1
401 if [ -n "$LXC_MAPPED_GID" ] && [ "$LXC_MAPPED_GID" != "-1" ]; then
402 chgrp
$LXC_MAPPED_GID $path/config
>/dev
/null
2>&1
403 chgrp
-R root
$path/rootfs
>/dev
/null
2>&1
410 $1 -h|--help -p|--path=<path> -s|--ssh={dropbear,openssh}
415 options
=$
(getopt
-o hp
:n
:s
: -l help,rootfs
:,path
:,name
:,mapped-uid
:,mapped-gid
:,ssh: -- "$@")
416 if [ $?
-ne 0 ]; then
420 eval set -- "$options"
425 -h|
--help) usage
$0 && exit 0;;
426 -p|
--path) path
=$2; shift 2;;
427 --rootfs) rootfs
=$2; shift 2;;
428 -n|
--name) name
=$2; shift 2;;
429 --mapped-uid) LXC_MAPPED_UID
=$2; shift 2;;
430 --mapped-gid) LXC_MAPPED_GID
=$2; shift 2;;
431 -s|
--ssh) SSH
=$2; shift 2;;
432 --) shift 1; break ;;
437 if [ "$(id -u)" != "0" ]; then
438 echo "This script should be run as 'root'"
442 if [ -z "$path" ]; then
443 echo "'path' parameter is required"
448 config
="$path/config"
449 if [ -z "$rootfs" ]; then
450 if grep -q '^lxc.rootfs' $config 2>/dev
/null
; then
451 rootfs
=$
(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
457 install_busybox
$rootfs $name
458 if [ $?
-ne 0 ]; then
459 echo "failed to install busybox's rootfs"
463 configure_busybox
$rootfs
464 if [ $?
-ne 0 ]; then
465 echo "failed to configure busybox template"
469 copy_configuration
$path $rootfs $name
470 if [ $?
-ne 0 ]; then
471 echo "failed to write configuration file"
476 if [ $?
-ne 0 ]; then
477 echo "failed to remap files to user"
481 if [ -n "$SSH" ]; then
485 if [ $?
-ne 0 ]; then
486 echo "Unable to install 'dropbear' ssh utility"
491 if [ $?
-ne 0 ]; then
492 echo "Unable to install 'OpenSSH' utility"
496 echo "$SSH: unrecognized ssh utility"
500 which dropbear
>/dev
/null
2>&1
501 if [ $?
-eq 0 ]; then