]> git.ipfire.org Git - thirdparty/dracut.git/blobdiff - modules.d/90dmsquash-live/dmsquash-live-root.sh
dmsquash-live: Support a flattened squashfs.img
[thirdparty/dracut.git] / modules.d / 90dmsquash-live / dmsquash-live-root.sh
index f63819cca91e260a8d9a1e2ea32a2df707744ee8..0c5e010ec192aef85b333835dfc2fd676629fe7c 100755 (executable)
@@ -1,9 +1,9 @@
 #!/bin/sh
-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
-# ex: ts=8 sw=4 sts=4 et filetype=sh
 
 type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
 
+command -v unpack_archive >/dev/null || . /lib/img-lib.sh
+
 PATH=/usr/sbin:/usr/bin:/sbin:/bin
 
 if getargbool 0 rd.live.debug -n -y rdlivedebug; then
@@ -20,12 +20,18 @@ livedev="$1"
 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"
+[ -z "$squash_image" ] && squash_image="squashfs.img"
 
 getargbool 0 rd.live.ram -d -y live_ram && live_ram="yes"
 getargbool 0 rd.live.overlay.reset -d -y reset_overlay && reset_overlay="yes"
 getargbool 0 rd.live.overlay.readonly -d -y readonly_overlay && readonly_overlay="--readonly" || readonly_overlay=""
 overlay=$(getarg rd.live.overlay -d overlay)
+getargbool 0 rd.writable.fsimg -d -y writable_fsimg && writable_fsimg="yes"
+overlay_size=$(getarg rd.live.overlay.size=)
+[ -z "$overlay_size" ] && overlay_size=32768
+
+getargbool 0 rd.live.overlay.thin && thin_snapshot="yes"
+getargbool 0 rd.live.overlay.overlayfs && overlayfs="yes"
 
 # CD/DVD media check
 [ -b $livedev ] && fs=$(blkid -s TYPE -o value $livedev)
@@ -36,12 +42,12 @@ getarg rd.live.check -d check || check=""
 if [ -n "$check" ]; then
     type plymouth >/dev/null 2>&1 && plymouth --hide-splash
     if [ -n "$DRACUT_SYSTEMD" ]; then
-        p=$(str_replace "$livedev" "-" '\x2d')
+        p=$(dev_unit_name "$livedev")
         systemctl start checkisomd5@${p}.service
     else
         checkisomd5 --verbose $livedev
     fi
-    if [ $? -ne 0 ]; then
+    if [ $? -eq 1 ]; then
         die "CD check failed!"
         exit 1
     fi
@@ -52,12 +58,12 @@ ln -s $livedev /run/initramfs/livedev
 
 # determine filesystem type for a filesystem image
 det_img_fs() {
-    udevadm settle
+    udevadm settle >&2
     blkid -s TYPE -u noraid -o value "$1"
 }
 
 modprobe squashfs
-
+CMDLINE=$(getcmdline)
 for arg in $CMDLINE; do case $arg in ro|rw) liverw=$arg ;; esac; done
 # mount the backing of the live image first
 mkdir -m 0755 -p /run/initramfs/live
@@ -72,7 +78,20 @@ if [ -f $livedev ]; then
     esac
     [ -e /sys/fs/$fstype ] || modprobe $fstype
 else
-    mount -n -t $fstype -o ${liverw:-ro} $livedev /run/initramfs/live
+    if [ "$(blkid -o value -s TYPE $livedev)" != "ntfs" ]; then
+        mount -n -t $fstype -o ${liverw:-ro} $livedev /run/initramfs/live
+    else
+        # Symlinking /usr/bin/ntfs-3g as /sbin/mount.ntfs seems to boot
+        # at the first glance, but ends with lots and lots of squashfs
+        # errors, because systemd attempts to kill the ntfs-3g process?!
+        if [ -x "/usr/bin/ntfs-3g" ]; then
+            ( exec -a @ntfs-3g ntfs-3g -o ${liverw:-ro} $livedev /run/initramfs/live ) | vwarn
+        else
+            die "Failed to mount block device of live image: Missing NTFS support"
+            exit 1
+        fi
+    fi
+
     if [ "$?" != "0" ]; then
         die "Failed to mount block device of live image"
         exit 1
@@ -84,7 +103,6 @@ do_live_overlay() {
     # create a sparse file for the overlay
     # overlay: if non-ram overlay searching is desired, do it,
     #              otherwise, create traditional overlay in ram
-    OVERLAY_LOOPDEV=$( losetup -f )
 
     l=$(blkid -s LABEL -o value $livedev) || l=""
     u=$(blkid -s UUID -o value $livedev) || u=""
@@ -102,65 +120,150 @@ do_live_overlay() {
     devspec=$( echo $overlay | sed -e 's/:.*$//' )
 
     # need to know where to look for the overlay
-    setup=""
-    if [ -n "$devspec" -a -n "$pathspec" -a -n "$overlay" ]; then
+    if [ -z "$setup" -a -n "$devspec" -a -n "$pathspec" -a -n "$overlay" ]; then
         mkdir -m 0755 /run/initramfs/overlayfs
+        opt=''
+        [ -n "$readonly_overlay" ] && opt=-r
         mount -n -t auto $devspec /run/initramfs/overlayfs || :
         if [ -f /run/initramfs/overlayfs$pathspec -a -w /run/initramfs/overlayfs$pathspec ]; then
-            losetup $OVERLAY_LOOPDEV /run/initramfs/overlayfs$pathspec
-            if [ -n "$reset_overlay" ]; then
-                dd if=/dev/zero of=$OVERLAY_LOOPDEV bs=64k count=1 conv=fsync 2>/dev/null
+            OVERLAY_LOOPDEV=$(losetup -f --show $opt /run/initramfs/overlayfs$pathspec)
+            over=$OVERLAY_LOOPDEV
+            umount -l /run/initramfs/overlayfs || :
+            oltype=$(det_img_fs $OVERLAY_LOOPDEV)
+            if [ -z "$oltype" ] || [ "$oltype" = DM_snapshot_cow ]; then
+                if [ -n "$reset_overlay" ]; then
+                    info "Resetting the Device-mapper overlay."
+                    dd if=/dev/zero of=$OVERLAY_LOOPDEV bs=64k count=1 conv=fsync 2>/dev/null
+                fi
+                if [ -n "$overlayfs" ]; then
+                    unset -v overlayfs
+                    [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit="yes"
+                fi
+                setup="yes"
+            else
+                mount -n -t $oltype $opt $OVERLAY_LOOPDEV /run/initramfs/overlayfs
+                if [ -d /run/initramfs/overlayfs/overlayfs ] &&
+                    [ -d /run/initramfs/overlayfs/ovlwork ]; then
+                    ln -s /run/initramfs/overlayfs/overlayfs /run/overlayfs$opt
+                    ln -s /run/initramfs/overlayfs/ovlwork /run/ovlwork$opt
+                    if [ -z "$overlayfs" ]; then
+                        overlayfs="yes"
+                        [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit="yes"
+                    fi
+                    setup="yes"
+                fi
+            fi
+        elif [ -d /run/initramfs/overlayfs$pathspec ] &&
+            [ -d /run/initramfs/overlayfs$pathspec/../ovlwork ]; then
+            ln -s /run/initramfs/overlayfs$pathspec /run/overlayfs$opt
+            ln -s /run/initramfs/overlayfs$pathspec/../ovlwork /run/ovlwork$opt
+            if [ -z "$overlayfs" ]; then
+                overlayfs="yes"
+                [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit="yes"
             fi
             setup="yes"
         fi
-        umount -l /run/initramfs/overlayfs || :
+    fi
+    if [ -n "$overlayfs" ]; then
+        modprobe overlay
+        if [ $? != 0 ]; then
+            m='OverlayFS is not available; using temporary Device-mapper overlay.'
+            unset -v overlayfs setup
+            [ -n "$reloadsysrootmountunit" ] && unset -v reloadsysrootmountunit
+        fi
     fi
 
     if [ -z "$setup" -o -n "$readonly_overlay" ]; then
         if [ -n "$setup" ]; then
             warn "Using temporary overlay."
         elif [ -n "$devspec" -a -n "$pathspec" ]; then
-            warn "Unable to find persistent overlay; using temporary"
-            sleep 5
+            [ -z "$m" ] &&
+                m='   Unable to find a persistent overlay; using a temporary one.'
+            m="$m"$'\n      All root filesystem changes will be lost on shutdown.'
+            m="$m"$'\n         Press [Enter] to continue.'
+            echo -e "\n\n\n\n${m}\n\n\n" > /dev/kmsg
+            if [ -n "$DRACUT_SYSTEMD" ]; then
+                if type plymouth >/dev/null 2>&1 && plymouth --ping ; then
+                    if getargbool 0 rhgb || getargbool 0 splash ; then
+                        m='>>>'$'\n''>>>'$'\n''>>>'$'\n\n\n'"$m"
+                        m="${m%n.*}"$'n.\n\n\n''<<<'$'\n''<<<'$'\n''<<<'
+                        plymouth display-message --text="${m}"
+                    else
+                        plymouth ask-question --prompt="${m}" --command=true
+                    fi
+                else
+                    m=">>>${m//.[[:space:]]/.}  <<<"
+                    systemd-ask-password --timeout=0 "${m}"
+                fi
+            else
+                type plymouth >/dev/null 2>&1 && plymouth --ping && plymouth --quit
+                read -s -r -p $'\n\n'"${m}" -n 1 reply
+            fi
         fi
-
-        dd if=/dev/null of=/overlay bs=1024 count=1 seek=$((512*1024)) 2> /dev/null
-        if [ -n "$setup" -a -n "$readonly_overlay" ]; then
-            RO_OVERLAY_LOOPDEV=$( losetup -f )
-            losetup $RO_OVERLAY_LOOPDEV /overlay
+        if [ -n "$overlayfs" ]; then
+            mkdir -m 0755 /run/overlayfs
+            mkdir -m 0755 /run/ovlwork
         else
-            losetup $OVERLAY_LOOPDEV /overlay
+            dd if=/dev/null of=/overlay bs=1024 count=1 seek=$((overlay_size*1024)) 2> /dev/null
+            if [ -n "$setup" -a -n "$readonly_overlay" ]; then
+                RO_OVERLAY_LOOPDEV=$(losetup -f --show /overlay)
+                over=$RO_OVERLAY_LOOPDEV
+            else
+                OVERLAY_LOOPDEV=$(losetup -f --show /overlay)
+                over=$OVERLAY_LOOPDEV
+            fi
         fi
     fi
 
     # set up the snapshot
-    sz=$(blockdev --getsz $BASE_LOOPDEV)
-    if [ -n "$readonly_overlay" ]; then
-        echo 0 $sz snapshot $BASE_LOOPDEV $OVERLAY_LOOPDEV p 8 | dmsetup create $readonly_overlay live-ro
-        base="/dev/mapper/live-ro"
-        over=$RO_OVERLAY_LOOPDEV
-    else
-        base=$BASE_LOOPDEV
-        over=$OVERLAY_LOOPDEV
+    if [ -z "$overlayfs" ]; then
+        if [ -n "$readonly_overlay" ] && [ -n "$OVERLAY_LOOPDEV" ]; then
+            echo 0 $sz snapshot $BASE_LOOPDEV $OVERLAY_LOOPDEV P 8 | dmsetup create --readonly live-ro
+            base="/dev/mapper/live-ro"
+        else
+            base=$BASE_LOOPDEV
+        fi
+    fi
+
+    if [ -n "$thin_snapshot" ]; then
+        modprobe dm_thin_pool
+        mkdir -m 0755 /run/initramfs/thin-overlay
+
+        # In block units (512b)
+        thin_data_sz=$(( $overlay_size * 1024 * 1024 / 512 ))
+        thin_meta_sz=$(( $thin_data_sz / 10 ))
+
+        # It is important to have the backing file on a tmpfs
+        # this is needed to let the loopdevice support TRIM
+        dd if=/dev/null of=/run/initramfs/thin-overlay/meta bs=1b count=1 seek=$((thin_meta_sz)) 2> /dev/null
+        dd if=/dev/null of=/run/initramfs/thin-overlay/data bs=1b count=1 seek=$((thin_data_sz)) 2> /dev/null
+
+        THIN_META_LOOPDEV=$( losetup --show -f /run/initramfs/thin-overlay/meta )
+        THIN_DATA_LOOPDEV=$( losetup --show -f /run/initramfs/thin-overlay/data )
+
+        echo 0 $thin_data_sz thin-pool $THIN_META_LOOPDEV $THIN_DATA_LOOPDEV 1024 1024 | dmsetup create live-overlay-pool
+        dmsetup message /dev/mapper/live-overlay-pool 0 "create_thin 0"
+
+        # Create a snapshot of the base image
+        echo 0 $sz thin /dev/mapper/live-overlay-pool 0 $base | dmsetup create live-rw
+    elif [ -z "$overlayfs" ]; then
+        echo 0 $sz snapshot $base $over PO 8 | dmsetup create live-rw
     fi
-    echo 0 $sz snapshot $base $over p 8 | dmsetup create live-rw
-}
 
-# live cd helper function
-do_live_from_base_loop() {
-    do_live_overlay
+    # Create a device for the ro base of overlayed file systems.
+    if [ -z "$overlayfs" ]; then
+        echo 0 $sz linear $BASE_LOOPDEV 0 | dmsetup create --readonly live-base
+    fi
+    ln -s $BASE_LOOPDEV /dev/live-base
 }
 
 # we might have a genMinInstDelta delta file for anaconda to take advantage of
 if [ -e /run/initramfs/live/${live_dir}/osmin.img ]; then
     OSMINSQFS=/run/initramfs/live/${live_dir}/osmin.img
-fi
-
-if [ -n "$OSMINSQFS" ]; then
     # decompress the delta data
-    dd if=$OSMINSQFS of=/osmin.img 2> /dev/null
+    dd if=$OSMINSQFS of=/run/initramfs/osmin.img 2> /dev/null
     OSMIN_SQUASHED_LOOPDEV=$( losetup -f )
-    losetup -r $OSMIN_SQUASHED_LOOPDEV /osmin.img
+    losetup -r $OSMIN_SQUASHED_LOOPDEV /run/initramfs/osmin.img
     mkdir -m 0755 -p /run/initramfs/squashfs.osmin
     mount -n -t squashfs -o ro $OSMIN_SQUASHED_LOOPDEV /run/initramfs/squashfs.osmin
     OSMIN_LOOPDEV=$( losetup -f )
@@ -168,33 +271,17 @@ if [ -n "$OSMINSQFS" ]; then
     umount -l /run/initramfs/squashfs.osmin
 fi
 
-# we might have an embedded fs image to use as rootfs (uncompressed live)
-if [ -e /run/initramfs/live/${live_dir}/ext3fs.img ]; then
-    FSIMG="/run/initramfs/live/${live_dir}/ext3fs.img"
-elif [ -e /run/initramfs/live/${live_dir}/rootfs.img ]; then
-    FSIMG="/run/initramfs/live/${live_dir}/rootfs.img"
-fi
-
-if [ -n "$FSIMG" ] ; then
-    BASE_LOOPDEV=$( losetup -f )
-    losetup -r $BASE_LOOPDEV $FSIMG
-
-    do_live_from_base_loop
-fi
-
 # we might have an embedded fs image on squashfs (compressed live)
 if [ -e /run/initramfs/live/${live_dir}/${squash_image} ]; then
     SQUASHED="/run/initramfs/live/${live_dir}/${squash_image}"
 fi
-
-if [ -e "$SQUASHED" ] ; then
-    if [ -n "$live_ram" ] ; then
-        echo "Copying live image to RAM..."
-        echo "(this may take a few minutes)"
-        dd if=$SQUASHED of=/squashed.img bs=512 2> /dev/null
-        umount -n /run/initramfs/live
-        echo "Done copying live image to RAM."
-        SQUASHED="/squashed.img"
+if [ -e "$SQUASHED" ]; then
+    if [ -n "$live_ram" ]; then
+        echo 'Copying live image to RAM...' > /dev/kmsg
+        echo ' (this may take a minute)' > /dev/kmsg
+        dd if=$SQUASHED of=/run/initramfs/squashed.img bs=512 2> /dev/null
+        echo 'Done copying live image to RAM.' > /dev/kmsg
+        SQUASHED="/run/initramfs/squashed.img"
     fi
 
     SQUASHED_LOOPDEV=$( losetup -f )
@@ -202,35 +289,119 @@ if [ -e "$SQUASHED" ] ; then
     mkdir -m 0755 -p /run/initramfs/squashfs
     mount -n -t squashfs -o ro $SQUASHED_LOOPDEV /run/initramfs/squashfs
 
-    BASE_LOOPDEV=$( losetup -f )
-    if [ -f /run/initramfs/squashfs/LiveOS/ext3fs.img ]; then
-        losetup -r $BASE_LOOPDEV /run/initramfs/squashfs/LiveOS/ext3fs.img
-    elif [ -f /run/initramfs/squashfs/LiveOS/rootfs.img ]; then
-        losetup -r $BASE_LOOPDEV /run/initramfs/squashfs/LiveOS/rootfs.img
+    if [ -d /run/initramfs/squashfs/LiveOS ]; then
+        if [ -f /run/initramfs/squashfs/LiveOS/rootfs.img ]; then
+            FSIMG="/run/initramfs/squashfs/LiveOS/rootfs.img"
+        elif [ -f /run/initramfs/squashfs/LiveOS/ext3fs.img ]; then
+            FSIMG="/run/initramfs/squashfs/LiveOS/ext3fs.img"
+        fi
+    elif [ -d /run/initramfs/squashfs/proc ]; then
+        FSIMG=$SQUASHED
+        if [ -z "$overlayfs" ]; then
+            overlayfs="yes"
+            [ -n "$DRACUT_SYSTEMD" ] && reloadsysrootmountunit="yes"
+        fi
+    else
+        die "Failed to find a root filesystem in $SQUASHED."
+        exit 1
     fi
+else
+    # we might have an embedded fs image to use as rootfs (uncompressed live)
+    if [ -e /run/initramfs/live/${live_dir}/rootfs.img ]; then
+        FSIMG="/run/initramfs/live/${live_dir}/rootfs.img"
+    elif [ -e /run/initramfs/live/${live_dir}/ext3fs.img ]; then
+        FSIMG="/run/initramfs/live/${live_dir}/ext3fs.img"
+    fi
+    if [ -n "$live_ram" ]; then
+        echo 'Copying live image to RAM...' > /dev/kmsg
+        echo ' (this may take a minute or so)' > /dev/kmsg
+        dd if=$FSIMG of=/run/initramfs/rootfs.img bs=512 2> /dev/null
+        echo 'Done copying live image to RAM.' > /dev/kmsg
+        FSIMG='/run/initramfs/rootfs.img'
+    fi
+fi
 
-    umount -l /run/initramfs/squashfs
-
-    do_live_from_base_loop
+if [ -n "$FSIMG" ]; then
+    if [ -n "$writable_fsimg" ]; then
+        # mount the provided filesystem read/write
+        echo "Unpacking live filesystem (may take some time)" > /dev/kmsg
+        mkdir -m 0755 /run/initramfs/fsimg/
+        if [ -n "$SQUASHED" ]; then
+            cp -v $FSIMG /run/initramfs/fsimg/rootfs.img
+        else
+            unpack_archive $FSIMG /run/initramfs/fsimg/
+        fi
+        FSIMG=/run/initramfs/fsimg/rootfs.img
+    fi
+    opt=-r
+       # For writable DM images...
+    if [ -z "$SQUASHED" -a -n "$live_ram" -a -z "$overlayfs" ] ||
+       [ -n "$writable_fsimg" ] ||
+       [ "$overlay" = none -o "$overlay" = None -o "$overlay" = NONE ]; then
+        if [ -z "$readonly_overlay" ]; then
+            opt=''
+            setup=rw
+        else
+            setup=yes
+        fi
+    fi
+    if [ "$FSIMG" = "$SQUASHED" ]; then
+        BASE_LOOPDEV=$SQUASHED_LOOPDEV
+    else
+        BASE_LOOPDEV=$(losetup -f --show $opt $FSIMG)
+        sz=$(blockdev --getsz $BASE_LOOPDEV)
+    fi
+    if [ "$setup" = rw ]; then
+        echo 0 $sz linear $BASE_LOOPDEV 0 | dmsetup create live-rw
+    else
+        # Add a DM snapshot or OverlayFS for writes.
+        do_live_overlay
+    fi
 fi
 
 if [ -b "$OSMIN_LOOPDEV" ]; then
     # set up the devicemapper snapshot device, which will merge
     # the normal live fs image, and the delta, into a minimzied fs image
-    echo "0 $( blockdev --getsz $BASE_LOOPDEV ) snapshot $BASE_LOOPDEV $OSMIN_LOOPDEV p 8" | dmsetup create --readonly live-osimg-min
+    echo "0 $sz snapshot $BASE_LOOPDEV $OSMIN_LOOPDEV P 8" | dmsetup create --readonly live-osimg-min
 fi
 
-ROOTFLAGS="$(getarg rootflags)"
-if [ -n "$ROOTFLAGS" ]; then
-    ROOTFLAGS="-o $ROOTFLAGS"
+if [ -n "$reloadsysrootmountunit" ]; then
+    > /xor_overlayfs
+    systemctl daemon-reload
 fi
 
-if [ -b "$BASE_LOOPDEV" ]; then
-    ln -s $BASE_LOOPDEV /run/initramfs/live-baseloop
+ROOTFLAGS="$(getarg rootflags)"
+
+if [ -n "$overlayfs" ]; then
+    mkdir -m 0755 /run/rootfsbase
+    if [ -n "$reset_overlay" ] && [ -L /run/overlayfs ]; then
+        ovlfs=$(readlink /run/overlayfs)
+        info "Resetting the OverlayFS overlay directory."
+        rm -r -- ${ovlfs}/* ${ovlfs}/.* >/dev/null 2>&1
+    fi
+    if [ -n "$readonly_overlay" ]; then
+        mkdir -m 0755 /run/rootfsbase-r
+        mount -r $FSIMG /run/rootfsbase-r
+        mount -t overlay LiveOS_rootfs-r -oro,lowerdir=/run/overlayfs-r:/run/rootfsbase-r /run/rootfsbase
+    else
+        mount -r $FSIMG /run/rootfsbase
+    fi
+    if [ -z "$DRACUT_SYSTEMD" ]; then
+        printf 'mount -t overlay LiveOS_rootfs -o%s,%s %s\n' "$ROOTFLAGS" \
+        'lowerdir=/run/rootfsbase,upperdir=/run/overlayfs,workdir=/run/ovlwork' \
+        "$NEWROOT" > $hookdir/mount/01-$$-live.sh
+    fi
+else
+    if [ -z "$DRACUT_SYSTEMD" ]; then
+        [ -n "$ROOTFLAGS" ] && ROOTFLAGS="-o $ROOTFLAGS"
+        printf 'mount %s /dev/mapper/live-rw %s\n' "$ROOTFLAGS" "$NEWROOT" > $hookdir/mount/01-$$-live.sh
+    fi
 fi
-ln -s /dev/mapper/live-rw /dev/root
-printf 'mount %s /dev/mapper/live-rw %s\n' "$ROOTFLAGS" "$NEWROOT" > $hookdir/mount/01-$$-live.sh
+[ -e "$SQUASHED" ] && umount -l /run/initramfs/squashfs
+
+ln -s null /dev/root
 
 need_shutdown
 
 exit 0
+