#!/bin/bash # # lxc: linux Container library # Authors: # Daniel Lezcano # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA install_busybox() { rootfs=$1 name=$2 res=0 tree="\ $rootfs/selinux \ $rootfs/dev \ $rootfs/home \ $rootfs/root \ $rootfs/etc \ $rootfs/etc/init.d \ $rootfs/bin \ $rootfs/sbin \ $rootfs/proc \ $rootfs/mnt \ $rootfs/tmp \ $rootfs/var/log \ $rootfs/usr/share/udhcpc \ $rootfs/dev/pts \ $rootfs/dev/shm \ $rootfs/lib \ $rootfs/usr/lib \ $rootfs/lib64 \ $rootfs/usr/lib64" mkdir -p $tree || return 1 chmod 755 $tree || return 1 pushd $rootfs/dev > /dev/null || return 1 # minimal devices needed for busybox mknod tty c 5 0 || res=1 mknod console c 5 1 || res=1 chmod 666 tty console || res=1 mknod tty0 c 4 0 || res=1 mknod tty1 c 4 0 || res=1 mknod tty5 c 4 0 || res=1 chmod 666 tty0 || res=1 mknod ram0 b 1 0 || res=1 chmod 600 ram0 || res=1 mknod null c 1 3 || res=1 chmod 666 null || res=1 popd > /dev/null # root user defined cat <> $rootfs/etc/passwd root:x:0:0:root:/root:/bin/sh EOF cat <> $rootfs/etc/group root:x:0:root EOF # mount everything cat <> $rootfs/etc/init.d/rcS #!/bin/sh /bin/syslogd /bin/mount -a /bin/udhcpc EOF # executable chmod 744 $rootfs/etc/init.d/rcS || return 1 # mount points cat <> $rootfs/etc/fstab proc /proc proc defaults 0 0 shm /dev/shm tmpfs defaults 0 0 EOF # writable and readable for other chmod 644 $rootfs/etc/fstab || return 1 # launch rcS first then make a console available # and propose a shell on the tty, the last one is # not needed cat <> $rootfs/etc/inittab ::sysinit:/etc/init.d/rcS tty1::respawn:/bin/getty -L tty1 115200 vt100 console::askfirst:/bin/sh EOF # writable and readable for other chmod 644 $rootfs/etc/inittab || return 1 cat <> $rootfs/usr/share/udhcpc/default.script #!/bin/sh case "\$1" in deconfig) ip addr flush dev \$interface ;; renew|bound) # flush all the routes if [ -n "\$router" ]; then ip route del default 2> /dev/null fi # check broadcast if [ -n "\$broadcast" ]; then broadcast="broadcast \$broadcast" fi # add a new ip address ip addr add \$ip/\$mask \$broadcast dev \$interface if [ -n "\$router" ]; then ip route add default via \$router dev \$interface fi [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf for i in \$dns ; do echo nameserver \$i >> /etc/resolv.conf done ;; esac exit 0 EOF chmod 744 $rootfs/usr/share/udhcpc/default.script return $res } configure_busybox() { rootfs=$1 functions="\ [ [[ addgroup adduser adjtimex ar arp arping ash awk basename \ brctl bunzip2 bzcat bzip2 cal cat catv chattr chgrp chmod \ chown chpasswd chpst chroot chrt chvt cksum clear cmp comm \ cp cpio crond crontab cryptpw cut date dc dd deallocvt \ delgroup deluser df dhcprelay diff dirname dmesg dnsd dos2unix \ du dumpkmap dumpleases echo ed egrep eject env envdir envuidgid \ ether-wake expand expr fakeidentd false fbset fdformat fdisk \ fetchmail fgrep find findfs fold free freeramdisk fsck \ fsck.minix ftpget ftpput fuser getopt getty grep gunzip gzip \ halt hdparm head hexdump hostid hostname httpd hwclock id \ ifconfig ifdown ifenslave ifup inetd init insmod install ip \ ipaddr ipcalc ipcrm ipcs iplink iproute iprule iptunnel \ kbd_mode kill killall killall5 klogd last length less linux32 \ linux64 linuxrc ln loadfont loadkmap logger login logname \ logread losetup lpd lpq lpr ls lsattr lsmod lzmacat makedevs \ md5sum mdev mesg microcom mkdir mkfifo mkfs.minix mknod mkswap \ mktemp modprobe more mount mountpoint msh mt mv nameif nc \ netstat nice nmeter nohup nslookup od openvt passwd patch \ pgrep pidof ping ping6 pipe_progress pivot_root pkill poweroff \ printenv printf ps pscan pwd raidautorun rdate readahead \ readlink readprofile realpath reboot renice reset resize rm \ rmdir rmmod route rpm rpm2cpio run-parts runlevel runsv \ runsvdir rx script sed sendmail seq setarch setconsole \ setkeycodes setlogcons setsid setuidgid sh sha1sum slattach \ sleep softlimit sort split start-stop-daemon stat strings \ stty su sulogin sum sv svlogd swapoff swapon switch_root \ sync sysctl syslogd tac tail tar taskset tcpsvd tee telnet \ telnetd test tftp tftpd time top touch tr traceroute \ true tty ttysize udhcpc udhcpd udpsvd umount uname uncompress \ unexpand uniq unix2dos unlzma unzip uptime usleep uudecode \ uuencode vconfig vi vlock watch watchdog wc wget which \ who whoami xargs yes zcat zcip" type busybox >/dev/null if [ $? -ne 0 ]; then echo "busybox executable is not accessible" return 1 fi file $(which busybox) | grep -q "statically linked" if [ $? -ne 0 ]; then echo "warning : busybox is not statically linked." echo "warning : The template script may not correctly" echo "warning : setup the container environment." fi # copy busybox in the rootfs cp $(which busybox) $rootfs/bin if [ $? -ne 0 ]; then echo "failed to copy busybox in the rootfs" return 1 fi # do hardlink to busybox for the different commands for i in $functions; do ln $rootfs/bin/busybox $rootfs/bin/$i; done # relink /sbin/init ln $rootfs/bin/busybox $rootfs/sbin/init # passwd exec must be setuid chmod +s $rootfs/bin/passwd touch $rootfs/etc/shadow chroot $rootfs /bin/passwd -d root echo "No password for 'root', please change !" return 0 } copy_configuration() { path=$1 rootfs=$2 name=$3 cat <> $path/config lxc.utsname = $name lxc.tty = 1 lxc.pts = 1 lxc.rootfs = $rootfs # uncomment the next line to run the container unconfined: #lxc.aa_profile = unconfined EOF if [ -d "$rootfs/lib" ]; then cat <> $path/config lxc.mount.entry=/lib $rootfs/lib none ro,bind 0 0 lxc.mount.entry=/usr/lib $rootfs/usr/lib none ro,bind 0 0 EOF fi if [ -d "/lib64" ] && [ -d "$rootfs/lib64" ]; then cat <> $path/config lxc.mount.entry=/lib64 $rootfs/lib64 none ro,bind 0 0 EOF fi if [ -d "/usr/lib64" ] && [ -d "$rootfs/usr/lib64" ]; then cat <> $path/config lxc.mount.entry=/usr/lib64 $rootfs/usr/lib64 none ro,bind 0 0 EOF fi } usage() { cat < EOF return 0 } options=$(getopt -o hp:n: -l help,path:,name: -- "$@") if [ $? -ne 0 ]; then usage $(basename $0) exit 1 fi eval set -- "$options" while true do case "$1" in -h|--help) usage $0 && exit 0;; -p|--path) path=$2; shift 2;; -n|--name) name=$2; shift 2;; --) shift 1; break ;; *) break ;; esac done if [ "$(id -u)" != "0" ]; then echo "This script should be run as 'root'" exit 1 fi if [ -z "$path" ]; then echo "'path' parameter is required" exit 1 fi rootfs=$path/rootfs install_busybox $rootfs $name if [ $? -ne 0 ]; then echo "failed to install busybox's rootfs" exit 1 fi configure_busybox $rootfs if [ $? -ne 0 ]; then echo "failed to configure busybox template" exit 1 fi copy_configuration $path $rootfs $name if [ $? -ne 0 ]; then echo "failed to write configuration file" exit 1 fi