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
43 binary_path
=`which $1`
45 echo "Unable to find $1 binary on the system"
49 dir_path
="${binary_path%/*}"
50 echo /{,usr
/}{,s
}bin |
grep $dir_path >/dev
/null
2>&1
52 echo "Binary $1 is located at $binary_path and will not be copied"
53 echo "($dir_path not supported)"
57 cp $binary_path $rootfs/$binary_path
59 echo "Failed to copy $binary_path to rootfs"
87 $rootfs/usr/share/udhcpc \
95 mkdir
-p $tree ||
return 1
96 chmod 755 $tree ||
return 1
98 pushd $rootfs/dev
> /dev
/null ||
return 1
100 # minimal devices needed for busybox
101 if [ $in_userns -eq 1 ]; then
102 for dev
in tty console tty0 tty1 ram0 null urandom
; do
103 echo "lxc.mount.entry = /dev/$dev dev/$dev none bind,optional,create=file 0 0" >> $path/config
106 mknod
-m 666 tty c
5 0 || res
=1
107 mknod
-m 666 console c
5 1 || res
=1
108 mknod
-m 666 tty0 c
4 0 || res
=1
109 mknod
-m 666 tty1 c
4 0 || res
=1
110 mknod
-m 666 tty5 c
4 0 || res
=1
111 mknod
-m 600 ram0 b
1 0 || res
=1
112 mknod
-m 666 null c
1 3 || res
=1
113 mknod
-m 666 zero c
1 5 || res
=1
114 mknod
-m 666 urandom c
1 9 || res
=1
120 cat <<EOF >> $rootfs/etc/passwd
121 root:x:0:0:root:/root:/bin/sh
124 cat <<EOF >> $rootfs/etc/group
129 cat <<EOF >> $rootfs/etc/init.d/rcS
137 chmod 744 $rootfs/etc
/init.d
/rcS ||
return 1
139 # launch rcS first then make a console available
140 # and propose a shell on the tty, the last one is
142 cat <<EOF >> $rootfs/etc/inittab
143 ::sysinit:/etc/init.d/rcS
144 tty1::respawn:/bin/getty -L tty1 115200 vt100
145 console::askfirst:/bin/sh
147 # writable and readable for other
148 chmod 644 $rootfs/etc
/inittab ||
return 1
150 cat <<EOF >> $rootfs/usr/share/udhcpc/default.script
154 ip addr flush dev \$interface
158 # flush all the routes
159 if [ -n "\$router" ]; then
160 ip route del default 2> /dev/null
164 if [ -n "\$broadcast" ]; then
165 broadcast="broadcast \$broadcast"
168 # add a new ip address
169 ip addr add \$ip/\$mask \$broadcast dev \$interface
171 if [ -n "\$router" ]; then
172 ip route add default via \$router dev \$interface
175 [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf
177 echo nameserver \$i >> /etc/resolv.conf
184 chmod 744 $rootfs/usr
/share
/udhcpc
/default.
script
191 # copy dropbear binary
192 copy_binary dropbear ||
return 1
194 # make symlinks to various ssh utilities
196 $rootfs/usr/bin/dbclient \
197 $rootfs/usr/bin/scp \
198 $rootfs/usr/bin/ssh \
199 $rootfs/usr/sbin/dropbearkey \
200 $rootfs/usr/sbin/dropbearconvert \
202 echo $utils |
xargs -n1 ln -s /usr
/sbin
/dropbear
204 # add necessary config files
205 mkdir
$rootfs/etc
/dropbear
206 dropbearkey
-t rsa
-f $rootfs/etc
/dropbear
/dropbear_rsa_host_key
> /dev
/null
2>&1
207 dropbearkey
-t dss
-f $rootfs/etc
/dropbear
/dropbear_dss_host_key
> /dev
/null
2>&1
209 echo "'dropbear' ssh utility installed"
216 # tools to be installed
222 client_optional_utils
="\
232 # new folders used by ssh
235 $rootfs/var/empty/sshd \
236 $rootfs/var/lib/empty/sshd \
237 $rootfs/var/run/sshd \
240 # create folder structure
242 if [ $?
-ne 0 ]; then
247 for bin
in $server_utils $client_utils; do
248 copy_binary
$bin ||
return 1
251 for bin
in $client_optional_utils; do
252 tool_path
=`which $bin` && copy_binary
$bin
256 cat <<EOF >> $rootfs/etc/passwd
257 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
260 cat <<EOF >> $rootfs/etc/group
264 # generate container keys
265 ssh-keygen
-t rsa
-N "" -f $rootfs/etc
/ssh
/ssh_host_rsa_key
>/dev
/null
2>&1
266 ssh-keygen
-t dsa
-N "" -f $rootfs/etc
/ssh
/ssh_host_dsa_key
>/dev
/null
2>&1
268 # by default setup root password with no password
269 cat <<EOF > $rootfs/etc/ssh/sshd_config
272 HostKey /etc/ssh/ssh_host_rsa_key
273 HostKey /etc/ssh/ssh_host_dsa_key
274 UsePrivilegeSeparation yes
275 KeyRegenerationInterval 3600
282 RSAAuthentication yes
283 PubkeyAuthentication yes
285 RhostsRSAAuthentication no
286 HostbasedAuthentication no
287 PermitEmptyPasswords yes
288 ChallengeResponseAuthentication no
291 echo "'OpenSSH' utility installed"
300 which busybox
>/dev
/null
2>&1
302 if [ $?
-ne 0 ]; then
303 echo "busybox executable is not accessible"
307 file -L $
(which busybox
) |
grep -q "statically linked"
308 if [ $?
-ne 0 ]; then
309 echo "warning : busybox is not statically linked."
310 echo "warning : The template script may not correctly"
311 echo "warning : setup the container environment."
314 # copy busybox in the rootfs
315 cp $
(which busybox
) $rootfs/bin
316 if [ $?
-ne 0 ]; then
317 echo "failed to copy busybox in the rootfs"
321 # symlink busybox for the commands it supports
322 # it would be nice to just use "chroot $rootfs busybox --install -s /bin"
323 # but that only works right in a chroot with busybox >= 1.19.0
324 pushd $rootfs/bin
> /dev
/null ||
return 1
325 .
/busybox
--help |
grep 'Currently defined functions:' -A300 | \
326 grep -v 'Currently defined functions:' |
tr , '\n' | \
327 xargs -n1 ln -s busybox
331 ln $rootfs/bin
/busybox
$rootfs/sbin
/init
333 # passwd exec must be setuid
334 chmod +s
$rootfs/bin
/passwd
335 touch $rootfs/etc
/shadow
337 # setting passwd for root
338 CHPASSWD_FILE
=$rootfs/root
/chpasswd.sh
340 cat <<EOF >$CHPASSWD_FILE
341 echo "setting root password to \"root\""
343 mount -n --bind /lib $rootfs/lib
344 if [ \$? -ne 0 ]; then
345 echo "Failed bind-mounting /lib at $rootfs/lib"
349 chroot $rootfs chpasswd <<EOFF 2>/dev/null
354 if [ \$? -ne 0 ]; then
355 echo "Failed to change root password"
363 lxc-unshare
-s MOUNT
-- /bin
/sh
< $CHPASSWD_FILE
375 grep -q "^lxc.rootfs" $path/config
2>/dev
/null ||
echo "lxc.rootfs = $rootfs" >> $path/config
376 cat <<EOF >> $path/config
377 lxc.haltsignal = SIGUSR1
378 lxc.rebootsignal = SIGTERM
382 lxc.cap.drop = sys_module mac_admin mac_override sys_time
384 # When using LXC with apparmor, uncomment the next line to run unconfined:
385 #lxc.aa_profile = unconfined
387 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
388 lxc.mount.entry = shm /dev/shm tmpfs defaults 0 0
397 for dir
in $libdirs; do
398 if [ -d "/$dir" ] && [ -d "$rootfs/$dir" ]; then
399 echo "lxc.mount.entry = /$dir $dir none ro,bind 0 0" >> $path/config
402 echo "lxc.mount.entry = /sys/kernel/security sys/kernel/security none ro,bind,optional 0 0" >>$path/config
409 if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then
410 chown
$LXC_MAPPED_UID $path/config
>/dev
/null
2>&1
411 chown
-R root
$path/rootfs
>/dev
/null
2>&1
414 if [ -n "$LXC_MAPPED_GID" ] && [ "$LXC_MAPPED_GID" != "-1" ]; then
415 chgrp
$LXC_MAPPED_GID $path/config
>/dev
/null
2>&1
416 chgrp
-R root
$path/rootfs
>/dev
/null
2>&1
423 $1 -h|--help -p|--path=<path> -s|--ssh={dropbear,openssh}
428 options
=$
(getopt
-o hp
:n
:s
: -l help,rootfs
:,path
:,name
:,mapped-uid
:,mapped-gid
:,ssh: -- "$@")
429 if [ $?
-ne 0 ]; then
433 eval set -- "$options"
438 -h|
--help) usage
$0 && exit 0;;
439 -p|
--path) path
=$2; shift 2;;
440 --rootfs) rootfs
=$2; shift 2;;
441 -n|
--name) name
=$2; shift 2;;
442 --mapped-uid) LXC_MAPPED_UID
=$2; shift 2;;
443 --mapped-gid) LXC_MAPPED_GID
=$2; shift 2;;
444 -s|
--ssh) SSH
=$2; shift 2;;
445 --) shift 1; break ;;
450 if [ "$(id -u)" != "0" ]; then
451 echo "This script should be run as 'root'"
455 if [ -z "$path" ]; then
456 echo "'path' parameter is required"
461 config
="$path/config"
462 if [ -z "$rootfs" ]; then
463 if grep -q '^lxc.rootfs' $config 2>/dev
/null
; then
464 rootfs
=$
(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
470 install_busybox
$rootfs $name
471 if [ $?
-ne 0 ]; then
472 echo "failed to install busybox's rootfs"
476 configure_busybox
$rootfs
477 if [ $?
-ne 0 ]; then
478 echo "failed to configure busybox template"
482 copy_configuration
$path $rootfs $name
483 if [ $?
-ne 0 ]; then
484 echo "failed to write configuration file"
489 if [ $?
-ne 0 ]; then
490 echo "failed to remap files to user"
494 if [ -n "$SSH" ]; then
498 if [ $?
-ne 0 ]; then
499 echo "Unable to install 'dropbear' ssh utility"
504 if [ $?
-ne 0 ]; then
505 echo "Unable to install 'OpenSSH' utility"
509 echo "$SSH: unrecognized ssh utility"
513 which dropbear
>/dev
/null
2>&1
514 if [ $?
-eq 0 ]; then