commit 02b21c70dda53e0be3cbc87755e09bf2b3671f43
parent a2066f1d48a3dbb79543cbe9b5a0599abd540a6c
Author: emmett1 <emmett1.2miligrams@gmail.com>
Date: Thu, 11 Jun 2020 13:03:10 +0800
initial commit
Diffstat:
| A | Makefile | | | 19 | +++++++++++++++++++ |
| A | init | | | 177 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mkinitrd | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 438 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,19 @@
+BINDIR = /usr/bin
+DATADIR = /usr/share/mkinitrd
+IBINDIR = $(DESTDIR)$(BINDIR)
+IDATADIR = $(DESTDIR)$(DATADIR)
+
+all:
+ @echo "Run 'make install' to install"
+
+install:
+ install -d $(IBINDIR)
+ install -m755 mkinitrd $(IBINDIR)
+ install -d $(IDATADIR)
+ install -m755 init $(IDATADIR)
+
+uninstall:
+ rm -f $(IBINDIR)/mkinitrd
+ rm -f $(IDATADIR)/init
+
+.PHONY: all install uninstall
diff --git a/init b/init
@@ -0,0 +1,177 @@
+#!/bin/sh
+
+export PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+shell() {
+ setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1'
+}
+
+problem() {
+ printf "Encountered a problem!\n\nDropping you to a shell.\n\n"
+ shell
+}
+
+msg() {
+ echo ":: $*"
+}
+
+no_device() {
+ printf "The device %s, which is supposed to contain the\n" $1
+ printf "root file system, does not exist.\n"
+ printf "Please fix this problem and exit this shell.\n\n"
+}
+
+no_mount() {
+ printf "Could not mount device %s\n" $1
+ printf "Sleeping forever. Please reboot and fix the kernel command line.\n\n"
+ printf "Maybe the device is formatted with an unsupported file system?\n\n"
+ printf "Or maybe filesystem type autodetection went wrong, in which case\n"
+ printf "you should add the rootfstype=... parameter to the kernel command line.\n\n"
+ printf "Available partitions:\n"
+}
+
+do_mount_root() {
+ mkdir $newroot
+ [ -n "$rootflags" ] && rootflags="$rootflags,"
+ rootflags="$rootflags$ro"
+
+ case "$root" in
+ /dev/* ) device=$root ;;
+ UUID=* ) eval $root; device="/dev/disk/by-uuid/$UUID" ;;
+ PARTUUID=*) eval $root; device="/dev/disk/by-partuuid/$PARTUUID" ;;
+ LABEL=* ) eval $root; device="/dev/disk/by-label/$LABEL" ;;
+ "" ) echo "No root device specified." ; problem ;;
+ esac
+
+ while [ ! -b "$device" ] ; do
+ no_device $device
+ problem
+ done
+
+ if ! mount -n -t "$rootfstype" -o "$rootflags" "$device" $newroot ; then
+ no_mount $device
+ cat /proc/partitions
+ while true ; do sleep 10000 ; done
+ fi
+}
+
+do_boot_live() {
+ mkdir $newroot
+ modprobe loop
+
+ MEDIA=/dev/disk/by-label/LIVECD
+ MEDIUM=/run/initramfs/medium
+ SYSTEM=/run/initramfs/system
+ WRITEDIR=/run/initramfs/overlayfs/write
+ WORKDIR=/run/initramfs/overlayfs/work
+ sfsimg=/run/initramfs/medium/rootfs/filesystem.sfs
+ delay=${delay:-5}
+
+ mkdir -p $MEDIUM $SYSTEM $WRITEDIR $WORKDIR
+
+ if [ ! -e $MEDIA ]; then
+ msg "wait $delay seconds..."
+ sleep $delay
+ if [ ! -e $MEDIA ]; then
+ msg "media is not appeared even after wait $delay seconds..."
+ msg "try increase delay by append 'delay=<seconds>' to boot cmdline"
+ sleep 9999
+ fi
+ fi
+
+ mount -o ro $MEDIA $MEDIUM || problem
+ sfs_dev=$(losetup --find --show --read-only $sfsimg)
+ mount -o defaults -r $sfs_dev $SYSTEM || problem
+ mount -t overlay overlay -o upperdir=$WRITEDIR,lowerdir=$SYSTEM,workdir=$WORKDIR $newroot || problem
+
+ # Tell system to skip fsck during startup
+ > $newroot/fastboot
+}
+
+do_try_resume() {
+ case "$resume" in
+ UUID=* ) eval $resume; resume="/dev/disk/by-uuid/$UUID" ;;
+ LABEL=*) eval $resume; resume="/dev/disk/by-label/$LABEL" ;;
+ esac
+
+ if $noresume || ! [ -b "$resume" ]; then return; fi
+
+ ls -lH "$resume" | ( read x x x x maj min x
+ echo -n ${maj%,}:$min > /sys/power/resume )
+}
+
+init=/sbin/init
+root=
+newroot=/.root
+rootdelay=
+rootfstype=auto
+ro="ro"
+rootflags=
+device=
+resume=
+noresume=false
+
+mount -t proc proc /proc -o nosuid,noexec,nodev
+mount -t sysfs sys /sys -o nosuid,noexec,nodev
+mount -t devtmpfs dev /dev -o mode=0755,nosuid
+mount -t tmpfs run /run -o nosuid,nodev,mode=0755
+
+read -r cmdline < /proc/cmdline
+
+for param in $cmdline ; do
+ case $param in
+ init=* ) init=${param#init=} ;;
+ root=* ) root=${param#root=} ;;
+ rootdelay=* ) rootdelay=${param#rootdelay=} ;;
+ rootfstype=*) rootfstype=${param#rootfstype=} ;;
+ rootflags=* ) rootflags=${param#rootflags=} ;;
+ resume=* ) resume=${param#resume=} ;;
+ noresume ) noresume=true ;;
+ ro ) ro="ro" ;;
+ rw ) ro="rw" ;;
+ initrd ) initrd=true ;;
+ live ) live=true ;;
+ esac
+done
+
+# udevd location depends on version
+if [ -x /sbin/udevd ]; then
+ UDEVD=/sbin/udevd
+elif [ -x /lib/udev/udevd ]; then
+ UDEVD=/lib/udev/udevd
+elif [ -x /lib/systemd/systemd-udevd ]; then
+ UDEVD=/lib/systemd/systemd-udevd
+else
+ echo "Cannot find udevd nor systemd-udevd"
+ problem
+fi
+
+${UDEVD} --daemon --resolve-names=never
+udevadm trigger --action=add --type=subsystems
+udevadm trigger --action=add --type=devices
+udevadm trigger --action=change --type=devices
+udevadm settle
+
+if [ -f /etc/mdadm.conf ] ; then mdadm -As ; fi
+if [ -x /sbin/vgchange ] ; then /sbin/vgchange -a y > /dev/null ; fi
+if [ -n "$rootdelay" ] ; then sleep "$rootdelay" ; fi
+
+if [ "$initrd" = true ]; then
+ shell
+fi
+
+if [ "$live" = true ]; then
+ do_boot_live
+else
+ do_try_resume # This function will not return if resuming from disk
+ do_mount_root
+fi
+
+killall -w ${UDEVD##*/}
+
+mount --move /proc $newroot/proc
+mount --move /sys $newroot/sys
+mount --move /dev $newroot/dev
+mount --move /run $newroot/run
+
+exec switch_root $newroot "$init" "$@"
diff --git a/mkinitrd b/mkinitrd
@@ -0,0 +1,242 @@
+#!/bin/bash
+
+add_file() {
+ # add_file file [ dest ][ mode ]
+ local file dest mode
+ [ "$1" ] || return
+ if [ -f $1 ]; then
+ file=$1
+ else
+ echo "missing file: $1"
+ return
+ fi
+ if [ -L $file ]; then
+ add_file $(readlink -f $file)
+ fi
+ if [ "${file:0:1}" != "/" ]; then
+ echo "absolute source path needed: $file"
+ return
+ fi
+ if [ "$2" ]; then
+ dest="$2"
+ else
+ dest=${file/\//}
+ fi
+ if [ "${dest:0:1}" = "/" ]; then
+ echo "destination path must without leading '/': $dest"
+ return
+ fi
+ mode=${3:-$(stat -c %a "$file")}
+ if [ ! "$mode" ]; then
+ echo "failed get file mode: $file"
+ return
+ fi
+ install -Dm$mode $file $INITRDDIR/$dest
+}
+
+
+add_binary() {
+ # add_binary binary
+ local bin lib
+ [ "$1" ] || return
+ bin=$(type -p $1)
+ if [ ! "$bin" ]; then
+ echo "missing bin: $1"
+ return
+ fi
+ if [ -x $INITRDDIR/$bin ]; then
+ return
+ fi
+ add_file $bin
+ for i in $(ldd $bin | sed "s/\t//" | cut -d " " -f1); do
+ case $i in
+ linux-vdso.so.1|linux-gate.so.1) continue;;
+ esac
+ lib=$(PATH=/lib:/lib64:/usr/lib type -p $i)
+ if [ ! "$lib" ]; then
+ echo "missing lib: $i"
+ continue
+ fi
+ if [ -e $INITRDDIR/$lib ]; then
+ continue
+ fi
+ add_file $lib
+ done
+}
+
+add_module() {
+ # add_module modname
+ local modname modpath
+ [ "$1" ] || return
+ if modinfo -k $KERNEL $1 &>/dev/null; then
+ modname=$(modinfo -k $KERNEL -F name $1 | cut -d ' ' -f1 | head -n1)
+ [ "$modname" = "name:" ] && return 0
+ modpath=$(modinfo -k $KERNEL -F filename $1 | cut -d ' ' -f1 | head -n1)
+ [ "$modpath" = "name:" ] && return 0
+ else
+ echo "missing module: $1"
+ return
+ fi
+ [ -f $INITDIR/lib/modules/$KERNEL/kernel/$(basename $modpath) ] && return
+ add_file "$modpath" lib/modules/$KERNEL/kernel/$(basename $modpath)
+ modinfo -F firmware -k $KERNEL $modname | while read -r line; do
+ if [ ! -f /lib/firmware/$line ]; then
+ echo "missing firmware for $modname: $line"
+ else
+ add_file /lib/firmware/$line
+ fi
+ done
+ modinfo -F depends -k $KERNEL $modname | while IFS=',' read -r -a line; do
+ for l in ${line[@]}; do
+ add_module "$l"
+ done
+ done
+}
+
+finalize_modules() {
+ local file
+ [ -d $INITRDDIR/lib/modules/$KERNEL/kernel ] || return
+ for file in /lib/modules/$KERNEL/modules.*; do
+ add_file $file
+ done
+ awk -F'/' '{ print "kernel/" $NF }' /lib/modules/$KERNEL/modules.order > $INITDIR/lib/modules/$KERNEL/modules.order
+ depmod -b $INITRDDIR $KERNEL
+}
+
+add_dir() {
+ # add_dir source [ target ]
+ [ "$1" ] || return
+ source=$1
+ if [ ! -d $source ]; then
+ echo "directory not exist: $source"
+ return
+ fi
+ if [ $2 ]; then
+ target=$2
+ else
+ target=$(dirname $source)
+ fi
+ mkdir -p $INITRDDIR/$target
+ cp -a $source $INITRDDIR/$target
+}
+
+make_dir() {
+ # make_dir path [ mode ]
+ local path=$1 mode=${2:-755}
+ [ "$path" ] || return
+ if [ ${path:0:1} = / ]; then
+ echo "path should not leading '/': $path"
+ return
+ fi
+ install -dm$mode $INITRDDIR/$path
+}
+
+if [ $1 ] ; then
+ KERNEL=$1
+else
+ KERNEL=$(uname -r)
+fi
+INITRD=/boot/initrd-$KERNEL.img
+
+if [ ! -d "/lib/modules/$1" ] ; then
+ echo "No modules directory named $1"
+ exit 1
+fi
+
+if [ ! $(type -p cpio) ]; then
+ echo "'cpio' not found"
+ exit 1
+fi
+
+DATADIR=/usr/share/mkinitrd
+INITIN=init
+
+# create a temporary working directory
+INITRDDIR=$(mktemp -d /tmp/initrd-work.XXXXXXXXXX)
+
+echo "Creating $INITRD... "
+
+# make required dirs
+for d in dev run sys proc; do
+ make_dir $d
+done
+
+# add the init file
+add_file $DATADIR/$INITIN init 755
+
+# add required binaries
+for b in bash sh cat cp killall ls mkdir mount umount sed awk sleep ln rm setsid \
+ uname readlink basename modprobe blkid switch_root depmod kmod lsmod insmod; do
+ add_binary $b
+done
+
+# add dirs
+add_dir /etc/modprobe.d/
+
+# add required terminfo
+add_file /usr/share/terminfo/l/linux
+
+# udev
+if [ -f /etc/udev/udev.conf ]; then
+ add_file /etc/udev/udev.conf
+ add_dir /lib/udev/rules.d
+ add_dir /etc/udev/rules.d/
+ add_binary udevadm
+ add_binary udevd
+ add_binary /lib/udev/ata_id
+ add_binary /lib/udev/scsi_id
+ # Add udevd if not in PATH
+ if [ -x /lib/udev/udevd ] ; then
+ add_binary /lib/udev/udevd
+ elif [ -x /lib/systemd/systemd-udevd ] ; then
+ add_binary /lib/systemd/systemd-udevd
+ fi
+fi
+
+# LVM
+if [ $(type -p lvm) ]; then
+ for i in lvm dmsetup lvchange lvrename lvrename lvextend lvcreate lvdisplay lvscan \
+ pvchange pvck pvcreate pvdisplay pvscan \
+ vgchange vgcreate vgscan vgrename vgck; do
+ add_binary $i
+ done
+ add_dir /etc/lvm
+fi
+
+# systemd
+for dir in /lib/systemd /lib/elogind; do
+ if [ -d $dir ]; then
+ add_dir $dir
+ fi
+done
+
+# for livecd
+add_binary /lib/udev/cdrom_id
+add_binary blockdev
+add_binary losetup
+add_module cdrom
+add_module loop
+add_module overlay
+
+# kernel modules
+for mod in kernel/crypto kernel/fs kernel/lib kernel/drivers/block kernel/drivers/ata kernel/drivers/md \
+ kernel/drivers/firewire kernel/drivers/input kernel/drivers/scsi kernel/drivers/message \
+ kernel/drivers/pcmcia kernel/drivers/virtio kernel/drivers/hid kernel/drivers/usb/host kernel/drivers/usb/storage; do
+ FTGT="$FTGT /lib/modules/$KERNEL/$mod"
+done
+for m in $(find $FTGT -type f -name "*.ko*" 2> /dev/null); do
+ m=$(echo ${m%*.ko*})
+ add_module $(basename $m)
+done
+
+finalize_modules
+
+( cd $INITRDDIR ; find . | cpio -o -H newc --quiet | gzip -9 ) > $INITRD
+
+# Remove the temporary directories
+rm -rf $INITRDDIR
+
+size=$(du -sh $INITRD | awk '{print $1}')
+echo "done ($size)"
+
+exit 0