#!/bin/sh # # tiny initramfs generation tool panic() { printf "panic >> %s\n" "$@" exit 1 } info() { printf "info >> %s\n" "$@" } # remove tmpdir remove_tmpdir() { rm -rf "$tmpdir" } # change current directory to script directory if user haven't do it check_currentdir() { script_dir=$(dirname $(readlink -f -- "$0")) [ "$PWD" = "$script_dir" ] || { cd "$script_dir" || panic "failed to change directory" } } # check needed files check_requirements() { # TODO use system busybox for f in ./init ./busybox; do [ -e "$f" ] || panic "$f doesn't exists" done # TODO handle busybox requirements ( busybox --list | grep ash ) } # create FHS directory structure create_structure() { for d in dev tmp var run etc usr/lib usr/bin mnt/root proc root sys; do mkdir -p "${tmpdir}/${d}" done } # some dynamically linked libraries and binaries compiled with hardcoded # dependencies path. to make it worked we need create symlinks for them. # also POSIX ln doesn't have --relative flag like in GNU ln. as workaround # we change directory to tmpdir and make needed symlinks. create_symlinks() { ( cd "$tmpdir" && { ln -s usr/lib lib ln -s usr/lib lib64 ln -s usr/bin bin ln -s usr/bin sbin ln -s ../run var/run cd "${tmpdir}/usr" ln -s bin sbin ln -s lib lib64 } ) } #parse_fstab() { # TODO parse fstab #while [ "$use_fstab" -eq 1 ] && read fs dir type opts; do thing; done < /etc/fstab #} #parse_crypttab() { # TODO parse crypttab #} # install mdev install_mdev() { install -m644 mdev.conf -t "${tmpdir}/etc" install -Dm755 storage-device -t "${tmpdir}/lib/mdev" } # install mdevd install_mdevd() { install_binaries mdevd mdevd-coldplug install -m644 mdev.conf -t "${tmpdir}/etc" install -Dm755 storage-device -t "${tmpdir}/lib/mdev" } # install udev install_udev() { install_binaries udevd udevadm dmsetup # FIXME rewrite this piece of crap find /usr/lib/udev -type f | grep -v "rc_keymaps\|hwdb.d" | cpio -pd "$tmpdir" >/dev/null 2>&1 } # handle lvm install_lvm() { install_binaries lvm # FIXME this code doesn't working with udev #mkdir "$tmpdir/etc/lvm" # use_lvmetad = 0 - avoid lvmetad missing warning message #cat < "$tmpdir/etc/lvm/lvmlocal.conf" #local { # issue_discards = ${lvm_discard:-0} # use_lvmetad = 0 #} #EOF # TODO implement use_lvmconf } # handle luks install_luks() { install_binaries cryptsetup # avoid locking directory missing warning message mkdir "${tmpdir}/run/cryptsetup" # TODO get rid of this workaround # workaround for luks2 install -s -m755 /usr/lib/libgcc_s.so.1 -t "${tmpdir}/usr/lib" [ "$luks_discard" = 1 ] && luks_args="--allow-discards $luks_args" # TODO detached header # TODO keyfile } # TODO implement hostonly mode # install drivers install_drivers() { modker="${moddir}${kernel}" find \ "${modker}/kernel/drivers/virtio" \ "${modker}/kernel/arch" \ "${modker}/kernel/crypto" \ "${modker}/kernel/fs" \ "${modker}/kernel/lib" \ "${modker}/kernel/drivers/block" \ "${modker}/kernel/drivers/ata" \ "${modker}/kernel/drivers/md" \ "${modker}/kernel/drivers/scsi" \ "${modker}/kernel/drivers/usb/storage" \ "${modker}/kernel/drivers/usb/host" \ -type f | cpio -pd "$tmpdir" >/dev/null 2>&1 # install list of drivers cp "${modker}/modules.softdep" "${modker}/modules.builtin" "${modker}/modules.order" "${tmpdir}/${modker}" # generate dependencies list of drivers depmod -b "$tmpdir" "$kernel" } # TODO make strip optional # handle binaries install_binaries() { for b in $(printf "%s\n" "$@" | tr " " "\n"); do # check binary existence command -v "$b" >/dev/null 2>&1 || panic "$b doesn't exists" # install and strip binary install -s -m755 "$(command -v $b)" -t "${tmpdir}/usr/bin" # check statically linking ldd "$(command -v $b)" >/dev/null 2>&1 || continue # install libraries install_libraries $b done } # TODO make strip optional # handle libraries install_libraries() { for l in $(ldd "$(command -v $1)" | sed -nre 's,.* (/.*lib.*/.*.so.*) .*,\1,p' -e 's,.*(/lib.*/ld.*.so.*) .*,\1,p'); do # check symlink if [ -h "$l" ]; then # check lib already existence if [ ! -e "${tmpdir}/usr/lib/${l##*/}" ] && [ ! -e "${tmpdir}/$(readlink -f $l)" ]; then # regular install -s -m755 "$(readlink -f $l)" -t "${tmpdir}/usr/lib" # FIXME handle all symlinks # symlink may link to symlink [ -h "/usr/lib/$(readlink $l)" ] && cp -a "/usr/lib/$(readlink $l)" "${tmpdir}/usr/lib" # symlink cp -a "$l" "${tmpdir}/usr/lib" fi else if [ ! -e "${tmpdir}/usr/lib/${l##*/}" ]; then install -s -m755 "$l" -t "${tmpdir}/usr/lib" fi fi done } install_files() { # FIXME eof broken # initialize config cat < "${tmpdir}/config" debug="$debug" root="$root" root_type="$root_type" root_args="$root_args" devmgr="$devmgr" #drivers="$drivers" use_lvm="$use_lvm" use_luks="$use_luks" luks_root="$luks_root" luks_header="$luks_header" luks_keyfile="$luks_keyfile" luks_args="$luks_args" EOF # needed for devmgr cat < "${tmpdir}/etc/group" root:x:0: tty:x:5: dialout:x:11: uucp:x:14: kmem:x:3: input:x:25: video:x:13: audio:x:12: lp:x:10: disk:x:9: cdrom:x:16: tape:x:6: kvm:x:24: floppy:x:8: EOF # needed for devmgr cat < "${tmpdir}/etc/passwd" root:x:0:0::/root:/bin/sh nobody:x:99:99::/:/bin/false EOF # install init script install -m755 ./init -t "$tmpdir" } # TODO add more compession tools # create and compress cpio archive create_initramfs() { { ( cd "$tmpdir" && { find . | cpio -oH newc | gzip -9 } ) > "${script_dir}/initramfs-${kernel}.img.gz" } >/dev/null 2>&1 [ "$?" = 0 ] || panic "failed to generate initramfs image" } # check root [ "$(id -u)" = 0 ] || panic "must be run as root" check_currentdir # source config . ./config || panic "./config doesn't exists" # handle debug mode [ "$debug" = 1 ] && { # debug shell commands set -x # don't remove anything trap : EXIT INT } # remove tmpdir on exit or unexpected error trap remove_tmpdir EXIT INT # variables tmpdir="$(mktemp -d /tmp/initramfs.XXXXXXXX)" || panic "failed to create working directory" kernel="$(uname -r)" moddir="/lib/modules/" check_requirements create_structure create_symlinks #parse_fstab #parse_crypttab install_binaries $binaries install_drivers install_files # handle device manager case "$devmgr" in mdev) install_mdev ;; mdevd) install_mdevd ;; udev) install_udev ;; *) panic "devmgr option broken" ;; esac [ "$use_luks" = 1 ] && install_luks [ "$use_lvm" = 1 ] && install_lvm create_initramfs info "done! check out initramfs-${kernel}.img.gz"