Dracut documentation explains rd.live.ram=1 but I can't get it to work in kiwi-live. There is code for it in dmsquash-live but kiwi-live doesn't seem to use it.
Therefore I'm starting an experiment. Here is kiwi-live-lib.sh for my intended first experiment. I haven't tested it yet and it might contain any kind of bug, because it's cumbersome to rebuild the initrd, iso, and USB stick. Does anyone have any comments or suggestions?
The purpose of rd.live.ram=1 is to allow disconnecting the USB stick after booting.
If boot parameters include both rd.live.ram=1 and rd.overlay.persistent then I read the existing cow partition but don't persist any new changes, so the USB stick can be disconnected.
(This also includes the one-line edit discussed in "Enable ISO image to be in any partition of USB stick",
https://groups.google.com/forum/#!topic/kiwi-images/XdLIhPlfi1Y ) #!/bin/bash
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
function lookupIsoDiskDevice {
local root=$1
local iso_label=${root#/dev/disk/by-label/}
local disk
for disk in $(lsblk -p -n -r -o NAME,TYPE | grep disk | cut -f1 -d' ');do
if [[ ${disk} =~ ^/dev/fd ]];then
# ignore floppy disk devices
continue
fi
iso_volid=$(lsblk -p -n -r -o LABEL "${disk}" | grep "${iso_label}")
if [ "${iso_volid}" = "${iso_label}" ];then
echo "${disk}"
return
fi
done
}
function setupDebugMode {
if getargbool 0 rd.kiwi.debug; then
local log=/run/initramfs/log
mkdir -p ${log}
exec > ${log}/boot.kiwi
exec 2>> ${log}/boot.kiwi
set -x
fi
}
function initialize {
local profile=/.profile
test -f ${profile} && cat ${profile}
}
function loadKernelModules {
modprobe squashfs
}
function initGlobalDevices {
if [ -z "$1" ]; then
die "No root device for operation given"
fi
isodev="$1"
isodiskdev=$(lookupIsoDiskDevice "${isodev}")
isofs_type=$(blkid -s TYPE -o value "${isodev}")
media_check_device=${isodev}
if [ ! -z "${isodiskdev}" ]; then
media_check_device=${isodiskdev}
fi
export media_check_device
export isodev
export isodiskdev
export isofs_type
}
function initGlobalOptions {
live_dir=$(getarg rd.live.dir -d live_dir)
[ -z "${live_dir}" ] && live_dir="LiveOS"
squash_image=$(getarg rd.live.squashimg)
[ -z "${squash_image}" ] && squash_image="squashfs.img"
cow_filesystem=$(getarg rd.live.overlay.cowfs)
[ -z "${cow_filesystem}" ] && cow_filesystem="ext4"
getargbool 0 rd.live.ram -d -y live_ram && live_ram="yes"
}
function mountIso {
ln -s "${isodev}" /run/initramfs/isodev
local iso_mount_point=/run/initramfs/live
mkdir -m 0755 -p "${iso_mount_point}"
if ! mount -n -t "${isofs_type}" "${isodev}" "${iso_mount_point}"; then
die "Failed to mount live ISO device"
fi
if [ -n "$live_ram" ]; then
umount ${iso_mount_point}
iso_image="run/initramfs/${isodev}.iso"
echo "Copying live image to RAM..."
echo "(this may take a few minutes)"
dd if="${isodev}" of="${iso_image}" bs=2048 2>/dev/null
echo "Done copying live image to RAM."
if ! mount -n -o loop,ro -t "{isofs_type}" "${iso_image}" "${iso_mount_point}"; then
die "Failed to mount live image"
fi
rm /run/initramfs/isodev
ln -s "${iso_image}" /run/initramfs/isodev
fi
echo "${iso_mount_point}"
}
function mountCompressedContainerFromIso {
local iso_mount_point=$1
local container_mount_point=/run/initramfs/squashfs_container
squashfs_container="${iso_mount_point}/${live_dir}/${squash_image}"
mkdir -m 0755 -p "${container_mount_point}"
if ! mount -n "${squashfs_container}" "${container_mount_point}";then
die "Failed to mount live ISO squashfs container"
fi
echo "${container_mount_point}"
}
function mountReadOnlyRootImageFromContainer {
local container_mount_point=$1
local rootfs_image="${container_mount_point}/LiveOS/rootfs.img"
local root_mount_point=/run/rootfsbase
mkdir -m 0755 -p "${root_mount_point}"
if ! mount -n "${rootfs_image}" "${root_mount_point}"; then
die "Failed to mount live ISO root filesystem"
fi
echo "${root_mount_point}"
}
function prepareTemporaryOverlay {
mkdir -m 0755 -p /run/overlayfs/rw
mkdir -m 0755 -p /run/overlayfs/work
}
function preparePersistentOverlay {
if [ -z "${isodiskdev}" ]; then
return 1
fi
local overlay_mount_point=/run/overlayfs
local partitions_before_cow_part
mkdir -m 0755 -p "${overlay_mount_point}"
if [ -n "$live_ram" ]; then
mkdir -m 0755 -p "${overlay_mount_point}/rw"
mkdir -m 0755 -p "${overlay_mount_point}/work"
mkdir -m 0755 -p /run/cow
if mount -L cow "/run/cow"; then
(cd "/run/cow"; tar cf - . | (cd "${overlay_mount_point}" ; tar xf -))
umount /run/cow
fi
rmdir /run/cow
return 0
fi
if ! mount -L cow "${overlay_mount_point}"; then
partitions_before_cow_part=$(_partition_count)
echo -e "n\np\n\n\n\nw\nq" | fdisk "${isodiskdev}"
if ! partprobe "${isodiskdev}"; then
return 1
fi
if [ "$(_partition_count)" -le "${partitions_before_cow_part}" ];then
return 1
fi
local write_partition
write_partition=$(lsblk "${isodiskdev}" -p -r -n -o NAME | tail -n1)
if ! mkfs."${cow_filesystem}" -L cow "${write_partition}"; then
return 1
fi
if ! mount -L cow ${overlay_mount_point}; then
return 1
fi
fi
mkdir -m 0755 -p ${overlay_mount_point}/rw
mkdir -m 0755 -p ${overlay_mount_point}/work
}
function runMediaCheck {
# messages are redirected to stderr because this code is called
# as part of the pre-mount hook via the dracut-pre-mount.service
# which only shows messages on stderr to the console and we want
# to see the check results during boot
if ! command -v checkmedia &>/dev/null; then
echo "No mediacheck program installed, mediacheck skipped" 1>&2
return
fi
local timeout=20
local check_result
check_result=/run/initramfs/checkmedia.result
checkmedia "${media_check_device}" &>${check_result}
local check_status=$?
if [ ${check_status} != 0 ];then
echo "ISO check failed" >> ${check_result}
else
echo "ISO check passed" >> ${check_result}
fi
echo "Press key to continue (waiting ${timeout}sec...)" >> ${check_result}
_run_dialog --timeout ${timeout} --textbox ${check_result} 20 70
if [ ${check_status} != 0 ];then
die "Failed to verify system integrity"
fi
}
#=========================================
# Methods considered private
#-----------------------------------------
function _setup_interactive_service {
local service=/usr/lib/systemd/system/dracut-run-interactive.service
[ -e ${service} ] && return
{
echo "[Unit]"
echo "Description=Dracut Run Interactive"
echo "DefaultDependencies=no"
echo "After=systemd-vconsole-setup.service"
echo "Wants=systemd-vconsole-setup.service"
echo "Conflicts=emergency.service emergency.target"
echo "[Service]"
echo "Environment=HOME=/"
echo "Environment=DRACUT_SYSTEMD=1"
echo "Environment=NEWROOT=/sysroot"
echo "WorkingDirectory=/"
echo "ExecStart=/bin/bash /bin/dracut-interactive"
echo "Type=oneshot"
echo "StandardInput=tty-force"
echo "StandardOutput=inherit"
echo "StandardError=inherit"
echo "KillMode=process"
echo "IgnoreSIGPIPE=no"
echo "TaskMax=infinity"
echo "KillSignal=SIGHUP"
} > ${service}
}
function _run_interactive {
_setup_interactive_service
systemctl start dracut-run-interactive.service
}
function _run_dialog {
echo "dialog $*" >/bin/dracut-interactive
_run_interactive
}
function _partition_count {
if [ -z "${isodiskdev}" ]; then
echo 0
else
lsblk "${isodiskdev}" -p -r -n -o TYPE | grep -c part
fi
}