Quest for the Live distro continues
Table of Contents
Introduction
These days laptops have so much RAM that it is possible to run a complete operating system from it. Some reasons to do it are:
- the system does not boot anymore and you need a quick way to access files, browse the web or rescue the system
- there is no Linux installed on the laptop and you are missing your favourite OS
- for security reason you want to start with a fresh system or you want to discharge every possible change after a working session
Since my favourite distribution is Slackware [6] I
started with Slackware 15 Live edition. However, even though I was able
to extract the init script from the initramfs and get all the desired
boot options, the system seems to not have unmounted properly the boot
device (I get an error when I try to mount it in read-write mode or
when I try eject /dev/sda
).
So my quest to a better alternative continues.
In this article we are going to review briefly the generic procedure I use to configure the distro to run directly from RAM and we will cover the specific configurations for:
The generic procedure
As described in more detail in previous articles (click on the tag #live to see the list) most of the time the procedure I use to run a new Live distro is:
- download the ISO image of the desired Linux Live
- mount it read-only in a folder
- find the following files in the mounted folder:
- boot configurations (usually in the file grub.cfg or syslinux.cfg or isolinux.cfg)
- the kernel (usually called bzImage or vmlinuz)
- the initramfs (usually called initrd.gz or initrd.xz)
- the image of the root filesystem (the biggest file on the drive sometimes split into multiple modules)
- create a bootable USB drive with Grub2
- copy the content of the ISO image to a folder on the USB key
- create a new entry in the file grub.cfg from the content of the boot configuration files in the ISO image
- extract the content of the initramfs to a temporary folder and read the init
script to learn what boot parameters are supported (it is a file
called init or linuxrc located in the root folder or in
bin
orsbin
) - use the knowledge from the previous point to tune grub.cfg
Some distributions (like Ubuntu-based and RedHat-based) have the init script (in the initramfs) which is either a binary file or too hard to read. In this situations official documentation is the only possible way to get the list of all the supported parameters. Unfortunately, from my experience, most of the time it is not that good.
XUbuntu or LUbuntu
If your laptop has Secure Boot active and you cannot disable it, your options regarding which distribution to use are limited. If you don’t mind using a systemd-based distro XUbuntu or LUbuntu might come in handy. Differently from others, these two distros have a default configuration to run from the boot device (mounted read-only) and from the live system you can perform a regular installation if you like.
On every boot you have to select some initial parameters like the layout of the keyboard and the timezone. This is annoying if you do not plan to install it. Luckily to get rid of it you just need to pass a few parameters from the boot loader.
So the steps are:
- download the ISO image from the official website
- copy it on a USB stick (from any Linux system):
dd if=path/to/isofile of=/dev/sdX bs=4M conv=notrunc,fsync
- boot the laptop where you want to run XUbuntu/LUbuntu from USB
- when you see the menu of Grub2 leave the selection on the first entry and press “e” to edit the command line
- edit the line that starts with “linux” to make it become:
linux /casper/vmlinuz file=/cdrom/preseed/lubuntu.seed toram
(if you are using XUbuntu you can leave the value xubuntu.seed
instead of changing it to lubuntu.seed
)
Check the supported boot options at [7] for more details.
Fedora
The same considerations done for Ubuntu apply to Fedora [11]. This is the development branch of the Red Hat world and it comes in multiple flavors called “Spins” [12]. Download for example the Xfce version [13] and copy it onto a USB stick with:
dd if=path/to/isofile of=/dev/sdX bs=4M conv=notrunc,fsync
Start your laptop from USB and edit the first Grub entry (moving the
selection on the first row and pressing “e”) removing rd.live.check quiet
. Then add rd.live.ram selinux=0 3
:
linux /images/pxeboot/vmlinuz root=live:CDLABEL=Fedora-Xfce-Live-40-1-14 rd.live.image rd.live.ram selinux=0
Be aware the root user has no password and the regular user is called one (with password one). I recommend setting the root password and changing the default password of one before using it.
A couple of further customization I like to do are:
- start in runlevel 3 (text mode) and then start the X Window System
with
startx
- the root filesystem will have only 1 GB of space, so my first
solution was to use the space under /dev/shm or /tmp, however if you
want to install new software you need more space and this can be
achieved by adding another boot parameter:
rd.minmem=<megabyte>
[14] The final configuration with this two points is:
linux /images/pxeboot/vmlinuz root=live:CDLABEL=Fedora-Xfce-Live-40-1-14 rd.live.image rd.live.ram selinux=0 rd.minmem=4096 3
Notes:
3
is to start in runlevel 3- I used
4096
to have 4 GB of more space in my root filesystem, but it is RAM memory, so do your own math to check if you have enough space and choose a proper value - Check the Dracut man page 14 for more available options
- I don’t remember if you will see
linux
orlinuxefi
in the Grub configuration, however it will work with both (keep what you have)
If you are annoyed by always typing all this stuff on every boot, I
recently found a grub command called configfile
[15]
that allows you to load
another config file from a partition. So you can copy the original
grub.cfg from the USB key (or from the ISO image), customize with these
options and once Grub is loaded you can type c
to enter the command
line and type, for example, configfile (hd1,gpt4)/grub.cfg
if your
saved file is in the root directory of the forth partition on the
second hard drive (check with ls
or the search
command to find
your file).
Porteus Kiosk
Let’s get back to an interesting Slackware-based distro: Porteus
Linux. This distribution comes in two flavors, one for the Desktop and
one aimed to be a web kiosk. Download the iso image of Porteus Kiosk
and mount it to see the boot configuration and to extract the init
script from the initrd file (full script in
Appendix 1).
Copy the content of the iso image in a folder
called porteus
on the bootable USB drive and add an entry in
grub.cfg
as the following:
menuentry "Porteus 5 XFCE 64-bit" {
load_video
insmod gzio
insmod ext2
search -f /porteus/vmlinuz --set=root
linux /porteus/vmlinuz copy2ram from=LABEL:USBBOOT nocd nohd locale=en_US.utf8 tz=UTC ipv6.disable=1 3
initrd /porteus/initrd.xz
}
Remember to substitute USBBOOT
in the third last line to match your
label of the usb partition holding the folder porteus
.
As you can see I have used copy2ram
and nocd nohd
to instruct
Porteus to copy the root filesystem to ram, unmount the USB drive and
avoid mounting the partitions from the main Hard Drive.
In the past I used successfully this configuration, however on my current laptop the firmware of the wifi card is missing so unfortunately I am not able to connect to the network.
SliTaz GNU/Linux
This Swiss distribution [8] is super lightweight and runs with BusyBox and the Xvesa graphic driver [9]. At the time of writing the rolling release is less than 100 MB and should run from RAM by design (so there is no need for an extra boot parameter).
The challenge here is that the configuration of the bootloader is a little bit different. It uses an executable called c32box.c32 (a COM32 binary [10]) to start the bootstrap procedure. In addition the initramfs (which is also the root fs in this case) is split in 4 parts. I wasn’t able to concatenate those parts in the proper way and extract the content, so I limited myself to come up with the following working configuration for Grub2:
menuentry "SliTaz 5 Rolling" {
load_video
insmod gzio
insmod ext2
search -f /slitaz/bzImage --set=root
linux /slitaz/bzImage initrd=/slitaz/rootfs4.gz,/slitaz/rootfs3.gz,/slitaz/rootfs2.gz,/slitaz/rootfs1.gz root=/dev/null video=-32 autologin
initrd /slitaz/rootfs4.gz /slitaz/rootfs3.gz /slitaz/rootfs2.gz /slitaz/rootfs1.gz
}
As you can deduce from the configuration, I have copied the content of
the SliTaz rolling release in the folder slitaz
on my USB drive and
I have moved the kernel and the files of the rootfs at the top level.
The first run left me with a system stuck probably because the kernel
is too old for my modern laptop. So I tried to use the kernel huge
from Slackware (one of the kernels is called huge
because it is supposed to have a vast set of drivers compiled directly
into it). This time the bootstrap seemed to run more smoothly however
it was not able to load some required modules (like zram).
At this point the bootstrap process asked me to choose keyboard
layout and time zone
and I was left with a login prompt. Eager to test the new system I
figured out the credentials for the user root (user=root,
password=root). I started inspecting the content of /etc/passwd
and of the folder /home
searching for a regular user and I found the
unprivileged user one
. I reset the password with passwd one
and logged in on a
different shell (accessible with CTRL+ALT+F3 for example).
Unfortunately there is nothing more I was able to do. The X server
doesn’t start (try to run startx
).
SalixOS Live
Left with the last chance, but without hoping on it too much I gave a try to SalixOS Live edition (two flavors also here, pick the correct one).
Since SalixOS is fully compatible with Slackware I thought there weren’t many differences between Slackware Live and this one. However eventually I was positively surprised because everything worked as I wished. My tests are:
- am I able to successfully eject the removable device?
- am I able to start the X server?
- am I able to connect to internet and browse the web?
- (optional) am I able to connect my bluetooth device?
The first three conditions are met, the last one I haven’t tried it yet.
Let’s see how to configure the system:
- the first time I tried to make an educated guess and without checking too carefully I was able to boot the kernel and reach the initramfs where the system was telling me it wasn’t able to properly mount the main filesystem
- even though the boot process was interrupted I was in a shell where
I could investigate what was wrong and I started to read the init
script with
less
(see Appendix 2 for the full script) - the reason why the root filesystem was not found is a missing parameter from the grub command line (I didn’t pass the label of the removable media)
- from the code, however, there is no parsing of the input parameters
so I suspected that the boot arguments were translated into
environment variables (and I was right) - checked with command
env
- the other issue is that there is a hard-coded path: the folder
modules
of the root filesystem must be in the directoryboot
under the root of the USB drive
I moved the folder modules
from salix64live
to boot
in the
filesystem of the removable device and used the following entry in
grub.cgf
:
menuentry "Salix Linux Live 64-bit" {
load_video
insmod gzio
insmod ext2
set args='max_loop=255 vga=791 locale=en_US.utf8 keymap=us useswap=no copy2ram=yes medialabel=USBBOOT tz=Europe/Dublin hwc=UTC runlevel=3'
search -f /salix64live/vmlinuz --set=root
linux /salix64live/vmlinuz initrd=initrd.gz $args ipv6.disable=1 # 3 debug hwc=localtime
initrd /salix64live/initrd.gz
}
(Substitute USBBOOT
with the label of the filesystem on your USB
stick)
Conclusions
In this article we saw some working configurations of Linux distributions that run entirely from RAM. Eventually the two most reliable are XUbuntu/LUbuntu if you have Secure Boot enabled and SalixOS (Live edition) for the rest of us in love with Slackware Linux.
References
[7] https://manpages.ubuntu.com/manpages/bionic/man7/casper.7.html
[8] https://slitaz.org/en/asso/
[9] https://slitaz.org/en/about/#spec
[10] https://www.syslinux.org/old/comboot.php
[11] https://fedoraproject.org/
[12] https://fedoraproject.org/spins/
[13] https://fedoraproject.org/spins/xfce/
[14] https://www.man7.org/linux/man-pages/man7/dracut.cmdline.7.html
[15] https://www.gnu.org/software/grub/manual/grub/html_node/configfile.html
Appendix 1: the full init script of Porteus (extracted from initrd.xz)
#!/bin/sh
### linuxrc script by brokenman <http://www.porteus.org>
export PATH=/bin:/usr/bin:./
# Source functions
#ORIGINAL: . ./finit
### ===> START IMPORT FROM finit <=== ###
## Functions for porteus init
## Author brokenman
# Export some color functions
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
BOLD='\033[1;37m'
RST='\033[0m' # Reset Color
# Find a parameter on boot line
param() {
if [ -e $CFGDEV/$FOLDER/$CFG ]; then
egrep -qo "^${1}$" $CFGDEV/$FOLDER/$CFG || egrep -qo " $1( |\$)" /proc/cmdline
else
egrep -qo " $1( |\$)" /proc/cmdline
fi
}
value() {
if [ -e $CFGDEV/$FOLDER/$CFG ]; then
egrep -o "^${1}=[^ ]+" $CFGDEV/$FOLDER/$CFG | cut -d= -f2
egrep -o " $1=[^ ]+" /proc/cmdline | cut -d= -f2
else
egrep -o " $1=[^ ]+" /proc/cmdline | cut -d= -f2
fi
}
# Begin debug staggered prompt boot mode
debug() { param debug && { echo -e "\n=====\n: Debugging started. Here is the shell for you.\n: Type your desired commands, hit Ctrl+D to continue booting\n: or press Ctrl+Alt+Del to reboot."; setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1'; echo -e "\n\n"; }; }
# Run fstab for setup
fstab() { rm -f /tmp/devices
param nocd || for x in /dev/sr*; do blkid $x >>/tmp/devices; done
param nohd || blkid | egrep -v '/dev/sr|/dev/loop|/dev/mapper' >>/tmp/devices
dev=`egrep -v 'TYPE="sw|TYPE="LVM|TYPE=".*_raid_member"' /tmp/devices 2>/dev/null | cut -d: -f1 | cut -d/ -f3 | sort | uniq`
cat > /etc/fstab << EOF
# Do not edit this file as fstab is recreated automatically during every boot.
# Please use /etc/rc.d/rc.local or sysvinit scripts if you want to mount/unmount
# drive, filesystem or network share.
# System mounts:
aufs / aufs defaults 0 0
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
devpts /dev/pts devpts rw,mode=0620,gid=5 0 0
# Device partitions:
EOF
for x in $dev; do
fs=`grep -w /dev/$x /tmp/devices | egrep -o ' TYPE=[^ ]+' | cut -d'"' -f2`
[ $fs = vfat ] && echo "/dev/$x /mnt/$x vfat $MOPT,umask=0,check=s,utf8,uid=1000 0 0" >>/etc/fstab || echo "/dev/$x /mnt/$x $fs $MOPT 0 0" >>/etc/fstab
if [ ! -d /mnt/$x ]; then
mkdir /mnt/$x
if [ $fs = ntfs ]; then
ntfs-3g /dev/$x /mnt/$x -o $MOPT,uid=1000,big_writes 2>/dev/null || { sed -i "/$x /d" /etc/fstab; rmdir /mnt/$x; }
else
mount -n /mnt/$x 2>/dev/null || { modprobe $fs 2>/dev/null && mount -n /mnt/$x 2>/dev/null || { sed -i "/$x /d" /etc/fstab; rmdir /mnt/$x; }; }
fi
fi
done
if [ -z "`egrep -o " noswap( |\$)" /proc/cmdline`" -a -e /tmp/devices ]; then
#echo -e "\n# Swap partitions:" >>/etc/fstab
for x in `grep 'TYPE="swap"' /tmp/devices | cut -d: -f1`; do echo "$x none swap sw,pri=1 0 0" >>/etc/fstab; done
fi }
# Mount things
mount_device() {
fs=`blkid /dev/$1 | egrep -o ' TYPE=[^ ]+' | cut -d'"' -f2`
if [ "$fs" ]; then
mkdir /mnt/$1
if [ $fs = vfat ]; then
mount -n /dev/$1 /mnt/$1 -o $MOPT,umask=0,check=s,utf8,uid=1000 2>/dev/null || rmdir /mnt/$1
elif [ $fs = ntfs ]; then
ntfs-3g /dev/$1 /mnt/$1 -o $MOPT,uid=1000,big_writes 2>/dev/null || rmdir /mnt/$1
else
mount -n /dev/$1 /mnt/$1 -o $MOPT 2>/dev/null || { modprobe $fs 2>/dev/null && mount -n /dev/$1 /mnt/$1 -o $MOPT || rmdir /mnt/$1; }
fi
fi }
# Search for boot location
search() { FND=none; for x in `ls /mnt | tac`; do
[ $1 /mnt/$x/$2 ] && { DEV=$x; FND=y; break; }; done
[ $FND = y ]; }
# Delay booting a little until devices have settled
nap() { echo -en $i"device not ready yet? delaying [1;33m$SLEEP[0m seconds \r"; sleep 1; }
lazy() { SLEEP=10; while [ $SLEEP -gt 0 -a $FND = none ]; do nap; let SLEEP=SLEEP-1; fstab; search $*; done }
# Find location of Porteus files
locate() { LPATH=`echo $2 | cut -b-5 | sed s@/dev@/mnt@`
if [ $LPATH = /mnt/ ]; then
DEV=`echo $2 | cut -d/ -f3`; LPTH=`echo $2 | cut -d/ -f4-`; SLEEP=6
while [ $SLEEP -gt 0 -a ! -b /dev/$DEV ]; do nap; let SLEEP=SLEEP-1; fstab; done
[ -d /mnt/$DEV ] || mount_device $DEV
[ $1 /mnt/$DEV/$LPTH ]
elif [ $LPATH = UUID: -o $LPATH = LABEL ]; then
ID=`echo $2 | cut -d: -f2 | cut -d/ -f1`; LPTH=`echo $2 | cut -d/ -f2-`; DEV=`blkid | grep $ID | cut -d: -f1 | cut -d/ -f3`; SLEEP=6
while [ $SLEEP -gt 0 -a "$DEV" = "" ]; do nap; let SLEEP=SLEEP-1; fstab; DEV=`blkid | grep $ID | cut -d: -f1 | cut -d/ -f3`; done
[ -d /mnt/$DEV ] || mount_device $DEV
[ $1 /mnt/$DEV/$LPTH ]
else
LPTH=$2; search $* || lazy $*
fi }
# Check if a location is writable
is_writable(){ touch $1/.test 2>/dev/null; [ -e $1/.test ] && rm $1/.test; }
# Booting failed. Failed to find porteus files.
fail() { echo -e $i"couldn't find $1. Correct your from= cheatcode.\n Documentation in /usr/doc/porteus. Press 'enter' to continue booting."; read -s; }
# Failed to initiate changes. Creating temporary changes on tmpfs for this session.
fail_chn() { mount -nt tmpfs -o size=$RAMSIZE tmpfs /memory/changes; CHANGES=memory; CHNDEV=memory; }
# Just draw a line
draw() { echo "[1;33m""---------------------------------------------------------""[0m"; }
# Error checking a save file.
fsck_dat() { echo $i"checking $1 for errors"
fs=`blkid $1 | egrep -o ' TYPE=[^ ]+' | cut -b8-10`
if [ $fs = xfs ]; then
echo $i"detected xfs - performing fsck at mount time"
elif [ $fs = ext ]; then
draw; e2fsck -C 0 -p $1; wait; draw
else
echo $i"detected unsupported fs - skipping fsck"
fi }
# Copy modules
cpmod() { NUM=`grep -c '.' $1`
modfile=$1
while read x; do
echo -en "[1;33m"" ($NUM modules left) \r""[0m"; let NUM=NUM-1; NAME=`basename "$x"`
cp "$x" /memory/copy2ram 2>/dev/null
if [ $? -eq 0 ]; then
sed -i s@^.*/"$NAME"@/memory/copy2ram/"$NAME"@ /tmp/modules
else
rm /memory/copy2ram/"$NAME"; echo -e $i"[1;36m""Not enough memory to copy $NAME""[0m"; echo -e $i"[1;36m""Other modules will be skipped.""[0m"
find /memory/copy2ram -name "*.xzm" | sort >/tmp/modules
break
fi
done < $modfile
echo -en " \r"
}
# If bootlog cheatcode is present then make log entry
blog(){
param log && echo "$1" >> $LOGFILE
}
# Check for a boot param
chk_bootcfg(){ grep "^$1" /union/etc/bootcmd.cfg; }
### ===> END IMPORT FROM finit <=== ###
# Enable pivot_root in initramfs to let it behave like initrd:
if [ -d /m ]; then
mount -nt tmpfs tmpfs -o mode=0755 /m
cp -a ??* /m 2>/dev/null
exec switch_root /m linuxrc "$@"
fi
mount -nt proc proc /proc
mount -nt sysfs sysfs /sys
echo 0 >/proc/sys/kernel/printk
## Check for debug
if [ `grep -q debug /proc/cmdline` ]; then DBUG=0; fi
clear
echo -e "${BOLD}Porteus. Lightweight, lightning fast, portable.${RST}"
echo
# Variables:
i=`echo "[1;33m""^ ""[0m"`
m=`echo "[1;33m""->""[0m"`
arch=`uname -m`; [ $arch = x86_64 ] || arch=i586
CFG=`value cfgfile`; [ $CFG ] || CFG=porteus-v5.0-$arch.cfg
FROM=`value from`; ISO=`echo $FROM | egrep ".*\.iso( |\$)"`
IP=`value ip | cut -d: -f2`
MOPT=`value mopt`; [ $MOPT ] || MOPT="noatime,nodiratime,suid,dev,exec,async"
CHANGES=`value changes`
RAMSIZE=`value ramsize`; [ $RAMSIZE ] || RAMSIZE=60%
LOAD=`value load | sed 's/;/|/g'`; [ $LOAD ] || LOAD=._null
NOLOAD=`value noload | sed 's/;/|/g'`; [ $NOLOAD ] || NOLOAD=._null
EXTRAMOD=`value extramod | sed 's/;/ /g'`
RAMMOD=`value rammod | sed 's/;/|/g'`
ROOTCOPY=`value rootcopy`
FOLDER=porteus
livedbg=/var/log/livedbg
LOGFILE=/var/log/boot.log
## Let's start!
mount -nt devtmpfs none /dev
# Perform filesystem check:
if param fsck; then
echo $i"performing linux filesystem check on all available devices:"
sleep 3
draw
for x in `blkid | grep 'TYPE="ext' | cut -d: -f1`; do e2fsck -C 0 -p $x; wait; done
draw
fi
# Create /etc/fstab and mount devices:
fstab
debug
# Find *.cfg file:
echo $i"searching for $CFG file"
if [ $IP ]; then BOOTDEV=network; CFGDEV=/mnt/nfs
for x in `lspci | grep 0200: | cut -d: -f3-4 | sed s/:/.*/g | tr a-z A-Z`; do modprobe `grep $x /lib/modules/$(uname -r)/modules.alias | tail -n1 | rev | cut -d" " -f1 | rev` 2>/dev/null; done
ls /sys/class/net | grep -q eth || { for x in `find /lib/modules/$(uname -r)/kernel/drivers/net -name "*.ko" | sed 's/.ko//g'`; do modprobe `basename $x` 2>/dev/null; ls /sys/class/net | grep -q eth && break || modprobe -r `basename $x` 2>/dev/null; done; }
mkdir -p /mnt/nfs/porteus /mnt/nfs/storage; udhcpc; modprobe nfsv4; mount -t nfs4 $IP:/srv/pxe/porteus /mnt/nfs/porteus -o ro,nolock 2>/dev/null || { modprobe nfsv3; mount -t nfs $IP:/srv/pxe/porteus /mnt/nfs/porteus -o ro,nolock 2>/dev/null; }
MAC=`ifconfig | grep eth0 | cut -d: -f5-7 | sed s/://g | cut -d" " -f1`
if [ "$CHANGES" = /srv/pxe/storage ]; then
if lsmod | grep -q nfsv3; then
mount -t nfs $IP:/srv/pxe/storage /mnt/nfs/storage -o rw,nolock 2>/dev/null && { mkdir -p /mnt/nfs/storage/client-$MAC/changes/home; CHANGES="/storage/client-$MAC"; }
else
mount -t nfs4 $IP:/srv/pxe/storage /mnt/nfs/storage -o rw,nolock 2>/dev/null && { mkdir -p /mnt/nfs/storage/client-$MAC/changes/home; CHANGES="/storage/client-$MAC"; }
fi
fi
elif [ $ISO ]; then CFGDEV=/mnt/isoloop
locate -e $FROM && { BOOTDEV=/mnt/$DEV; mkdir /mnt/isoloop; mount -o loop /mnt/$DEV/$LPTH /mnt/isoloop; ISOSRC=/mnt/$DEV/$LPTH; }
else
if [ $FROM ]; then
locate -e $FROM/porteus/$CFG
if [ $? -eq 0 ]; then
DIR=`echo $LPTH | rev | cut -d/ -f3- | rev`; [ $DIR ] && FOLDER=$DIR/porteus
else
echo -e "${YELLOW}from= cheatcode is incorrect, press enter to search through all devices${RST}"
read -s; search -e porteus/$CFG
fi
else
search -e porteus/$CFG || lazy -e porteus/$CFG
fi
CFGDEV=/mnt/$DEV
fi
[ -e $CFGDEV/$FOLDER/$CFG ] && PTH=$CFGDEV/$FOLDER || . fatal
# Set some variables to export as environment variables
DELAY=`value delay`; [ $DELAY ] && { echo $i"delaying $DELAY sec (waiting for slow devices to settle)"; sleep $DELAY; }
BOOTDEV=$CFGDEV
MODDIR=$PTH/modules
BASEDIR=${PTH%/*}
PORTDIR=$PTH
PORTCFG=$CFGDEV/$FOLDER/$CFG
echo $i"using Porteus data from $PTH"
# Make all drivers available:
mount -o loop $PTH/base/000-kernel.xzm /opt/000-kernel 2>/dev/null
mount -o bind /opt/000-kernel/lib/modules /lib/modules 2>/dev/null
# Create symlinks used often by porteus scripts:
if [ $CFGDEV = /mnt/nfs -o $CFGDEV = /mnt/isoloop ];then
ln -sf /mnt/live$PTH/modules /porteus/modules
ln -sf /mnt/live$PTH/optional /porteus/optional
else
ln -sf $PTH/modules /porteus/modules
ln -sf $PTH/optional /porteus/optional
fi
debug
# Setup changes:
if [ $CHANGES ]; then
echo $i"setting up directory for changes"
CHNEXIT=`echo $CHANGES | cut -d: -f1`; [ $CHNEXIT = EXIT ] && CHANGES=`echo $CHANGES | cut -d: -f2-`
[ -r $CFGDEV/$CHANGES ] && { DEV=`echo $CFGDEV | sed s@/mnt/@@`; LPTH=$CHANGES; } || locate -r $CHANGES
if [ $? -eq 0 ]; then
if [ -d /mnt/$DEV/$LPTH ]; then
mkdir -p /mnt/$DEV/$LPTH/changes 2>/dev/null && \
mount -o bind /mnt/$DEV/$LPTH/changes /memory/changes && touch /memory/changes/._test1 2>/dev/null
else
if blkid /mnt/$DEV/$LPTH 2>/dev/null | cut -d" " -f3- | grep -q _LUKS; then
for x in dm_crypt cryptd cbc sha256_generic aes_generic aes_x86_64; do modprobe $x 2>/dev/null; done
losetup /dev/loop2 /mnt/$DEV/$LPTH
echo $i"found encrypted .dat container"
/opt/000-kernel/sbin/cryptsetup luksOpen /dev/loop2 crypt
fsck_dat /dev/mapper/crypt
mount /dev/mapper/crypt /memory/changes 2>/dev/null && touch /memory/changes/._test1 2>/dev/null
else
fsck_dat /mnt/$DEV/$LPTH
mount -o loop /mnt/$DEV/$LPTH /memory/changes 2>/dev/null && touch /memory/changes/._test1 2>/dev/null
fi
fi
if [ $? -eq 0 ]; then
echo $i"testing filesystem on "$CHANGES" for posix compatibility"
ln -s /memory/changes/._test1 /memory/changes/._test2 2>/dev/null && chmod +x /memory/changes/._test1 2>/dev/null && [ -x /memory/changes/._test1 ] && chmod -x /memory/changes/._test1 2>/dev/null && [ ! -x /memory/changes/._test1 ] && rm -f /memory/changes/._test1 /memory/changes/._test2
if [ $? -ne 0 ]; then
rm -f /memory/changes/._test1 /memory/changes/._test2; umount /memory/changes
echo && echo -e "[1;33m""A Windows filesystem (FAT, NTFS) or other non-posix compatible filesystem\nhas been detected on $CHANGES.\nYour changes cannot be saved directly to the specified storage media with this\nsetup. Please use the '[1;36mPorteus save file manager[1;33m' to create a .dat container\nand use it for saving your changes after your next reboot.""[0m"
echo "boot will continue in '[1;36mAlways Fresh[0m' mode for this session"
sleep 10; CHGERR=1; rmdir /mnt/$DEV/$LPTH/changes; fail_chn
else
echo $i"filesystem is posix compatible"; CHNDEV=/mnt/$DEV
rmdir /memory/changes/mnt/* 2>/dev/null
rm -rf /memory/changes/var/lock/* /var/run/laptop-mode-tools/* /var/spool/cron/cron.??????
for x in `find /memory/changes/var/run -name "*pid" 2>/dev/null`; do rm $x; done
if [ $CHNEXIT = EXIT -o "`egrep -o " changes-ro( |\$)" /proc/cmdline`" ]; then
CHNEXIT=$CHNDEV/$LPTH; echo $CHNEXIT >/tmp/changes-exit
param changes-ro && echo $i"[1;36m""changes will not be saved for this session""[0m" || echo $i"[1;36m""changes will be saved only during reboot/shutdown""[0m"
for x in `find /memory/changes -name ".wh.*" | grep -v '.wh..wh..opq' | tr ' ' '@' `; do x=`echo $x | tr '@' ' ' `; cp -a --parents "$x" /var; done
umount /memory/changes; mount -nt tmpfs -o size=$RAMSIZE tmpfs /memory/changes
## should not be needed with new busybox ## need to fix busybox bug on 'cp -a' as it does not preserve perms on dirs:
mv /var/memory/changes/* /memory/changes 2>/dev/null; CHANGES=memory
#chown -R guest /memory/changes/home/guest 2>/dev/null
fi
fi
else
echo $i"changes not writable, using memory instead"; CHGERR=2; umount /memory/changes 2>/dev/null; fail_chn
fi
else
CHGERR=3; fail $CHANGES; fail_chn
fi
else
echo $i"changes cheatcode not found, using memory only"; fail_chn
fi
mkdir -p /memory/changes/mnt/live
debug
# Setup aufs:
echo $i"creating live filesystem and inserting modules"
mount -t aufs -o nowarn_perm,xino=/memory/xino/.aufs.xino,br:/memory/changes=rw aufs /union
if [ $? -ne 0 ]; then echo -e "[31m""cant setup union (aufs) - read only filesystem?\nWhen you finish debugging press Ctrl+Alt+Del to reboot.""[0m"; sh; fi
# Check for base modules update
if [ -d $CFGDEV/$FOLDER/updates ]; then
echo $i"[1;36m""Base updates detected ...""[0m"
# Check if user has booted over network or from ISO
if [ $ISO ]||[ $IP ]||[ "$CFGDEV" = /mnt/isoloop ]; then
echo $i"Booting from ISO or network detected. Skipping updates ..."
else
if is_writable $CFGDEV/$FOLDER/base; then
echo $i"Copying base updates ... please wait"
basemods=`ls -1 $CFGDEV/$FOLDER/updates | grep "^00[1-3]-[a-z|A-Z]"`
for x in $basemods; do
echo "Copying: $x to $CFGDEV/$FOLDER/porteus/"
cp $CFGDEV/$FOLDER/updates/$x $CFGDEV/$FOLDER/base/ 2>/dev/null
rm $CFGDEV/$FOLDER/updates/$x
done
## Allow time slow devices?
echo "Pausing, to allow the dust to settle.. please wait"
sleep 10
rm -rf $CFGDEV/$FOLDER/updates && echo "Removed updates folder" || echo "Could not remove updates folder"
else
echo $i"Non writable media. Skipping updates ..."
fi
fi
fi
# Find modules:
find $PTH/base $PTH/modules -name "*.xzm" 2>/dev/null | egrep -ve "$NOLOAD" | sort >/tmp/modules
find $PTH/optional -name "*.xzm" 2>/dev/null | egrep -e "$LOAD" | sort >>/tmp/modules
if param vga_detect; then
echo $i"detecting GPU"
lspci >/tmp/lspci; nv=`grep "0300: 10de:" /tmp/lspci | cut -d":" -f4`; amd=`grep "0300: 1002:" /tmp/lspci | cut -d":" -f4`
if [ $nv ]; then
echo $i"$nv chipset found, checking which nvidia driver supports it"
cd /usr/share/pciids/NVIDIA; NV=`grep $nv * | cut -d: -f1`; cd /
if [ $NV ]; then
echo $i"nvidia-$NV.xx driver will be activated -"
echo $i"if present in $PTH/optional folder"
find $PTH/optional -name "nvidia-$NV*" 2>/dev/null >>/tmp/modules
else
echo $i"latest nvidia driver will be activated -"
echo $i"if present in $PTH/optional folder"
find $PTH/optional -name "nvidia-*" 2>/dev/null | egrep -v '96.43.|173.14.|304.' >>/tmp/modules
fi
elif [ $amd ]; then
echo $i"checking if $amd GPU belongs to 'Radeon HD' series"
cd /usr/share/pciids/AMD; HD=`grep $amd * | cut -d: -f1`; cd /
if [ $HD ]; then
echo $i"$HD-xx driver will be activated -"
echo $i"if present in $PTH/optional folder"
find $PTH/optional -name "$HD-*" 2>/dev/null >>/tmp/modules
else
echo $i"$amd GPU is not supported by amd-catalyst driver - refusing activation"
fi
else
echo $i"could not find any nVidia/AMD GPU on this PC"
fi
fi
if param base_only; then
grep base/0 /tmp/modules > /tmp/mod
mv /tmp/mod /tmp/modules
else
if [ "$EXTRAMOD" ]; then
for folder in $EXTRAMOD; do
echo $i"searching for additional modules in $folder"
locate -d $folder && { find /mnt/$DEV/$LPTH -name "*.xzm" 2>/dev/null | egrep -ve "$NOLOAD" | sort >>/tmp/modules; } || fail $folder
done
fi
fi
# Copy data to RAM:
if param copy2ram; then
echo $i"copying Porteus data to RAM, this may take some time..."
[ $RAMMOD ] && { egrep -e "$RAMMOD" /tmp/modules > /tmp/rammod; cpmod /tmp/rammod; } || cpmod /tmp/modules
fi
# Populate aufs with modules:
umount /lib/modules /opt/000-kernel 2>/dev/null
while read line; do
NAME=`basename "$line"`
mkdir /memory/images/"$NAME"
mount -o loop "$line" /memory/images/"$NAME" 2>/dev/null
if [ $? -eq 0 ]; then
echo " $m $NAME"; mount -no remount,add=1:/memory/images/"$NAME"=rr aufs /union
else
echo $i"[1;36m""Cannot read $NAME - corrupted module?""[0m"; rmdir /memory/images/"$NAME"
fi
done < /tmp/modules
mount -no bind /union/lib/modules /lib/modules 2>/dev/null
# Add "changes on exit" device/file/folder:
if [ -e /tmp/changes-exit ]; then
mkdir /memory/images/changes
if [ -d $CHNEXIT ]; then
mount -o bind $CHNEXIT/changes /memory/images/changes
elif [ -b /dev/mapper/crypt ]; then
mount /dev/mapper/crypt /memory/images/changes
else
mount -o loop $CHNEXIT /memory/images/changes
fi
echo " $m changes"; mount -no remount,add=1:/memory/images/changes=ro aufs /union
echo $CHNEXIT/changes >>/tmp/modules
param changes-ro && rm /tmp/changes-exit
fi
debug
# Copy /rootcopy folder:
if param norootcopy; then
ROOTCOPY=none
echo $i"skipping /rootcopy directory"
else
if [ $ROOTCOPY ]; then
locate -d $ROOTCOPY
if [ $? -eq 0 ]; then echo $i"copying content of $ROOTCOPY directory"; cp -af /mnt/$DEV/$LPTH/. /union/. 2>/dev/null; else fail $ROOTCOPY; ROOTCOPY=none; fi
else
ROOTCOPY=none
echo $i"copying content of $PTH/rootcopy directory"
cp -af $PTH/rootcopy/. /union/. 2>/dev/null
fi
fi
uep=/union/etc/profile.d
uepp=$uep/porteus.sh
[ ! -d $uep ] && mkdir -p $uep
#[ ! `grep -o "DISTRO=" $uepp >/dev/null 2>&1` ] && echo "export DISTRO=porteus" >> $uepp
if [ -e $uepp ]; then
sed -i '/DISTRO/d' $uepp
sed -i '/BOOTDEV/d' $uepp
sed -i '/BASEDIR/d' $uepp
sed -i '/PORTDIR/d' $uepp
sed -i '/MODDIR/d' $uepp
sed -i '/CHGERR/d' $uepp
sed -i '/PORTCFG/d' $uepp
fi
echo "export DISTRO=porteus" >> $uepp
echo "export BOOTDEV=$CFGDEV" >> $uepp
echo "export BASEDIR=${PTH%/*}" >> $uepp
echo "export PORTDIR=$PTH" >> $uepp
echo "export MODDIR=$MODDIR" >> $uepp
echo "export PORTCFG=$PORTCFG" >> $uepp
if [ $CHGERR ]; then echo "export CHGERR=$CHGERR" >> $uepp; fi
chmod +x $uepp
# Collect boot arguments
grep "^[aA0-zZ9]" $PORTCFG > /union/etc/bootcmd.cfg
cat /proc/cmdline | tr ' ' '\n' >> /union/etc/bootcmd.cfg
## Finish:
# Create 7 free loop devices for truecrypt, etc...
#x=`losetup | tail -n1 | cut -d: -f1 | sed 's@/dev/loop@@'`
x=`grep -oE 'loop[0-9]+$' /proc/partitions | tail -n1 | tr -d [:alpha:]`
let y=x+7
while [ $x -le $y ]; do [ -b /dev/loop$y ] && break || mknod /dev/loop$y b 7 $y; let y=y-1; done
if param nonetwork; then
echo $i"disabling dhcpcd and NetworkManager services"
chmod -x /union/etc/rc.d/rc.inet1 /union/etc/rc.d/rc.networkmanager 2>/dev/null
nma=/union/etc/xdg/autostart/nm-applet.desktop
test -e $nma && ! grep -q "Hidden=true" $nma && echo "Hidden=true" >> $nma
fi
if [ "$IP" -a -x /union/etc/rc.d/rc.networkmanager ]; then
#if [ -z "`egrep -o "copy2ram( |\$)" /proc/cmdline`" -o -d /mnt/nfs/storage/client-$MAC ]; then
if [ -z "`egrep -o "^copy2ram" /union/etc/bootcmd.cfg`" -o -d /mnt/nfs/storage/client-$MAC ]; then
echo "nameserver $IP" > /union/etc/resolv.conf
nmc=/union/etc/NetworkManager/NetworkManager.conf; HW=`ifconfig | grep eth0 | cut -dW -f2 | cut -d" " -f2`
! grep -q "unmanaged-devices=mac:$HW" $nmc && sed -i '/\[keyfile\]/ a\unmanaged-devices=mac:'$HW'' $nmc
fi
fi
# Start bluetooth if cheat exists
if param bluetooth; then
echo "Starting bluetooth ..."
[ -e /union/etc/rc.d/rc.bluetooth ] && chmod +x /union/etc/rc.d/rc.bluetooth
fi
cp -af /dev/console /union/dev
#cat > /union/etc/mtab << EOF
#aufs / aufs rw 0 0
#proc /proc proc rw 0 0
#sysfs /sys sysfs rw 0 0
#devtmpfs /dev devtmpfs rw 0 0
#devpts /dev/pts devpts rw,mode=0620,gid=5 0 0
#EOF
fstab
debug
#if param copy2ram; then
if chk_bootcfg copy2ram; then
echo $i"[1;36m""finished copying to RAM - booting media can be removed safely""[0m"
fi
# Create debug file:
[ -e /tmp/devices ] && { echo "# Recognized devices:" >$livedbg; cat /tmp/devices >>$livedbg; }
[ $BOOTDEV ] && CFGDEV=$BOOTDEV
echo -e "\n# Booting device:\n$CFGDEV\n\n# Porteus data found in:\n$PTH\n\n# Changes are stored in:\n$CHANGES\n\n# Non standard /rootcopy dir:\n$ROOTCOPY\n\n# Modules activated during boot time:" >>$livedbg; cat /tmp/modules >>$livedbg
echo -e "\n# Base module versions:" >>$livedbg; cat /union/etc/porteus/* /etc/porteus/* >>$livedbg
grep "^/mnt/isoloop" $livedbg && echo "" >> $livedbg && echo "ISO=$ISOSRC" >> $livedbg
#if [ $ISO ]; then
# [ -d /union/mnt/isoloop ] && rmdir /union/mnt/isoloop
# ln -sf /mnt/live/mnt/isoloop /union/mnt/isoloop
#fi
cp -af $livedbg /union/var/log/porteus-livedbg
## Check for text mode cheat code
chk_bootcfg 3 && export OPTS="3"
echo $i"changing root directory"
# Cleanup mount points at union/mnt for this session
for x in `ls -1 /union/mnt | grep -v "live"`; do
[ -d /union/mnt/$x ] && rmdir /union/mnt/$x # Will fail if dir not empty!
[ -L /union/mnt/$x ] && rm -f /union/mnt/$x
done
if chk_bootcfg noauto; then
for x in `grep /mnt/ /etc/fstab | cut -d/ -f3`; do mkdir -p /union/mnt/$x; umount -n /mnt/$x 2>/dev/null && rmdir /mnt/$x; done
else
#grep /mnt/ /etc/fstab >> /union/etc/mtab
for x in `grep /mnt/ /etc/fstab | cut -d/ -f3`; do mkdir -p /union/mnt/$x; mount -n --move /mnt/$x /union/mnt/$x; rmdir /mnt/$x; done
fi
sed -i 's/ ntfs / ntfs-3g /g' /etc/fstab
cp -f /etc/fstab /union/etc 2>/dev/null
# Add all symlinks of all mount points at /mnt to union
for x in `ls -1 /mnt`; do
[ -d /union/mnt/$x ] && rmdir /union/mnt/$x
ln -sf /mnt/live/mnt/$x /union/mnt/$x
done
cp -r /etc/porteus /union/etc 2>/dev/null
umount -n /lib/modules 2>/dev/null
rm -r /lib/* /usr/*
debug
echo "[1m""live system is ready now - starting Porteus""[0m"
cp -f /union/sbin/init /bin
if [ $? -eq 0 ]; then
pivot_root /union /union/mnt/live
exec bin/chroot . /mnt/live/bin/init "$@" $OPTS <dev/console >dev/console 2>&1
else
echo -e "[31m""!!ERROR!!\nSomething went wrong and I cannot continue.\nPress Ctrl+Alt+Del to reboot.""[0m"
sh
fi
Appendix 2: the full init script of SalixOS (extracted from initrd.gz)
#!/bin/ash
#Dimitris Tzemos <dijemos@gmail.com> (changes for salix)
# Eric Hameleers <alien@slackware.com> (encryption support)
LIVELABEL="LIVE" #edit in build-slackware-live.sh script too
#DISTRONAME="Salix-kde-15.0"
DISTRONAME="Salix-xfce-15.0"
#DISTRONAME="Salix-mate-15.0"
if [ ! -z "$medialabel" ]; then
LIVELABEL=$medialabel
fi
echo ""
echo "*** Live system initialization ***"
mount -v proc /proc -t proc
mount -v sysfs /sys -t sysfs
/load_kernel_modules 2>/dev/null
# Sometimes the devices need extra time to be available.
# A root filesystem on USB is a good example of that.
if [ ! -z "$wait" ]; then
sleep $wait
else
sleep 3
fi
# Fire at least one blkid:
#blkid 1>/dev/null 2>/dev/null
mdev -s
mkdir /tmp #fuse needs /tmp
mkdir /slroot
mount -o defaults -t tmpfs none /slroot #-o defaults: bug in busybox (options=0)
mkdir /slroot/live
mkdir /slroot/live/media
mediadetected="none"
if [ ! -z "$nfsroot" ]; then
mediadetected="nfs"
address=`echo $ip | cut -f1 -d:`
netmask=`echo $ip | cut -f4 -d:`
gateway=`echo $ip | cut -f3 -d:`
ifconfig eth0 $address netmask $netmask
route add default gw $gateway
mount -t nfs -o nolock $nfsroot /slroot/live/media
echo "$LIVELABEL found on $nfsroot"
else
sleeptime=0
while [ "$mediadetected" = "none" ] && [ "$sleeptime" != "10" ]; do #try each seconds, but don't wait (USB) more than 10 seconds
if blkid | grep -q "LABEL=\"$LIVELABEL\""; then
livedevice=`blkid | grep "LABEL=\"$LIVELABEL\"" | sed -n 1p | cut -f1 -d:`
echo "$DISTRONAME-Live found on $livedevice"
mount -o ro $livedevice /slroot/live/media
if blkid | grep "LABEL=\"$LIVELABEL\"" | sed -n 1p | grep -q "TYPE=\"iso9660\""
then mediadetected="cd"
else mediadetected="sd"
fi
else
sleep 1
let sleeptime+=1
mdev -s
fi
done
fi
if [ "$mediadetected" == "none" ]; then
echo "*** Live system error - live media not detected - exiting ***"
sh
fi
##copy live-media to RAM if requested
if [ "$copy2ram" = "yes" ]; then
echo -n "Copying live system to RAM ..."
mkdir /slroot/live/tmp
mount --move /slroot/live/media /slroot/live/tmp
mount -t tmpfs none /slroot/live/media
mkdir /slroot/live/media/boot
for bootfile in `find /slroot/live/tmp/boot -maxdepth 1 -type f`; do
cp $bootfile /slroot/live/media/boot/
done
cp -r /slroot/live/tmp/boot/syslinux /slroot/live/media/boot/
touch /slroot/live/media/boot/
mkdir /slroot/live/media/boot/modules
if [ `ls /slroot/live/tmp/boot/modules/ | wc -l` != 0 ]; then
for module in /slroot/live/tmp/boot/modules/*; do #first copy main non excluded modules
modulename=`basename $module`
if ! echo $exclude | sed 's/:/\n/g' | grep -q "^$modulename$"; then
cp /slroot/live/tmp/boot/modules/$modulename /slroot/live/media/boot/modules/
fi
done
fi
mkdir /slroot/live/media/boot/optional
for modulename in `echo $include | sed 's/:/ /g'`; do #copy included optional modules
if [ -f /slroot/live/tmp/boot/optional/$modulename ]; then
cp /slroot/live/tmp/boot/optional/$modulename /slroot/live/media/boot/optional/
fi
done
umount /slroot/live/tmp
rmdir /slroot/live/tmp
mount -o remount,ro /slroot/live/media
if [ "$mediadetected" = "cd" ]; then
eject $livedevice
fi
echo " done"
fi
#mount all modules in /live/modules/* except excluded ones
mkdir /slroot/live/modules
modulescount=0
if [ `ls /slroot/live/media/boot/modules/ | wc -l` != 0 ]; then
for module in /slroot/live/media/boot/modules/*; do
modulename=`basename $module`
if ! echo $exclude | sed 's/:/\n/g' | grep -q "^$modulename$"; then #if module is not excluded by bootparam
mkdir /slroot/live/modules/$modulename
mount -o loop -t squashfs $module /slroot/live/modules/$modulename
modulesbranches="/slroot/live/modules/$modulename=ro:$modulesbranches"
echo "Loading SquashFS module $modulename"
modulescount=$(($modulescount+1))
fi
done
fi
#load requested optional modules
for modulename in `echo $include | sed 's/:/ /g'`; do
if [ -f /slroot/live/media/boot/optional/$modulename ]; then
mkdir /slroot/live/modules/$modulename
mount -o loop -t squashfs /slroot/live/media/boot/optional/$modulename /slroot/live/modules/$modulename
modulesbranches="/slroot/live/modules/$modulename=ro:$modulesbranches"
echo "Loading SquashFS module $modulename"
modulescount=$(($modulescount+1))
fi
done
if [ $modulescount = 0 ]; then
echo -e "\nError: no modules has been loaded"
exec sh
fi
modulesbranches=`echo $modulesbranches | sed 's/:$//'`
unionfsmodulesbranches=`echo $modulesbranches | sed 's/\/slroot//g'` #TODO: Unionfs-
overlaymodulesbranches=`echo $modulesbranches | sed 's/=ro//g'`
#mount (union) all modules in /live/system (ro)
mkdir /slroot/live/system
if [ $modulescount = 1 ]
then mount --bind $overlaymodulesbranches /slroot/live/system
else mount -t overlay -o ro,lowerdir=$overlaymodulesbranches overlay /slroot/live/system 2>/dev/null ||
unionfs -o ro,allow_other,suid,dev,use_ino,cow,max_files=524288,chroot=/slroot $unionfsmodulesbranches /slroot/live/system #TODO - (required for NFS)
fi
find_loop() {
# The losetup of busybox is different from the real losetup - watch out!
lodev=$(losetup -f)
if [ -z "$lodev" ]; then
# We exhausted the available loop devices, so create the block device:
for NOD in $(seq 0 ${MAXLOOPS}); do
if [ ! -b /dev/loop${NOD} ]; then
mknod -m660 /dev/loop${NOD} b 7 ${NOD}
break
fi
done
lodev=/dev/loop${NOD}
elif [ ! -b $lodev ]; then
# We exhausted the available loop devices, so create the block device:
mknod -m660 $lodev b 7 $(echo $lodev |sed %/dev/loop%%)
fi
echo "$lodev"
}
#setup persistent system changes
if [ ! -z "$changes" ] && [ ! "$copy2ram" == "yes" ] && [ "$mediadetected" != "cd" ]; then
echo "Using persistent system storage ($changes)"
if [ "$mediadetected" == "sd" ]; then
mkdir -p /slroot/live/$changes
if echo $changes | grep -q "="; then
filesize=`echo "$changes" | cut -f2 -d=`
changes=`echo "$changes" | cut -f1 -d=`
fi
if [ ! -d /slroot/live/media/$changes ] && [ ! -f /slroot/live/media/$changes ]; then #storage space creation
#if [ ! -z "$filesize" ]; then
# echo "Creating $changes ($filesize MB) persistent system storage ..."
# dd if=/dev/zero of=/slroot/live/media/$changes bs=1024k count=0 seek=$filesize #TODO: check available space
# sleep 1
# mkfs.ext3 -F /slroot/live/media/$changes
# sleep 1
#else
if mount | grep -q "$livedevice on /slroot/live/media type ext3"; then #TODO: check FS type
echo "mount $livedevice on /slroot/live/media type ext3"
mount -o remount,rw /slroot/live/media
mkdir -p /slroot/live/media/$changes
fi
#fi
fi
if [ -f /slroot/live/media/$changes ]; then ## setup persistent file
mount -o remount,rw /slroot/live/media
## add these here for persistent
# Find a free loop device to mount the persistence container file:
prdev=$(find_loop)
losetup $prdev /slroot/live/media/$changes
# Check if the persistence container is LUKS encrypted:
if cryptsetup isLuks $prdev 1>/dev/null 2>/dev/null ; then
echo "Unlocking LUKS encrypted persistence file '/${changes}'"
cryptsetup luksOpen $prdev $(basename ${changes}) </dev/tty0 >/dev/tty0 2>&1
if [ $? -ne 0 ]; then
echo "${DISTRONAME}: Failed to unlock persistence file '/${changes}'."
echo "${DISTRONAME}: Falling back to RAM."
else
# LUKS properly unlocked; from now on use the mapper device instead:
prdev=/dev/mapper/$(basename ${changes})
fi
fi
prfs=$(blkid $prdev |rev |cut -d'"' -f2 |rev)
mount -t $prfs $prdev /slroot/live/$changes 2>/dev/null
##
#mount -o loop /slroot/live/media/$changes /slroot/live/$changes
fi
if [ -d /slroot/live/media/$changes ]; then ## setup persistent folder only for ext3,4 usb filesystem
mount -o remount,rw /slroot/live/media
mount --bind /slroot/live/media/$changes /slroot/live/$changes
fi
else
echo "Using persistent system storage ($changes)"
mkdir -p /slroot/live/$changes
mount -t nfs -o nolock $changes /slroot/live/$changes #TODO: no auth / security
fi
fi
#mount (union) all modules (ro) and /live/changes (rw) in /live/union (rw)
if [ ! -z "$changes" ]; then
UPPERDIR=/slroot/live/$changes/changes
WORKOVLDIR=/slroot/live/$changes/ofswd
else
UPPERDIR=/slroot/live/changes
WORKOVLDIR=/slroot/live/ofswd
fi
mkdir -p /slroot/live/union
[ ! -d ${UPPERDIR} ] && mkdir -p ${UPPERDIR}
[ ! -d ${WORKOVLDIR} ] && mkdir -p ${WORKOVLDIR}
mount -t overlay -o workdir=${WORKOVLDIR},upperdir=${UPPERDIR},lowerdir=$overlaymodulesbranches overlay /slroot/live/union 2>/dev/null ||
unionfs -o allow_other,suid,dev,use_ino,cow,max_files=524288,chroot=/slroot /live/changes=rw:$unionfsmodulesbranches /slroot/live/union #TODO - (required for NFS)
#setup system tree
for directory in /slroot/live/union/*; do #bind /live/union top directories into /
directoryname=`basename $directory`
mkdir /slroot/$directoryname
mount --bind $directory /slroot/$directoryname
done
mkdir -p /slroot/tmp
mkdir -p /slroot/sys
mkdir -p /slroot/proc
mkdir -p /slroot/dev
mknod /slroot/dev/console c 5 1 2>/dev/null
mknod /slroot/dev/null c 1 3 2>/dev/null #needed to mount /proc (rc.S) on read-only filesystem
cat > /slroot/live/union/etc/fstab << END
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults,nodev,nosuid,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,nodev,nosuid,mode=1777 0 0
tmpfs /dev/shm tmpfs defaults,nodev,nosuid,mode=1777 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
none / tmpfs defaults 1 1
END
#system startup tweaking
if [ ! -z "$changes" ]; then
#cp -f /slroot/live/system/etc/rc.d/rc.S /slroot/live/union/etc/rc.d/
#cp -f /slroot/live/system/etc/rc.d/rc.M /slroot/live/union/etc/rc.d/
#cp -f /slroot/live/system/etc/rc.d/rc.modules /slroot/live/union/etc/rc.d/
rm -f /slroot/live/union/etc/udev/rules.d/70-persistent-net.rules
fi
touch /slroot/live/union/etc/fastboot
# Disable the root filesystem check altogether:
sed -i -e '/^if \[ ! \$READWRITE = yes/,/^fi # Done checking root filesystem/s/^/#/' /slroot/live/union/etc/rc.d/rc.S
echo "cat /proc/mounts | grep -v '^rootfs' > /etc/mtab" >> /slroot/live/union/etc/rc.d/rc.S #update /etc/mtab
echo "mount -o remount,rw /live/media" >> /slroot/live/union/etc/rc.d/rc.S
if [ "$fastboot" = "yes" ]; then #faster startup (actions already done by "build-slackware-live.sh --sysprep")
echo "Enabling fast boot"
sed -e 's@^\( */usr/bin/fc-cache.*\)$@: #\1@' \
-e 's@^\( */bin/sh /etc/rc.d/rc.udev\)$@: #\1@' \
-e 's@^\( */usr/bin/gtk-update.*\)$@: #\1@' \
-e 's@^\( */usr/bin/update-gdk.*\)$@: #\1@' \
-e 's@^\( */usr/bin/update-gtk.*\)$@: #\1@' \
-e 's@^\( */usr/bin/update-mime-database.*\)$@: #\1@' \
-e 's@^\( */usr/bin/update-pango.*\)$@: #\1@' \
-e 's@^\( */usr/bin/glib-compile-schemas.*\)$@: #\1@' \
-e 's@^\( */sbin/ldconfig.*\)$@: #\1@' \
-i /slroot/live/union/etc/rc.d/rc.M
sed -e 's@^\( */sbin/depmod.*\)$@: #\1@' \
-i /slroot/live/union/etc/rc.d/rc.modules
fi
if [ "$mediadetected" = "nfs" ] && [ -x /slroot/live/union/etc/rc.d/rc.networkmanager ]; then
chmod -x /slroot/live/union/etc/rc.d/rc.networkmanager #if enabled, system hangs
elif ! [ -x /slroot/live/union/etc/rc.d/rc.wicd -a -x /slroot/live/union/usr/sbin/wicd ]; then
chmod +x /slroot/live/union/etc/rc.d/rc.networkmanager
fi
#system shutdown tweaking
#if [ ! -z "$changes" ]; then
#cp -f /slroot/live/system/etc/rc.d/rc.6 /slroot/live/union/etc/rc.d/
#fi
sed -i 's/\(\/rc.[06]\)\( fast\)*/\1 fast/' /slroot/live/union/etc/inittab #to prevent system hang at shutdown
sed -e 's@^\( *\)\([a-z/]*sleep.*\)@\1: #\2@' \
-e 's@^\( *\)\([a-z/]*sync\)@\1: #\2@' \
-e 's@^\(.*umount.*\)$@\1 \>/dev/null 2\>\&1@' \
-i /slroot/live/union/etc/rc.d/rc.6
sed -e 's@^\(.*umount -v -a -t no,proc,sysfs.*\)$@umount -v -a -t no,overlay,unionfs,proc,sysfs \>/dev/null 2\>\&1@' -i /slroot/live/union/etc/rc.d/rc.6
sed -e 's@^\(.*umount -v -a -l -f -r -t nfs,smbfs,cifs.*\)$@umount -v -a -l -f -r -t nfs,smbfs,cifs \>/dev/null 2\>\&1@' -i /slroot/live/union/etc/rc.d/rc.6
sed -e 's@^\(.*umount -v -a -t no,proc,sysfs.*\)$@umount -v -a -t no,proc,sysfs \>/dev/null 2\>\&1@' -i /slroot/live/union/etc/rc.d/rc.6
if [ -z "$changes" ]
then sed -e 's@^\(.*-o remount.*\)$@/bin/mount -o remount,ro /live/media \>/dev/null 2\>\&1 #\1\n/bin/sync\n/bin/sleep 3@' -i /slroot/live/union/etc/rc.d/rc.6
else sed -e 's@^\(.*-o remount.*\)$@/bin/mount -o remount,ro /live/media \>/dev/null 2\>\&1\nmount -o remount,ro /live/changes \>/dev/null 2\>\&1 #\1\nsync; sleep 3@' \
-i /slroot/live/union/etc/rc.d/rc.6
fi
if [ "$mediadetected" = "nfs" ]; then
sed -e 's@^\( *\)\([a-z/]*fuser.*\)@\1: #\2@' \
-e 's@^\( *\)\([a-z/]*dhcpcd -k.*\)@\1: #\2@' \
-e 's@^\( *\)\(\. /etc/rc\.d/rc\.inet1 stop\)@\1: #\2@' \
-e 's@-t \(nfs,\)\(.*\)@-t \2 #\1@' \
-i /slroot/live/union/etc/rc.d/rc.6
fi
if [ "$mediadetected" = "cd" ] && [ ! "$copy2ram" = "yes" ]; then
sed -e "s@\(/sbin/reboot\)@reboot -w; shutdown -k now \>/dev/null\n cdrecord --eject dev=$livedevice \>/dev/null 2\>\&1\n sleep 5\n \1@" \
-e "s@\(/sbin/poweroff\)@poweroff -w; shutdown -k now \>/dev/null\n cdrecord --eject dev=$livedevice \>/dev/null 2\>\&1\n sleep 5\n \1@" \
-i /slroot/live/union/etc/rc.d/rc.6
fi
#setup persistent homedir
if [ ! -z "$home" ] && [ ! "$copy2ram" == "yes" ] && [ "$mediadetected" != "cd" ]; then
echo "Setting up persistent home directory ($home)"
uid=1000
if [ -z "`grep "^[^:]\+:x:$uid:" /slroot/live/union/etc/passwd | cut -f1 -d:`" ]; then
uid=0
fi
homedir=`grep "x:$uid:" /slroot/live/union/etc/passwd | cut -f6 -d:`
gid=`grep "x:$uid:" /slroot/live/union/etc/passwd | cut -f4 -d:`
if [ "$mediadetected" == "sd" ]; then
if echo $home | grep -q "="; then
filesize=`echo "$home" | cut -f2 -d=`
home=`echo "$home" | cut -f1 -d=`
fi
if [ ! -d /slroot/live/media/$home ] && [ ! -f /slroot/live/media/$home ]; then #storage space creation
#if [ ! -z "$filesize" ]; then
# echo "Creating $home ($filesize MB) persistent home directory ..."
# dd if=/dev/zero of=/slroot/live/media/$home bs=1024k count=0 seek=$filesize #TODO: check available space
# sleep 1
# mkfs.ext3 -F /slroot/live/media/$home
# sleep 1
# mount -o loop /slroot/live/media/$home /slroot/$homedir
# cp -dpR /slroot/live/union/etc/skel/.??* /slroot/$homedir/
# cp -dpR /slroot/live/union/etc/skel/* /slroot/$homedir/
# chown -R $uid:$gid /slroot/$homedir
# umount /slroot/$homedir
#else
if mount | grep -q "$livedevice on /slroot/live/media type ext3"; then #TODO: check FS type (vfat not supported)
mount -o remount,rw /slroot/live/media
mkdir -p /slroot/live/media/$home
cp -dpR /slroot/live/union/etc/skel/.??* /slroot/live/media/$home/
cp -dpR /slroot/live/union/etc/skel/* /slroot/live/media/$home/
cp /slroot/live/union/$homedir/Desktop/* /slroot/live/media/$home/Desktop
chown -R $uid:$gid /slroot/live/media/$home
fi
#fi
fi
if [ -f /slroot/live/media/$home ]; then # home directory in persistent file
mount -o remount,rw /slroot/live/media
## add these here for persistent
# Find a free loop device to mount the persistence container file:
prdev=$(find_loop)
losetup $prdev /slroot/live/media/$home
# Check if the persistence container is LUKS encrypted:
if cryptsetup isLuks $prdev 1>/dev/null 2>/dev/null ; then
echo "Unlocking LUKS encrypted persistence file '/${changes}'"
cryptsetup luksOpen $prdev $(basename ${home}) </dev/tty0 >/dev/tty0 2>&1
if [ $? -ne 0 ]; then
echo "${DISTRONAME}: Failed to unlock persistence file '/${changes}'."
echo "${DISTRONAME}: Falling back to RAM."
else
# LUKS properly unlocked; from now on use the mapper device instead:
prdev=/dev/mapper/$(basename ${home})
fi
fi
prfs=$(blkid $prdev |rev |cut -d'"' -f2 |rev)
mount -t $prfs $prdev /slroot/$homedir 2>/dev/null
if [ ! -f /slroot/$homedir/.xinitrc ]; then
cp -dpR /slroot/live/union/etc/skel/.??* /slroot/$homedir/
cp -dpR /slroot/live/union/etc/skel/* /slroot/$homedir
cp /slroot/live/union/$homedir/Desktop/* /slroot/$homedir/Desktop
chown -R $uid:$gid /slroot/$homedir
fi
##
#mount -o loop /slroot/live/media/$home /slroot/live/media/$homedir
fi
if [ -d /slroot/live/media/$home ]; then # persistent home directory
mount -o remount,rw /slroot/live/media
mkdir -p /slroot/live/media/$home
mount --bind /slroot/live/media/$home /slroot/$homedir
fi
else
echo "Setting up persistent home directory ($home)"
mount -t nfs -o nolock $home /slroot/$homedir #TODO: no auth / security
fi
fi
#runlevel boot parameter handling
if [ ! -z "$runlevel" ]; then
echo "Setting up runlevel ($runlevel)"
sed -i s/^id:[1-5]:initdefault:$/id:$runlevel:initdefault:/ /slroot/live/union/etc/inittab
fi
#autologin (runlevel 5)
runlevel=`cat /slroot/live/union/etc/inittab | sed -n /^id:[1-5]:initdefault:$/p | cut -f2 -d:`
if [ $runlevel = 5 ]; then
login=`cat /slroot/live/union/etc/passwd | grep ":1000:" | cut -f1 -d:`
if [ -z "$login" ]; then login="root"; fi
echo "Setting up autologin (login=$login)"
sed -i "s/^c1:.*$/c1:5:respawn:\/sbin\/agetty -a $login 38400 tty1 linux/" /slroot/live/union/etc/inittab
if [ -x /slroot/live/union/usr/bin/startx ]; then
cat > /slroot/live/union/etc/profile.d/x.sh << END
if [ -z "\$DISPLAY" ] && [ "\`id -u\`" != "0" ] && [ "\`tty\`" = "/dev/tty1" ]; then
startx
logout
fi
END
chmod +x /slroot/live/union/etc/profile.d/x.sh
fi
fi
#system i18n setup
if [ ! -z "$locale" ]; then
echo "Setting up locale ($locale)"
if [ -f /slroot/live/union/etc/profile.d/lang.sh ] && grep -q "^export LANG=" /slroot/live/union/etc/profile.d/lang.sh
then sed -i s/^export\ LANG=.*/export\ LANG=$locale/ /slroot/live/union/etc/profile.d/lang.sh
else echo "export LANG=$locale" >> /slroot/live/union/etc/profile.d/lang.sh
fi
if [ -f /slroot/live/union/etc/kde/kdm/kdmrc ]; then
locale_noutf8=$(echo $locale | sed 's/\.utf8//')
sed -i "s/\(^\|^#\)Language=.*/Language=$locale_noutf8/" /slroot/live/union/etc/kde/kdm/kdmrc
fi
LIBSUFFIX=
[ -d /slroot/live/union/usr/lib64 ] && LIBSUFFIX=64
# Make firefox match OS locale
# Now included in $DISTRONAME version, but keep it for other Slackware version or distro
#if [ -w /slroot/live/union/usr/lib$LIBSUFFIX/firefox/greprefs/all.js ]; then
# sed -i -e 's/pref("intl.locale.matchOS", false);/pref("intl.locale.matchOS", true);/g' /slroot/live/union/usr/lib$LIBSUFFIX/firefox/greprefs/all.js
#fi
if [ -w /slroot/live/union/usr/lib$LIBSUFFIX/firefox-*/defaults/pref/langpacks.js ]; then
sed -i -e 's/pref("intl.locale.matchOS", false);/pref("intl.locale.matchOS", true);/g' /slroot/live/union/usr/lib$LIBSUFFIX/firefox-*/defaults/pref/langpacks.js
fi
# Make thunderbird match OS locale
# Now included in $DISTRONAME version, but keep it for other Slackware version or distro
#if [ -w /slroot/live/union/usr/lib$LIBSUFFIX/thunderbird/greprefs/all.js ]; then
# sed -i -e 's/pref("intl.locale.matchOS", false);/pref("intl.locale.matchOS", true);/g' /slroot/live/union/usr/lib$LIBSUFFIX/thunderbird/greprefs/all.js
#fi
if [ -w /slroot/live/union/usr/lib$LIBSUFFIX/thunderbird-*/defaults/pref/langpacks.js ]; then
sed -i -e 's/pref("intl.locale.matchOS", false);/pref("intl.locale.matchOS", true);/g' /slroot/live/union/usr/lib$LIBSUFFIX/thunderbird-*/defaults/pref/langpacks.js
fi
fi
if [ ! -z "$keymap" ]; then
keyb=$keymap
if [ -n "$keyb" ] || [-n "$numlock" ] || [ -n "$scim" ] || [ -n "$ibus" ]; then
# keyboard settting
[ -n "$keyb" ] || keyb=us
[ -n "$numlock" ] || numlock=off
[ -n "$scim" ] || scim=off
[ -n "$ibus" ] || ibus=off
grep "^$keyb|.*|.*|.*" /keymaps | sed -e "s/^.*|\(.*\)|\(.*\)|\(.*\)/\1|\2|\3/" > /slroot/live/union/tmp/xkb
xkblayout="$(sed -e "s/^\(.*\)|.*|.*/\1/" /slroot/live/union/tmp/xkb)"
xkbvariant="$(sed -e "s/^.*|\(.*\)|.*/\1/" /slroot/live/union/tmp/xkb)"
xkboptions="$(sed -e "s/^.*|.*|\(.*\)/\1/" /slroot/live/union/tmp/xkb)"
rm /slroot/live/union/tmp/xkb
# Fall back to keymap if no xkb maping available
if [ -z "$xkblayout" ]; then
xkblayout="$keyb"
xkbvariant=""
xkboptions=""
fi
/usr/bin/loadkeys -u $keyb.map 1>&2 2>/dev/null
if [ -e /slroot/live/union/etc/rc.d/rc.keymap ]; then
sed -i "s/\(^[ \t]*\/usr\/bin\/loadkeys -u\).*$/\1 $keyb.map/" /slroot/live/union/etc/rc.d/rc.keymap
fi
if [ -e /slroot/live/union/etc/X11/xorg.conf.d ]; then
cat <<EOF > /slroot/live/union/etc/X11/xorg.conf.d/10-keymap.conf
Section "InputClass"
Identifier "Keyboard settings"
MatchIsKeyboard "yes"
Driver "evdev"
Option "XkbLayout" "$xkblayout"
Option "XkbVariant" "$xkbvariant"
Option "XkbOptions" "$xkboptions"
EndSection
EOF
fi
fi
fi
if [ ! -z "$tz" ]; then
if [ -f /slroot/usr/share/zoneinfo/$tz ]; then
#cat /slroot/usr/share/zoneinfo/$tz > /slroot/etc/localtime
ln -sf /usr/share/zoneinfo/$tz /slroot/etc/localtime
ln -sf /usr/share/zoneinfo/$tz /slroot/etc/localtime-copied-from
fi
fi
if [ ! -z "$hwc" ]; then
if [ "$hwc" == "UTC" ] || [ "$hwc" == "localtime" ]; then
echo "$hwc" > /slroot/etc/hardwareclock
fi
fi
#setup everything needed to install live system
if [ -f /build-slackware-live.sh ]; then
cp /build-slackware-live.sh /slroot/live/union/usr/sbin/
chmod +x /slroot/live/union/usr/sbin/build-slackware-live.sh
fi
#detect fixed partitions
blkid | while read line; do
partition=`echo $line | cut -f1 -d: | cut -c 6-`
device=`echo $partition | cut -c1-3`
type=`echo $line | sed 's/^.*TYPE=\"\([^\"]*\)\".*$/\1/'`
loopdevice=`echo $partition | cut -c-4`
if [ "$loopdevice" != "loop" ] && [ "`cat /sys/block/$device/removable`" = "0" ]; then
if [ "$type" = "swap" ]; then
if [ "$useswap" = "yes" ]; then
echo "Enabling swap on /dev/$partition"
echo "/dev/$partition none swap defaults 0 0" >> /slroot/live/union/etc/fstab
else
echo "/dev/$partition none swap defaults,noauto 0 0" >> /slroot/live/union/etc/fstab
fi
#else
# echo "Detected /dev/$partition ($type)"
# echo "/dev/$partition /mnt/$partition $type defaults,noauto,user 0 0" >> /slroot/live/union/etc/fstab
# mkdir -p /slroot/live/union/mnt/$partition
elif [ "$type" = "vfat" ] && [ "$LIBSUFFIX" = "64" ]; then
mkdir -p /slroot/live/union/boot/efi
mount -t vfat /dev/$partition /slroot/live/union/boot/efi 2>/dev/null
if [ -d /slroot/live/union/boot/efi/EFI ]; then
echo "Adding EFI partition /dev/$partition to /etc/fstab"
echo "/dev/$partition /boot/efi vfat defaults 1 0" >> /slroot/live/union/etc/fstab
umount /slroot/live/union/boot/efi 2>/dev/null
else
umount /slroot/live/union/boot/efi 2>/dev/null
rm -rf /slroot/live/union/boot/efi
fi
fi
fi
done
#setup root password
if [ ! -z "$rootpw" ]; then
echo "Setting up root password"
echo "root:$rootpw" > /slroot/tmp/chpasswd.tmp
chroot /slroot /usr/sbin/chpasswd < /slroot/tmp/chpasswd.tmp
rm -f /slroot/tmp/chpasswd.tmp
fi
#chroot to live system
umount /proc
umount /sys
mount -r -o remount /slroot 2>/dev/null #remount root directory read-only for normal startup
echo "*** Live system ready ***"
echo ""
exec switch_root /slroot /sbin/init || exec sh