# HG changeset patch # User Christopher Rogers # Date 1363194475 0 # Node ID 29b33964d9739ccf561517713db1bce70f787ec7 # Parent 0b68eab7409c2d55351be4f78a43ff6bc99d5a53 initramfs: Add new linux-live scripts support. diff -r 0b68eab7409c -r 29b33964d973 initramfs/init --- a/initramfs/init Thu Jul 19 12:14:30 2012 +0000 +++ b/initramfs/init Wed Mar 13 17:07:55 2013 +0000 @@ -1,216 +1,76 @@ #!/bin/sh +# Initial script for Linux Live Kit +# Author: Tomas M -success() -{ - cat > /run/init - [ -d /proc/sys ] && umount /proc - echo -e "\\033[70G[ \\033[1;32mOK\\033[0;39m ]" - exit -} +export PATH=.:/:/usr/sbin:/usr/bin:/sbin:/bin -launch_init() -{ - mount --move /run /mnt/run - success < /dev/null; then - cryptsetup luksOpen $root $dmlabel - else - read -s -t 60 -p "Pass phrase : " passphrase - key=$(echo $passphrase | hashalot -x -n 32 sha512) - blocks=$(cat $(find /sys/block | grep /$dev/size)) - echo 0 $blocks crypt aes-plain $key 0 $root 0 | \ - dmsetup create $dmlabel - fi - mount /dev/mapper/$dmlabel /mnt - fi - grep -q subroot= /proc/cmdline && return - grep -q loopfs= /proc/cmdline && return - if [ -d /mnt/etc ]; then - umount /sys - [ -n "$1" ] && for i in $@ ; do - cp -a $i /mnt$(dirname $i) - done - mount /mnt -o remount,ro - launch_init - fi - failed -} +header "Live Kit init " -mount_mapper() -{ - mount $root /mnt - try_init /dev/mapper $@ -} +init_proc_sysfs -lvmsetup() -{ - grep -q lvmroot= /proc/cmdline || return 1 - modprobe dm-mod - vgscan --ignorelockingfailure - vgchange -ay --ignorelockingfailure - root="/dev/mapper/$(sed 's/.*lvmroot=\([^ ]*\).*/\1/' < /proc/cmdline)" - return 0 -} +debug_start +debug_shell -load_raid() -{ -while read line; do - case "$line" in - *raid10*) modprobe raid10 ;; - *raid0*) modprobe raid0 ;; - *raid1*) modprobe raid1 ;; - *raid[456]*) modprobe raid456 ;; - *mirror*) modprobe dm-mirror ;; - esac -done -} +init_devs +init_aufs +init_zram -if [ "$1" != "logged" ]; then - mount -t devpts devpts /dev/pts - mount -t tmpfs tmpfs /dev/shm - mount -t tmpfs tmpfs /run - script -qc '/init logged' /run/boot.log - . /run/init -else -mount -t proc proc /proc -mount -t sysfs sysfs /sys -if grep -q dmraid= /proc/cmdline; then - root="$(sed 's/.*dmraid=\([^ ]*\).*/\1/' < /proc/cmdline)" - echo -n "Switching / to dmraid $root..." - dmraid -s | grep ^type | awk '{ print $3 }' | load_raid - case "$root" in - /dev/*);; - *) root=/dev/mapper/$(dmraid -s|grep ^name|awk '{print $3}')p${root#p};; - esac - dmraid -ay - lvmsetup - mount_mapper +# find data dir with filesystem bundles +DATA="$(find_data 60 "$DATAMNT")" +debug_shell + +# setup persistent changes, if possible +persistent_changes "$DATA" "$CHANGES" +debug_shell + +# copy to RAM if needed +DATA="$(copy_to_ram "$DATA" "$CHANGES")" +debug_shell + +# init aufs union +init_union "$CHANGES" "$UNION" +debug_shell + +echo "Copying initramfs to /initramfs" +copy_initramfs /initramfs + +# setup initramfs if it exist +if [ -d /initramfs ]; then + echo "Setup initramfs for first module..." + mount -n -o remount,add:1:/initramfs=ro aufs $UNION fi -if grep -q softraid= /proc/cmdline; then - root="$(sed 's/.*softraid=\([^ ]*\).*/\1/' < /proc/cmdline)" - echo -n "Switching / to softraid $root..." - mdadm --examine --scan --config=partitions > /etc/mdadm.conf - grep -qs " $root " /etc/mdadm.conf || - root=$(awk '/dev.md/ { print $2; exit }' < /etc/mdadm.conf) - grep level=raid /etc/mdadm.conf | load_raid - for i in 1 2 3 4 5 6 7 8 9; do - sleep $i - mdadm --assemble --scan - grep -qs ': active' /proc/mdstat && break - done - lvmsetup - mount_mapper /etc/mdadm.conf +debug_shell + +# add data to union +union_append_bundles "$DATA" "$BUNDLES" "$UNION" +debug_shell + +# rootcopy +copy_rootcopy_content "$DATA" "$UNION" + +# create empty fstab +fstab_create "$UNION" +debug_shell + +if [ -d $DATAMNT/mirror ]; then + echolog "Setup repo for mirror iso..." + mount -n -o remount,add:1:/$DATAMNT/mirror=ro aufs $UNION fi -if lvmsetup; then - echo -n "Switching / to lvm $root..." - mount_mapper -fi -if grep -q mount= /proc/cmdline; then - root="$(sed 's/.*mount=\([^ ]*\).*/\1/' < /proc/cmdline)" - dev=$(blkid | grep $root | sed 's/:.*//;q') - echo "Mounting $dev ($root) ..." - if ! mount $dev /mnt; then - if echo $dev | grep -q "/dev/sd"; then - delay=`cat /sys/module/usb_storage/parameters/delay_use` - delay=$((1+$delay)) - echo -n "sleep for $delay seconds..." - sleep $delay - fi - mount $dev /mnt - fi - grep -q posixovl /proc/cmdline && mount.posixovl /mnt -fi -if grep -q loopfs= /proc/cmdline; then - loopfs="$(sed 's/.*loopfs=\([^ ]*\).*/\1/' < /proc/cmdline)" - echo -n "Into loop file $loopfs..." - losetup /dev/loop0 /mnt/$loopfs - mount /dev/loop0 /mnt 2> /dev/null -fi -if grep -q bindfs= /proc/cmdline; then - bind="$(sed 's/.*bindfs=\([^ ]*\).*/\1/' < /proc/cmdline)" - echo "Binding ${bind/,/ to } ..." - mount --bind /mnt/${bind%,*} /mnt/${bind%,*}/${bind#*,} -fi -grep -q cryptoroot= /proc/cmdline && try_init -umount /sys -if grep -q subroot= /proc/cmdline; then - subroot="/$(sed 's/.*subroot=\([^ ]*\).*/\1/' < /proc/cmdline)" && - echo -n "Chrooting to $subroot..." - mount --move /dev/pts /mnt$subroot/dev/pts - run=$subroot/run - mount --move /run /mnt$run - cp $(LD_TRACE_LOADED_OBJECTS=1 /lib/ld*.so /usr/sbin/chroot | sed \ - 's|.*=> \(/lib/l[^ ]*\).*|\1|;/^\//!d') /usr/sbin/chroot /mnt$run - success < /run/init -if [ $free -lt 100 ] || ! mount -t tmpfs $size tmpfs /mnt; then - echo -e "\\033[70G[ \\033[1;33mSkipped\\033[0;39m]" - exit -fi -for i in $(ls -ar /); do - case "$i" in - .|..) ;; - mnt) mkdir /mnt/mnt;; - *) if ! cp -a /$i /mnt 2> /dev/null; then - failed - umount /mnt - exec /sbin/init - fi;; - esac -done -launch_init_modular -fi + +header "Live Kit done, starting $LIVEKITNAME" + +change_root "$UNION" + +header "!!ERROR occured, you shouldn't be here.!!" +/bin/sh diff -r 0b68eab7409c -r 29b33964d973 initramfs/lib/.config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/initramfs/lib/.config Wed Mar 13 17:07:55 2013 +0000 @@ -0,0 +1,35 @@ +#!/bin/bash +# This is a config file for Linux Live Kit build script. +# You shouldn't need to change anything expect LIVEKITNAME + +# Live Kit Name. Defaults to 'mylinux'; +# For example, Slax changes it to 'slax' +# Must not contain any spaces. +# If you change it, you must run ./tools/isolinux.bin.update script +# in order to update isolinux.bin for CD booting. +LIVEKITNAME="slitaz" + +# Kernel file, will be copied to your Live Kit +VMLINUZ=/boot/vmlinuz + +# Kernel version. Change it to "3.2.28" for example, if you are building +# Live Kit with a different kernel than the one you are actually running +KERNEL=$(uname -r) + +# List of directories which will be modularized +# No subdirectories are allowed, no slashes, +# so You can't use /var/tmp here for example +# Exclude directories like proc sys tmp +MKMOD="bin etc home lib lib64 opt root sbin srv usr var" + +# List of files and directories you'd like to exclude from your Live Kit +EXCLUDE="/etc/fstab /etc/mtab" + +# Temporary directory to store livekit filesystem +LIVEKITDATA=/tmp/$LIVEKITNAME-data-$$ + +# Bundle extension, for example 'sb' for .sb extension +BEXT=xz + +# Directory with kernel .ko modules, can be different in some distros +LMK="lib/modules/$KERNEL" diff -r 0b68eab7409c -r 29b33964d973 initramfs/lib/livekitlib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/initramfs/lib/livekitlib Wed Mar 13 17:07:55 2013 +0000 @@ -0,0 +1,662 @@ +#!/bin/sh + +# Functions library :: for Linux Live Kit scripts +# Author: Tomas M. +# + +# ================================================================= +# debug and output functions +# ================================================================= + +debug_start() +{ + if grep -q debug /proc/cmdline; then + DEBUG_IS_ENABLED=1 + else + DEBUG_IS_ENABLED= + fi +} + +debug_log() +{ + if [ "$DEBUG_IS_ENABLED" ]; then + echo "- debug: $*" >&2 + log "- debug: $*" + fi +} + +# header +# $1 = text to show +# +header() +{ + echo """$@""" +} + + +# echo green star +# +echo_green_star() +{ + echo -ne """* """ +} + +# log - store given text in /var/log/livedbg +log() +{ + echo "$@" 2>/dev/null >>/var/log/livedbg +} + +echolog() +{ + echo "$@" + log "$@" +} + +# show information about the debug shell +show_debug_banner() +{ + echo + echo "=====" + echo ": Debugging started. Here is the root shell for you." + echo ": Type your desired commands or hit Ctrl+D to continue booting." + echo +} + +# debug_shell +# executed when debug boot parameter is present +# +debug_shell() +{ + if [ "$DEBUG_IS_ENABLED" ]; then + show_debug_banner + setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1' + echo + fi +} + +fatal() +{ + echolog + header "Fatal error occured - $1" + echolog "Something went wrong and we can't continue. This should never happen." + echolog "Please reboot your computer with Ctrl+Alt+Delete ..." + echolog + setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1' +} + +# get value of commandline parameter $1 +# $1 = parameter to search for +# +cmdline_value() +{ + cat /proc/cmdline | egrep -o "(^|[[:space:]])$1=[^[:space:]]+" | tr -d " " | cut -d "=" -f 2- | tail -n 1 +} + + +# test if the script is started by root user. If not, exit +# +allow_only_root() +{ + if [ "0$UID" -ne 0 ]; then + echo "Only root can run $(basename $0)"; exit 1 + fi +} + +# Create bundle +# call mksquashfs with apropriate arguments +# $1 = directory which will be compressed to squashfs bundle +# $2 = output file +# $3..$9 = optional arguments like -keep-as-directory or -b 123456789 +# +create_bundle() +{ + debug_log "create_module" "$*" + rm -f "$2" # overwrite, never append to existing file + mksquashfs "$1" "$2" -comp xz -b 512K $3 $4 $5 $6 $7 $8 $9>/dev/null +} + + +# Move entire initramfs tree to tmpfs mount. +# It's a bit tricky but is necessray to enable pivot_root +# even for initramfs boot image +# +transfer_initramfs() +{ + if [ ! -r /lib/initramfs_escaped ]; then + echo "switch root from initramfs to ramfs" + SWITCH=/m # one letter directory + mkdir -p $SWITCH + mount -t tmpfs -o size="100%" tmpfs $SWITCH + cp -a /??* $SWITCH 2>/dev/null # only copy two-and-more-letter directories + cd $SWITCH + echo "This file indicates that we successfully escaped initramfs" > $SWITCH/lib/initramfs_escaped + exec switch_root -c /dev/console . $0 + fi +} + +copy_initramfs() +{ + SWITCH=$1 # one letter directory + mkdir -p $SWITCH + SYS_DIR="dev bin etc boot lib sbin home root run usr var" + for dir in $SYS_DIR; do + cp -a /$dir /$SWITCH + done + +} + +# mount virtual filesystems like proc etc +# +init_proc_sysfs() +{ + debug_log "init_proc_sysfs" "$*" + mkdir -p /proc /sys /etc $MEMORY + mount -n -t proc proc /proc + echo "0" >/proc/sys/kernel/printk + mount -n -t sysfs sysfs /sys + mount -n -o remount,rw rootfs / + ln -sf /proc/mounts /etc/mtab +} + +# make sure some devices are there +init_devs() +{ + debug_log "init_devs" "$*" + echo /sbin/mdev > /proc/sys/kernel/hotplug + mdev -s + modprobe zram 2>/dev/null + modprobe loop 2>/dev/null + modprobe squashfs 2>/dev/null + modprobe fuse 2>/dev/null +} + +# Activate zram (auto-compression of RAM) +# Compressed RAM consumes 1/2 or even 1/4 of original size +# Setup static size of 500MB +# +init_zram() +{ + debug_log "init_zram" "$*" + echo_green_star + echo "Setting dynamic RAM compression using ZRAM" + echo 536870912 > /sys/block/zram0/disksize # 512MB + mkswap /dev/zram0 >/dev/null + swapon /dev/zram0 -p 32767 + echo 100 > /proc/sys/vm/swappiness +} + +# load the AUFS kernel module if needed +# +init_aufs() +{ + debug_log "init_aufs" "$*" + # TODO maybe check here if aufs support is working at all + # and procude useful error message if user has no aufs + modprobe aufs brs=1 2>/dev/null +} + +# Setup empty union +# $1 = changes directory (ramfs or persistent changes) +# $2 = union directory where to mount the union +# +init_union() +{ + debug_log "init_union" "$*" + + echo_green_star + echo "Setting up union using AUFS 3" + mkdir -p "$1" + mkdir -p "$2" + mount -t aufs -o nowarn_perm,xino="/.xino",trunc_xino,br="$1" aufs "$2" + if [ $? -ne 0 ]; then dmesg | tail -n 1; fatal "can't setup union (aufs)"; fi +} + +# Return device mounted for given directory +# $1 = directory +# +mounted_device() +{ + debug_log "mounted_device" "$*" + + local MNT TARGET + MNT="$1" + while [ "$MNT" != "/" -a "$MNT" != "." -a "$MNT" != "" ]; do + TARGET="$(grep -F " $MNT " /proc/mounts | cut -d " " -f 1)" + if [ "$TARGET" != "" ]; then + echo "$TARGET" + return + fi + MNT="$(dirname "$MNT")" + done +} + +# Return mounted dir for given directory +# $1 = directory +# +mounted_dir() +{ + debug_log "mounted_dir" "$*" + + local MNT + MNT="$1" + while [ "$MNT" != "/" -a "$MNT" != "." -a "$MNT" != "" ]; do + if mountpoint -q "$MNT" 2>/dev/null; then + echo "$MNT" + return + fi + MNT="$(dirname "$MNT")" + done +} + +# Make sure to mount FAT12/16/32 using vfat +# in order to support long filenames +# $1 = device +# +device_bestfs() +{ + debug_log "device_bestfs" "$*" + local FS + + FS="$(blkid "$1" | sed -r "s/.* TYPE=//" | sed -r 's/ .*//' | tr -d '"' | tr [A-Z] [a-z])" + if [ "$FS" = "msdos" -o "$FS" = "fat" -o "$FS" = "vfat" ]; then + FS="vfat" + elif [ "$FS" = "ntfs" ]; then + FS="ntfs-3g" + elif [ "$1" = "iso9660" -o "$1" = "udf" ]; then + echo -n ",ro" + else + echo "-t $FS" + fi +} + +# Filesystem options for mount +# $1 = filesystem or '-t filesystem' +# +fs_options() +{ + debug_log "fs_options" "$*" + + if [ "$1" = "-t" ]; then + shift + fi + if [ "$1" = "vfat" ]; then + echo "-o check=s,shortname=mixed,iocharset=utf8" + fi +} + + +# Modprobe network kernel modules until a working driver is found. +# These drivers are (or used to be) probed in Slackware's initrd. +# The function returns the first device found, yet it doesn't have +# to be a working one, eg. if the computer has two network interfaces +# and ethernet cable is plugged only to one of them. +# +init_network_dev() +{ + debug_log "init_network_dev" "$*" + local MODULE ETH + + for MODULE in 3c59x acenic de4x5 e1000 e1000e e100 epic100 hp100 \ + ne2k-pci pcnet32 8139too 8139cp tulip via-rhine r8169 atl1e yellowfin \ + tg3 dl2k ns83820 atl1 b44 bnx2 skge sky2 tulip depca 3c501 3c503 \ + 3c505 3c507 3c509 3c515 ac3200 at1700 cosa cs89x0 de600 de620 e2100 \ + eepro eexpress eth16i ewrk3 forcedeth hostess_sv11 hp-plus hp ni52 \ + ni65 sb1000 sealevel smc-ultra sis900 smc9194 wd; do + modprobe $MODULE 2>/dev/null + ETH="$(cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " " | head -n 1)" + if [ "$ETH" != "" ]; then + echo $ETH + return 0 + fi + rmmod $MODULE 2>/dev/null + done + + # If we are here, none of the above specified modules worked. + # As a last chance, try to modprobe everything. + find /lib/modules/ | xargs -n 1 modprobe + cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " " | head -n 1 +} + + +# Download data from tftp +# $1 = target (store downloaded files there) +# +download_data_pxe() +{ + debug_log "download_data_pxe" "$*" + local CMD CLIENT SERVER GW MASK PORT ETH PROTOCOL + + mkdir -p "$1/$LIVEKITNAME" + + cmdline_value ip | while IFS=":" read CLIENT SERVER GW MASK PORT; do + echo_green_star >&2 + echo "Downloading files from $SERVER ..." >&2 + + ETH=$(init_network_dev) + if [ "$PORT" = "" ]; then PORT="7529"; fi + + # set IP address as given by boot paramter + if [ "$CLIENT" != "" -a "$MASK" != "" ]; then + ifconfig $ETH "$CLIENT" netmask "$MASK" + route add default gw "$GW" + else + # if client ip is unknown, try to get a DHCP lease + udhcpc -i $ETH -f -q + fi + + # well known IP address of Google public DNS service + echo nameserver 8.8.8.8 >> /etc/resolv.conf + + PROTOCOL=http + wget -q -O "$1/PXEFILELIST" "http://$SERVER:$PORT/PXEFILELIST?$(uname -r):$(uname -m)" + if [ $? -ne 0 ]; then + echo "Error downloading from http://$SERVER:$PORT, trying TFTP" >&2 + PROTOCOL=tftp + tftp -g -r PXEFILELIST -l "$1/PXEFILELIST" $SERVER + fi + + cat "$1/PXEFILELIST" | while read FILE; do + if [ "$PROTOCOL" = "http" ]; then + wget -O "$1/$LIVEKITNAME/$FILE" "http://$SERVER:$PORT/$FILE" + else + echo "* $FILE ..." >&2 + tftp -g -r $FILE -l "$1/$LIVEKITNAME/$FILE" $SERVER + fi + done + done + + echo "$1/$LIVEKITNAME" +} + +# Find LIVEKIT data by mounting all devices +# If found, keep mounted, else unmount +# $1 = data directory target (mount here) +# $2 = data directory which contains compressed bundles +# +find_data_try() +{ + debug_log "find_data_try" "$*" + + local DEVICE FS FROM OPTIONS + + mkdir -p "$1" + blkid | sort | cut -d: -f 1 | grep -E -v "/loop|/ram|/zram" | while read DEVICE; do + FROM="$2" + FS="$(device_bestfs "$DEVICE")" + OPTIONS="$(fs_options $FS)" + mount -r "$DEVICE" "$1" $FS $OPTIONS 2>/dev/null + + # if the FROM parameter is actual file, mount it again as loop (eg. iso) + if [ -f "$1/$FROM" ]; then + mount -o remount,rw "$DEVICE" "$1" 2>/dev/null + mkdir -p "$1/../iso" + mount -o loop,ro "$1/$FROM" "$1/../iso" 2>/dev/null + FROM="../iso/$LIVEKITNAME" + fi + + # search for bundles in the mounted directory + if [ "$(find "$1/$FROM" -maxdepth 2 -name "*.$BEXT" 2>/dev/null)" != "" ]; then + # we found at least one bundle/module here + mount -o remount,rw "$DEVICE" "$1" 2>/dev/null + echo "$1/$FROM" | tr -s "/" | sed -r "s:/[^/]+/[.][.]/:/:g" + return + fi + + # unmount twice, since there could be mounted ISO as loop too. If not, it doesn't hurt + umount "$1" 2>/dev/null + umount "$1" 2>/dev/null + done +} + +# Retry finding LIVEKIT data several times, +# until timeouted or until data is found +# $1 = timeout +# $2 = data directory target (mount here) +# +find_data() +{ + debug_log "find_data" "$*" + + local DATA FROM + + if [ "$(cmdline_value ip)" != "" ]; then + download_data_pxe "$2" + return + fi + + FROM="$(cmdline_value from)" + if [ "$FROM" = "" ]; then FROM="$LIVEKITNAME"; fi + + echo_green_star >&2 + echo -n "Looking for $LIVEKITNAME data in /$FROM .." | tr -s "/" >&2 + for timeout in $(seq 1 $1); do + echo -n "." >&2 + DATA="$(find_data_try "$2" "$FROM")" + if [ "$DATA" != "" ]; then + echo "" >&2 + echo "* Found on $(mounted_device "$2")" >&2 + echo "$DATA" + return + fi + sleep 1 + done + echo "" >&2 + + if [ "$DATA" = "" ]; then + fatal "$LIVEKITNAME data not found" + fi + +} + +# Activate persistent changes +# $1 = data directory +# $2 = target changes directory +# +persistent_changes() +{ + debug_log "persistent_changes" "$*" + + local CHANGES T1 T2 + + CHANGES="$1/$(basename "$2")" + T1="$CHANGES/.empty" + T2="$T1"2 + + # Setup the directory anyway, it will be used in all cases + mkdir -p "$2" + + # If persistent changes are not requested, end here + if grep -vq perch /proc/cmdline; then + return + fi + + # check if changes directory exists and is writable + touch "$T1" 2>/dev/null && rm -f "$T1" 2>/dev/null + + # if not, simply return back + if [ $? -ne 0 ]; then + echo "* Persistent changes not writable or not used" + return + fi + + echo_green_star + echo "Testing persistent changes for posix compatibility" + touch "$T1" && ln -sf "$T1" "$T2" 2>/dev/null && \ + chmod +x "$T1" 2>/dev/null && test -x "$T1" && \ + chmod -x "$T1" 2>/dev/null && test ! -x "$T1" && \ + rm "$T1" "$T2" 2>/dev/null + + if [ $? -ne 0 ]; then + echo "* Activating dynamic sized storage for persistent changes" + rm "$T1" "$T2" 2>/dev/null + + mount.dynfilefs "$CHANGES/changes.dat" 4000 "$2" + if [ "$(device_bestfs "$2/loop.fs" | tr -d " ")" = "-t" ]; then + mke2fs -F "$2/loop.fs" >/dev/null + fi + mount -o loop,sync "$2/loop.fs" "$2" + rmdir "$2/lost+found" 2>/dev/null + else + echo "* Activating native persistent changes" + mount --bind "$CHANGES" "$2" + fi +} + +# Copy content of rootcopy directory to union +# $1 = data directory +# $2 = union directory +copy_rootcopy_content() +{ + debug_log "copy_rootcopy_content" "$*" + + if [ "$(ls -1 "$1/rootcopy/" 2>/dev/null)" != "" ]; then + echo_green_star + echo "Copying content of rootcopy directory..." + cp -a "$1"/rootcopy/* "$2" + fi +} + +# Copy data to RAM if requested +# $1 = live data directory +# $2 = changes directory +# +copy_to_ram() +{ + debug_log "copy_to_ram" "$*" + + local MDIR MDEV RAM CHANGES + + if grep -vq toram /proc/cmdline; then + echo "$1" + return + fi + + echo "* Copying $LIVEKITNAME data to RAM..." >&2 + RAM="$(dirname "$2")"/toram + mkdir -p "$RAM" + cp -a "$1"/* "$RAM" + echo "$RAM" + + MDIR="$(mounted_dir "$1")" + MDEV="$(mounted_device "$1")" + MDEV="$(losetup $MDEV 2>/dev/null | cut -d " " -f 3)" + umount "$MDIR" 2>/dev/null + + if [ "$MDEV" ]; then # iso was mounted here, try to unmount the FS it resides on too + MDEV="$(mounted_device "$MDEV")" + umount "$MDEV" 2>/dev/null + fi +} + +# load filter +# +filter_load() +{ + local FILTER + FILTER=$(cmdline_value load) + if [ "$FILTER" = "" ]; then + cat - + else + cat - | egrep "$FILTER" + fi +} + +# noload filter +# +filter_noload() +{ + local FILTER + FILTER=$(cmdline_value load) + if [ "$FILTER" = "" ]; then + cat - + else + cat - | egrep -v "$FILTER" + fi +} + +# sort modules by number even if they are in subdirectory +# +sortmod() +{ + cat - | sed -r "s,(.*/(.*)),\\2:\\1," | sort -n | cut -d : -f 2- +} + +# Mount squashfs filesystem bundles +# and add them to union +# $1 = directory where to search for bundles +# $2 = directory where to mount bundles +# $3 = directory where union is mounted +# +union_append_bundles() +{ + debug_log "union_append_bundles" "$*" + + local BUN + + echo_green_star + echo "Adding bundles to union" + ( ls -1 "$1" | sort -n ; cd "$1" ; find base/ 2>/dev/null ; find modules/ 2>/dev/null | sortmod | filter_load) | grep '[.]'$BEXT'$' | filter_noload | while read BUNDLE; do + echo "* $BUNDLE" + BUN="$(basename "$BUNDLE")" + mkdir -p "$2/$BUN" + mount -o loop -t squashfs "$1/$BUNDLE" "$2/$BUN" + mount -n -o remount,add:1:$2/$BUN=rr aufs $3 + done +} + +# Create empty fstab properly +# $1 = root directory +# +fstab_create() +{ + debug_log "fstab_create" "$*" + + local FSTAB + FSTAB="$1/etc/fstab" + echo aufs / aufs defaults 0 0 > $FSTAB + echo proc /proc proc defaults 0 0 >> $FSTAB + echo sysfs /sys sysfs defaults 0 0 >> $FSTAB + echo devpts /dev/pts devpts gid=5,mode=620 0 0 >> $FSTAB + echo tmpfs /dev/shm tmpfs defaults 0 0 >> $FSTAB +} + + +# Change root and execute init +# $1 = where to change root +# +change_root() +{ + debug_log "change_root" "$*" + + umount /proc + umount /sys + + cd "$1" + + # make sure important device files and directories are in union + mkdir -p boot dev proc sys tmp mnt run + chmod 1777 tmp + if [ ! -e dev/console ]; then mknod dev/console c 5 1; fi + if [ ! -e dev/tty ]; then mknod dev/tty c 5 0; fi + if [ ! -e dev/tty0 ]; then mknod dev/tty0 c 4 0; fi + if [ ! -e dev/tty1 ]; then mknod dev/tty1 c 4 1; fi + if [ ! -e dev/null ]; then mknod dev/null c 1 3; fi + if [ ! -e sbin/fsck.aufs ]; then ln -s /bin/true sbin/fsck.aufs; fi + + # find chroot and init + if [ -x bin/chroot ]; then CHROOT=bin/chroot; fi + if [ -x sbin/chroot ]; then CHROOT=sbin/chroot; fi + if [ -x usr/bin/chroot ]; then CHROOT=usr/bin/chroot; fi + if [ -x usr/sbin/chroot ]; then CHROOT=usr/sbin/chroot; fi + if [ "$CHROOT" = "" ]; then fatal "Can't find executable chroot command"; fi + + if [ -x bin/init ]; then INIT=bin/init; fi + if [ -x sbin/init ]; then INIT=sbin/init; fi + if [ "$INIT" = "" ]; then fatal "Can't find executable init command"; fi + + mkdir -p mnt/live + mount -n -o remount,ro aufs . + pivot_root . mnt/live + exec $CHROOT . $INIT < dev/console > dev/console 2>&1 +}