#!/bin/bash # # lxc: linux Container library # Authors: # Daniel Lezcano # Updated to work with LXC 4.0.x by Matthew Chamley # Template for slackware by Matteo Bernardini # some parts are taken from the debian one (used as model) # 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 cache=${cache:-/var/cache/lxc/slackware} # Use the primary Slackware site by default, but please consider changing # this to a closer mirror site. MIRROR=${MIRROR:-https://mirror.riscyslack.org/RiscySlack} if [ -z "$arch" ]; then case "$( uname -m )" in i?86) arch=i486 ;; arm*) arch=arm ;; ppc64le) arch=powerpc64le ;; riscv64) arch=riscv64 ;; *) arch=$( uname -m ) ;; esac fi configure_slackware() { rootfs=$1 hostname=$2 echo "Configuring..." ; echo # The next part contains excerpts taken from SeTconfig (written by # Patrick Volkerding) from the slackware setup disk. # But before pasting them just set a variable to use them as they are T_PX=$rootfs ( cd $T_PX ; chmod 755 ./ ) ( cd $T_PX ; chmod 755 ./var ) if [ -d $T_PX/usr/src/linux ]; then chmod 755 $T_PX/usr/src/linux fi if [ ! -d $T_PX/proc ]; then mkdir $T_PX/proc chown root.root $T_PX/proc fi if [ ! -d $T_PX/sys ]; then mkdir $T_PX/sys chown root.root $T_PX/sys fi chmod 1777 $T_PX/tmp if [ ! -d $T_PX/var/spool/mail ]; then mkdir -p $T_PX/var/spool/mail chmod 755 $T_PX/var/spool chown root.mail $T_PX/var/spool/mail chmod 1777 $T_PX/var/spool/mail fi echo "#!/bin/sh" > $T_PX/etc/rc.d/rc.keymap echo "# Load the keyboard map. More maps are in /usr/share/kbd/keymaps." \ >> $T_PX/etc/rc.d/rc.keymap echo "if [ -x /usr/bin/loadkeys ]; then" >> $T_PX/etc/rc.d/rc.keymap echo " /usr/bin/loadkeys us" >> $T_PX/etc/rc.d/rc.keymap echo "fi" >> $T_PX/etc/rc.d/rc.keymap chmod 755 $T_PX/etc/rc.d/rc.keymap # Network configuration is left to the user, that have to edit # /etc/rc.d/rc.inet1.conf and /etc/resolv.conf of the container # just set the hostname cat < $rootfs/etc/HOSTNAME $hostname.example.net EOF cp $rootfs/etc/HOSTNAME $rootfs/etc/hostname # make needed devices, from Chris Willing's MAKEDEV.sh # http://www.vislab.uq.edu.au/howto/lxc/MAKEDEV.sh DEV=$rootfs/dev mkdir -p ${DEV} # Remove any existing "devices" first, as these might be files # created by package install scripts: for clear_device in ${DEV}/null ${DEV}/zero ${DEV}/random ${DEV}/urandom \ ${DEV}/tty ${DEV}/console ${DEV}/tty0 ${DEV}/tty1 ${DEV}/tty2 ${DEV}/tty3 \ ${DEV}/tty4 ${DEV}/tty5 ${DEV}/full ${DEV}/initctl ${DEV}/loop0 \ ${DEV}/loop1 ; do rm -f $clear_device done # Create initial set of devices: mknod -m 666 ${DEV}/null c 1 3 mknod -m 666 ${DEV}/zero c 1 5 mknod -m 666 ${DEV}/random c 1 8 mknod -m 666 ${DEV}/urandom c 1 9 mkdir -m 755 ${DEV}/pts mkdir -m 1777 ${DEV}/shm mknod -m 666 ${DEV}/tty c 5 0 mknod -m 600 ${DEV}/console c 5 1 mknod -m 666 ${DEV}/tty0 c 4 0 mknod -m 666 ${DEV}/tty1 c 4 1 mknod -m 666 ${DEV}/tty2 c 4 2 mknod -m 666 ${DEV}/tty3 c 4 3 mknod -m 666 ${DEV}/tty4 c 4 4 mknod -m 666 ${DEV}/tty5 c 4 5 mknod -m 666 ${DEV}/full c 1 7 mknod -m 600 ${DEV}/initctl p mknod -m 660 ${DEV}/loop0 b 7 0 mknod -m 660 ${DEV}/loop1 b 7 1 ln -s pts/ptmx ${DEV}/ptmx ln -s /proc/self/fd ${DEV}/fd echo "Adding an etc/fstab that must be modified later with the" echo "full path of the container's rootfs if you decide to move it." cat >$rootfs/etc/fstab <> $rootfs/etc/rc.d/rc.local # reduce the number of local consoles: two should be enough sed -i '/^c3\|^c4\|^c5\|^c6/s/^/# /' $rootfs/etc/inittab # In a container, use shutdown for powerfail conditions. LXC sends the SIGPWR # signal to init to shut down the container with lxc-stop and without this the # container will be force stopped after a one minute timeout. sed -i "s,pf::powerfail:/sbin/genpowerfail start,pf::powerfail:/sbin/shutdown -h now,g" $rootfs/etc/inittab sed -i "s,pg::powerokwait:/sbin/genpowerfail stop,pg::powerokwait:/sbin/shutdown -c,g" $rootfs/etc/inittab # create the library symlinks chroot $rootfs ldconfig # set a default combination for the luggage echo "root:root" | chroot $rootfs chpasswd 2> /dev/null echo "Root default password is 'root', please change it!" # borrow the time configuration from the local machine cp -a /etc/localtime $rootfs/etc/localtime return 0 } copy_slackware() { rootfs=$1 # make a local copy of the installed filesystem echo -n "Copying rootfs to $rootfs..." mkdir -p $rootfs cp -a $cache/rootfs-$release-$arch/* $rootfs/ || exit 1 # fix fstab with the actual path sed -i "s|$cache/rootfs-$release-$arch|$rootfs|" $rootfs/etc/fstab return 0 } install_slackware() { rootfs=$1 mkdir -p /var/lock/subsys/ ( flock -n -x 200 if [ $? -ne 0 ]; then echo "Cache repository is busy." return 1 fi if [ "$arch" == "x86_64" ]; then PKGMAIN=slackware64 elif [ "$arch" == "powerpc64le" ]; then PKGMAIN=slackware64 elif [ "$arch" == "riscv64" ]; then PKGMAIN=slackware64 elif [ "$arch" == "arm" ]; then PKGMAIN=slackwarearm else PKGMAIN=slackware fi export CONF=$cache/slackpkg-conf export ROOT=$cache/rootfs-$release-$arch mkdir -p $cache/cache-$release-$arch $cache/rootfs-$release-$arch \ $cache/slackpkg-$release-$arch $CONF/templates echo "$MIRROR/$PKGMAIN-$release/" > $CONF/mirrors touch $CONF/blacklist cat < $CONF/slackpkg.conf # v15.0 ARCH=$arch TEMP=$cache/cache-$release-$arch WORKDIR=$cache/slackpkg-$release-$arch WGETFLAGS="--passive-ftp" DELALL=off CHECKMD5=on CHECKGPG=on CHECKSIZE=off PRIORITY=( patches %PKGMAIN extra pasture testing ) POSTINST=on ONLY_NEW_DOTNEW=off ORIG_BACKUPS=on ONOFF=on DOWNLOAD_ALL=on DIALOG=off BATCH=on DEFAULT_ANSWER=y USE_INCLUDES=on SPINNING=off DIALOG_MAXARGS=139000 EOF # thanks to Vincent Batts for this list of packages # (that I modified a little :P) # http://connie.slackware.com/~vbatts/minimal/ cat < $CONF/templates/minimal-lxc.template aaa_base aaa_elflibs aaa_glibc-solibs aaa_libraries aaa_terminfo bash bin bridge-utils bzip2 coreutils cracklib cyrus-sasl db48 dbus dcron dhcpcd dialog diffutils e2fsprogs elfutils elogind elvis etc eudev findutils gawk gnupg gnutls grep gzip hostname iproute2 iptables iputils kmod less libcap-ng libffi libmnl libnl3 libpcap libpwquality libtasn1 libtirpc libunistring logrotate mpfr net-tools nettle network-scripts ncurses pam openssh openssl-solibs p11-kit pkgtools procps-ng sed shadow sharutils slackpkg sysklogd sysvinit sysvinit-functions sysvinit-scripts tar util-linux wget which xz EOF TEMPLATE=${TEMPLATE:-minimal-lxc} if [ ! "$TEMPLATE" = "minimal-lxc" ]; then if [ -f /etc/slackpkg/templates/$TEMPLATE.template ]; then cat /etc/slackpkg/templates/$TEMPLATE.template \ > $CONF/templates/$TEMPLATE.template else TEMPLATE="minimal-lxc" fi fi # clean previous installs rm -fR $ROOT/* slackpkg -default_answer=n update slackpkg install-template $TEMPLATE # add a slackpkg default mirror echo "$MIRROR/$PKGMAIN-$release/" >> $ROOT/etc/slackpkg/mirrors # blacklist the devs package (we have to use our premade devices). # do the same with the kernel packages (we use the host's one), # but leave available headers and sources echo "devs" >> $ROOT/etc/slackpkg/blacklist sed -i \ -e "s|^#kernel-|kernel-|" \ -e "s|^kernel-headers|#kernel-headers|" \ -e "s|^kernel-source|#kernel-source|" \ $ROOT/etc/slackpkg/blacklist return 0 ) 200>/var/lock/subsys/lxc return $? } copy_configuration() { path=$1 rootfs=$2 name=$3 cat <> $path/config # Adding a . for LXC 4.0.x lxc.uts.name = $name # Adding .fstab for LXC 4.0.x lxc.mount.fstab = $rootfs/etc/fstab # Added .max and .path for LXC 4.0.x lxc.tty.max = 4 lxc.pty.max = 1024 lxc.rootfs.path = $rootfs lxc.cgroup.devices.deny = a # /dev/null and zero lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm # consoles lxc.cgroup.devices.allow = c 5:1 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 4:0 rwm lxc.cgroup.devices.allow = c 4:1 rwm # /dev/{,u}random lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 1:8 rwm lxc.cgroup.devices.allow = c 136:* rwm lxc.cgroup.devices.allow = c 5:2 rwm # rtc lxc.cgroup.devices.allow = c 254:0 rwm # we don't trust even the root user in the container, better safe than sorry. # comment out only if you know what you're doing. lxc.cap.drop = sys_module mknod mac_override mac_admin sys_time setfcap setpcap # you can try also this alternative to the line above, whatever suits you better. # lxc.cap.drop=sys_admin EOF if [ $? -ne 0 ]; then echo "Failed to add configuration." return 1 fi return 0 } clean() { if [ ! -e $cache ]; then exit 0 fi # lock, so we won't purge while someone is creating a repository ( flock -n -x 200 if [ $? != 0 ]; then echo "Cache repository is busy." exit 1 fi echo -n "Purging the download cache..." rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 exit 0 ) 200>/var/lock/subsys/lxc } usage() { cat < --clean EOF return 0 } options=$(getopt -o hp:n:a:r:c -l help,rootfs:,path:,name:,arch:,release:,clean -- "$@") 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;; --rootfs) rootfs=$2; shift 2;; -a|--arch) arch=$2; shift 2;; -r|--release) release=$2; shift 2;; -n|--name) name=$2; shift 2;; -c|--clean) clean=$2; shift 2;; --) shift 1; break ;; *) break ;; esac done if [ ! -z "$clean" -a -z "$path" ]; then clean || exit 1 exit 0 fi type installpkg if [ $? -ne 0 ]; then echo "'installpkg' command is missing." exit 1 fi type slackpkg if [ $? -ne 0 ]; then echo "'slackpkg' command is missing." exit 1 fi if [ -z "$path" ]; then echo "'path' parameter is required." exit 1 fi if [ "$(id -u)" != "0" ]; then echo "This script should be run as 'root'." exit 1 fi # If no release version was specified, use current release=${release:-current} if [ -z "$name" ]; then # no name given? set a default one name=slackwarecontainer fi # detect rootfs config="$path/config" if [ -z "$rootfs" ]; then if grep -q '^lxc.rootfs' $config 2>/dev/null ; then rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config) else rootfs=$path/rootfs fi fi echo set -e install_slackware $rootfs if [ $? -ne 0 ]; then echo "Failed to install slackware." exit 1 fi echo configure_slackware $cache/rootfs-$release-$arch $name if [ $? -ne 0 ]; then echo "Failed to configure slackware for a container." exit 1 fi echo rootfs=$path/rootfs copy_slackware $rootfs if [ $? -ne 0 ]; then echo "Failed to copy rootfs." exit 1 fi echo copy_configuration $path $rootfs $name if [ $? -ne 0 ]; then echo "Failed to write configuration file." exit 1 fi if [ ! -z $clean ]; then clean || exit 1 exit 0 fi