Re: Question on conversion from initrd to initramfs (1/2027 initrd support drop from kernel)

Jody Bruchon via busybox <[email protected]>
Newsgroups gmane.linux.busybox
Message-ID <[email protected]>
10+ years ago, I wanted to switch from initrd to initramfs. I had an 
extremely difficult time getting it all correct because switch_root has 
a lot of extremely specific requirements that you must meet before 
calling it, and any failure immediately after calling switch_root can be 
notoriously hard to debug. It's also critical that you use "cpio -o -H 
newc" to make the initramfs, then any compression format that your 
kernel supports can be used to compress it.

I don't mean to publicly advertise my work (mostly because I figured all 
this out a long time ago and I'm sure some of it isn't up to my current 
scripting standards) but I'm hoping that revealing some of my "secret 
sauce" will help you (and others) figure out how to do it correctly. 
PLEASE FEEL FREE TO STEAL THIS CODE! I am perfectly fine with you using 
it however you please. I've attached the init "wrapper" script to place 
in the root directory of the initramfs that unpacks the "real" tmpfs 
root and switches to it, and below I'll paste the "make it" snippet that 
packs my skeleton initramfs + packages (tarballs to unpack in the new 
root directory) into an "initrd.gz" (really an initramfs but I conform 
to DOS file restrictions for old boot loaders like SYSLINUX) that the 
kernel understands. (TSS is "Tritech Service System," my custom 
"embedded" Linux system I use for PC repair and maintenance.)

You can basically shove your existing initrd contents into a directory 
containing the /init and cd into it and use "find . | cpio -o -H newc | 
gzip -9 > initrd.gz" to make self-unpacking initramfs that changes from 
a ramfs into a tmpfs (you care about this, TRUST ME) and executes 
whatever init you choose (in the init wrapper change INIT=/init to 
INIT=/sbin/init for sysvinit etc). Let me know if this is helpful! I 
always like to know that someone else didn't suffer like I did.

--- snip ---
     cp "$TSSDIR/kernels/modules-tss-std-$ARCH.tar.xz" 
$DEST_FS/packages/modules-tss-std-${ARCH}_1.pkg.tar.xz
     cp "$TSSDIR/kernels/firmware.tar.xz" 
$DEST_FS/packages/firmware_1-all.pkg.tar.xz
     cp "$TSSPKGDIR/$ARCH"/tritech-utils_* $DEST_FS/packages/
     cp "$TSSPKGDIR/all"/tss-base-fs_* $DEST_FS/packages/
     cp "$TSSPKGDIR/all"/tss-init_* $DEST_FS/packages/
     cp "$TSSPKGDIR/all"/tss-configuration_* $DEST_FS/packages/

     # Update early init script and build initramfs images in parallel
     test -e init && cp -f init $DEST_FS/init && chmod 755 $DEST_FS/init
     cd "$DEST_FS"
     find . | cpio -o -H newc 2>/dev/null | gzip -9 > 
$TSSDIR/initramfs/initramfs1-$ARCH.gz &
     WAITS="$WAITS $!"
     find . | \
         grep -v '\./packages/modules-tss-.*\.tar\..*' | \
         grep -v '\./packages/firmware\.tar\..*' | \
         cpio -o -H newc 2>/dev/null | gzip -9 > 
$TSSDIR/initramfs/initramfs2-$ARCH.gz &
     WAITS="$WAITS $!"
--- snip ---

On 2026-03-04 2:16 PM, Michael D. Setzer II via busybox wrote:
> In doing a test with kernel 7.0.rc1 and later 7.0.rc2 noticed dmesg
> lines about initrd support being removed by 1/2027. So looked into
> doing the conversion.
>
> Tried about 20 things I found online, but many resulted in kernel
> panics. But final working solution resulted in minor changes.
>
> Original method would create ramdisk.lzma from a directory
> structor and the new method creates initramfs.lzma.
>
> Then changes included creating an init file that is a link to the
> origina etc/init.d/rcS2 which has one line added to end the earlier
> rcS init file. (Old setup goes back to 2004, when I took over
> project).
>
> The added line is.
> exec /sbin/init
>
> Seems that is to keep PID 1 running?
>
> Other change was to comment  first line of
> cat etc/inittab
>
> #::sysinit:/etc/init.d/rcS
> ::ctrlaltdel:/sbin/reboot
> tty1::respawn:/bin/login g4l
> tty2::askfirst:/bin/login
> tty3::askfirst:/bin/login
> tty4::askfirst:/bin/login
> tty5::askfirst:/bin/login
>
> Then only change I've noted is that under old initrd boot the df
> command would show this
> Filesystem           1K-blocks      Used Available Use% Mounted on
> /dev/root.old           127507     75746     51761  59% /
> with initramfs get this.
> Filesystem           1K-blocks      Used Available Use% Mounted on
>
> The initramfs starts by this
> echo "Packing rootfs into cpio archive"
> (
>      cd bootcd/rootfs
>      # Include hidden files (.bash_profile etc.) via find so nothing is
> missed.
>      find . | cpio --quiet -o -H newc
> ) > bootcd/isolinux/ramdisk.cpio
>
> later the is compressed
> lzma -v bootcd/isolinux/ramdisk.cpio
> mv bootcd/isolinux/ramdisk.cpio.lzma /boot/initramfs.lzma
> (will clean files names soon).
>
> So loading kernel and initramfs.lzma works from
> syslinux booting with hybrid image via cd or usb
> grub4dos bios and uefi usbs
> grub directly.
>
> 	linux /bz6x19.5
> 	initrd /initramfs.lzma
>
> Don't know if I missed anything? Or did something not necessary.
> Thanks.
>
>
> +------------------------------------------------------------+
>   Michael D. Setzer II - Computer Science Instructor (Retired)
>   mailto:[email protected]
>   mailto:[email protected]
>   mailto:[email protected]
>   Guam - Where America's Day Begins
>   G4L Disk Imaging Project maintainer
>   http://sourceforge.net/projects/g4l/
> +------------------------------------------------------------+
>
>
>
> _______________________________________________
> busybox mailing list
> [email protected]
> https://lists.busybox.net/mailman/listinfo/busybox

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
init (text/plain, 5.6 KB)
#!/bin/sh

# Wrapper init script for Tritech Service System
# Version 1.6 (2018-07-21)

# This script is responsible for unpacking the system
# into a tmpfs instance and switching into it.
# We must do this because initramfs is a ramfs instance
# which will crash the system if it accidentally fills.
# Packages that make up the system are put into place
# by this script, including kernel modules and firmware.

# The general procedure is as follows:
# 1. Mount a tmpfs instance to unpack to
# 2. Copy critical packages that are included in the wrapper
#    to the tmpfs instance
# 3. Unpack package files in wrapper's /packages folder
# 4. Unpack kernel modules and firmware
# 5. Copy the home skeleton archive to the /etc/init folder
# 6. Switch into the tmpfs root permanently.
# If the last step fails, a failsafe shell will launch.

# Failsafe shell if init terminates prematurely
trap 'exec /bin/sh' EXIT

export PATH=/bin:/sbin:/usr/bin:/usr/sbin

mkdir -p /proc /sys /dev /mnt
mount -t devtmpfs devtmpfs /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys

# Set all CPUs to maximum performance (if possible)
for X in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
	do
	test -e "$X" && echo "$MODE" > $X 2>/dev/null
done

V=0
INIT=/init

for X in $(tr ' ' '\n' < /proc/cmdline)
	do case $X in
		debug-init) V=1; echo "TSS init debugging enabled" ;;
		root=*) ROOT=$(echo $X | sed 's/.*=//') ;;
		init=*) INIT=$(echo $X | sed 's/.*=//') ;;
	esac
done

# Root filesystem override capability for supporting "traditional" roots.
if [ ! -z "$ROOT" ]
	then echo "Root device override: $ROOT"
	# Linux allows mount by UUID but we need to verify it exists before trying.
	test ! -e $ROOT && ROOT=$(blkid | grep -i "UUID=\"$ROOT\"" | sed 's/:.*//')
	if [ -e $ROOT ]
		then mount -t auto $ROOT /mnt && \
		unset V X lzo gz bz2 xz lzma FLIST DECOMP ROOT BN && \
		umount /proc /sys /dev 2>/dev/null && \
		test -x /mnt/$INIT && exec /sbin/switch_root /mnt $INIT "$@"
		echo "WARNING: Could not mount specified root device."
		else echo "WARNING: Could not mount specified root device."
	fi
fi

# Set up compressed swap for very low memory systems
setup_zramswap () {
	SZ=/sys/block/zram0
	DEV=/dev/zram0
	RAM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
	grep -q "zramswap" /proc/cmdline || test $RAM -gt 500000
	echo $(expr $RAM \* 1024) > $SZ/disksize
	test ! -e $DEV && mknod $DEV b $(cat $SZ/dev | tr ":" " ")
	mkswap $DEV 2>/dev/null >/dev/null
	swapon $DEV 2>/dev/null >/dev/null
	unset DEV SZ RAM
}
### End functions

# For low memory systems, we need zram swap working as soon as possible
setup_zramswap

# Mount tmpfs into which the system will be unpacked
mount -t tmpfs newroot /mnt -o size=80%
mkdir -p /mnt/packages/installed

# Be resilient if normal compression tools aren't present
test -x /usr/bin/unxz && xz='/usr/bin/unxz -c'
test -x /usr/bin/xz && xz='/usr/bin/xz -dc'
test -x /usr/bin/unlzop && lzo='/usr/bin/unlzop -c'
test -x /bin/lzop && lzo='/bin/lzop -dc'
test -x /usr/bin/lzop && lzo='/usr/bin/lzop -dc'
test -x /bin/gunzip && gz='/bin/gunzip -c'
test -x /bin/gzip && gz='/bin/gzip -dc'
test -x /usr/bin/gzip && gz='/usr/bin/gzip -dc'
test -x /bin/bunzip2 && bz2='/bin/bunzip2 -c'
test -x /bin/bzip2 && bz2='/bin/bzip2 -dc'
test -x /usr/bin/bzip2 && bz2='/usr/bin/bzip2 -dc'

echo -n "Loading: "

# For packages included in this wrapper, the package files
# need to be copied to the new root manually to achieve
# the same effect as if they were unpacked normally.
# The fastest way to do this is to tar and untar with
# a pipe since it can use lists.
for X in /packages/installed/*
	do echo -n "."
	cp "$X" "/mnt/$X"
	tar -c -T "$X" 2>/dev/null | tar -C /mnt -xp 2>/dev/null || echo -n "[ERROR]"
done

for X in /packages/*.pkg.tar.* /modules.* /firmware.*
	do
	if [ -e "$X" ]
		then echo -n "."
		BN="$(basename "$X")"
		DECOMP="$(echo "$BN" | sed 's/.*\.//')"
		test "$DECOMP" = "txz" && DECOMP="xz"
		DECOMP="$(eval "echo \$$DECOMP")"
		FLIST="/mnt/packages/installed/$(echo "$BN" | sed 's/\.pkg\.tar\.[a-z]*$//')"
		if eval $DECOMP "$X" | tar -C /mnt -xvp > $FLIST 2>/dev/null
			then rm -f "$X"
			else return 1
		fi
	fi
done

mkdir -p /mnt/lib/modules/$(/bin/uname -r)
echo -n "."
test -e /home-skel.tar.gz && mv /home-skel.tar.gz /mnt/etc/init/
echo -n "."
test -e /mnt/etc/tss/version && rm -f /mnt/etc/tss/version
mv /version /mnt/etc/tss/
echo 'party time! =)'

# BusyBox init fallback support
for X in 1 2 3 4
	do test ! -e /mnt/dev/tty$X && mknod /mnt/dev/tty$X c 4 $X
done
test ! -x /mnt/etc/init.d/rcS && mkdir -p /mnt/etc/init.d && ln -s /bin/sh /mnt/etc/init.d/rcS

test "$V" = "1" && echo -e "\nEarly init debug shell." && /bin/sh

unset V X lzo gz bz2 xz lzma FLIST DECOMP ROOT

umount /proc /sys

# Switch into new root. This should generally never fail.
test -x /mnt/$INIT && exec /sbin/switch_root /mnt $INIT "$@"

# If there is no /init present, try /sbin/init
test -x /mnt/sbin/init && exec /sbin/switch_root /mnt /sbin/init "$@"

# Fall back to shells in the new root if that doesn't work out
echo "switch_root apparently could not run /init or /sbin/init"
echo "Trying to run a shell in the new root instead..."
test -x /mnt/bin/bash && exec /sbin/switch_root /mnt /bin/bash "$@"
test -x /mnt/bin/sh && exec /sbin/switch_root /mnt /bin/sh "$@"

###############################################################
# This section should never be reached.

echo "For some reason, switch_root couldn't be done at all."
echo "Since we can't proceed further because something is"
echo "wrong, you're getting dropped into an infinitely"
echo "respawning shell. Apologies for this awful inconvenience."

while true
	do sleep 1
	/bin/sh
done
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.