383 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			383 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| #
 | |
| # tiny initramfs generation tool
 | |
| 
 | |
| # print message
 | |
| msg() {
 | |
|     case "$1" in
 | |
| 	info)
 | |
| 	    printf "info >> %s\n" "$2" >&2
 | |
| 	    ;;
 | |
| 	panic)
 | |
| 	    printf "panic >> %s\n" "$2" >&2
 | |
| 	    exit 1
 | |
| 	    ;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| # remove tmpdir
 | |
| remove_tmpdir() {
 | |
|     msg info "removing work dir"
 | |
|     rm -rf "$tmpdir"
 | |
| }
 | |
| 
 | |
| # change current directory to script directory if user haven't do it
 | |
| check_currentdir() {
 | |
|     msg info "changing directory to script dir"
 | |
|     script_dir=$(dirname $(readlink -f -- "$0"))
 | |
|     [ "$PWD" = "$script_dir" ] || {
 | |
| 	cd "$script_dir" || msg panic "failed to change directory"
 | |
|     }
 | |
| }
 | |
| 
 | |
| # check needed files
 | |
| check_requirements() {
 | |
|     msg info "checking requirements"
 | |
|     # TODO use system busybox
 | |
|     for f in ./init ./busybox; do
 | |
| 	[ -e "$f" ] || msg panic "$f doesn't exists"
 | |
|     done
 | |
| 
 | |
|     # TODO handle busybox requirements ( busybox --list | grep ash )
 | |
| }
 | |
| 
 | |
| # create FHS directory structure
 | |
| create_structure() {
 | |
|     msg info "creating directory 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() {
 | |
|     msg info "creating 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() {
 | |
|     msg info "installing mdev"
 | |
|     install -m644 mdev.conf -t "${tmpdir}/etc"
 | |
|     install -Dm755 storage-device -t "${tmpdir}/lib/mdev"
 | |
| }
 | |
| 
 | |
| # install mdevd
 | |
| install_mdevd() {
 | |
|     msg info "installing 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() {
 | |
|     msg info "installing 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() {
 | |
|     msg info "installing LVM"
 | |
|     install_binaries lvm
 | |
| 
 | |
|     # if hostonly mode enabled install only needed drivers
 | |
|     [ "$hostonly" = 1 ] && {
 | |
| 	for lvm_driver in dm-thin-pool dm-multipath dm-snapshot dm-cache dm-log dm-mirror; do
 | |
| 	    for lvm_driver_dep in $(modprobe -D "$lvm_driver" 2>/dev/null | grep -v builtin | cut -d " " -f 2); do
 | |
| 		install -Dm644 "$lvm_driver_dep" "${tmpdir}${lvm_driver_dep}"
 | |
| 	    done
 | |
| 	done
 | |
|     }
 | |
| 
 | |
|     # FIXME this code doesn't working with udev
 | |
|     #mkdir "$tmpdir/etc/lvm"
 | |
|     # use_lvmetad = 0 - avoid lvmetad missing warning message
 | |
|     #cat <<EOF > "$tmpdir/etc/lvm/lvmlocal.conf"
 | |
|     #local {
 | |
|     #	issue_discards = ${lvm_discard:-0}
 | |
|     #	use_lvmetad = 0
 | |
|     #}
 | |
|     #EOF
 | |
|     # TODO implement use_lvmconf
 | |
| }
 | |
| 
 | |
| # handle luks
 | |
| install_luks() {
 | |
|     msg info "installing LUKS"
 | |
|     install_binaries cryptsetup
 | |
| 
 | |
|     # if hostonly mode enabled install only needed drivers
 | |
|     [ "$hostonly" = 1 ] && {
 | |
| 	for luks_driver in aes dm-crypt sha256 sha512 wp512 ecb lrw xts twofish serpent; do
 | |
| 	    for luks_driver_dep in $(modprobe -D "$luks_driver" 2>/dev/null | grep -v builtin | cut -d " " -f 2); do
 | |
| 		install -Dm644 "$luks_driver_dep" "${tmpdir}${luks_driver_dep}"
 | |
| 	    done
 | |
| 	done
 | |
|     }
 | |
| 
 | |
|     # 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" || msg panic "failed to install LUKS libraries"
 | |
| 
 | |
|     # block discard support
 | |
|     [ "$luks_discard" = 1 ] && luks_args="--allow-discards $luks_args"
 | |
| 
 | |
|     # copy luks header
 | |
|     [ -f "$luks_header" ] && {
 | |
| 	install -m400 "$luks_header" "${tmpdir}/root/luks_header" || msg panic "failed to copy LUKS header"
 | |
| 	luks_args="--header=/root/luks_header $luks_args"
 | |
|     }
 | |
| 
 | |
|     # copy luks keyfile
 | |
|     [ -f "$luks_keyfile" ] && {
 | |
| 	install -m400 "$luks_keyfile" "${tmpdir}/root/luks_keyfile" || msg panic "failed to copy LUKS keyfile"
 | |
| 	luks_args="--key-file=/root/luks_keyfile $luks_args"
 | |
|     }
 | |
| }
 | |
| 
 | |
| # install drivers
 | |
| install_drivers() {
 | |
|     msg info "installing hostonly drivers"
 | |
|     [ -n "$root_type" ] || msg panic "hostonly mode required root_type option to be configured"
 | |
| 
 | |
|     # perform autodetection of drivers via /sys
 | |
|     for driver in $(find /sys/devices -name modalias -exec sort -u "{}" "+"); do
 | |
|         for driver_dep in $(modprobe -D "$driver" 2>/dev/null | grep -v builtin | cut -d " " -f 2); do
 | |
| 	    install -Dm644 "$driver_dep" "${tmpdir}${driver_dep}"
 | |
|         done
 | |
|     done
 | |
| 
 | |
|     # TODO autodetect root fs driver
 | |
|     # TODO separate root type option
 | |
|     # install root fs driver
 | |
|     for root_driver in $(modprobe -D "$root_type" 2>/dev/null | grep -v builtin | cut -d " " -f 2); do
 | |
|         install -Dm644 "$root_driver" "${tmpdir}${root_driver}"
 | |
|     done
 | |
| 
 | |
|     # install user specified drivers
 | |
|     [ -n "$drivers" ] && {
 | |
| 	for custom_driver in $(printf "%s\n" "$drivers" | tr " " "\n"); do
 | |
| 	    for custom_driver_dep in $(modprobe -D "$custom_driver" 2>/dev/null | grep -v builtin | cut -d " " -f 2); do
 | |
| 		install -Dm644 "$custom_driver_dep" "${tmpdir}${custom_driver_dep}"
 | |
| 	    done
 | |
| 	done
 | |
|     }
 | |
| }
 | |
| 
 | |
| # find and install all drivers
 | |
| install_all_drivers() {
 | |
|     msg info "installing all drivers"
 | |
|     find \
 | |
|         "${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" \
 | |
|         "${modker}/kernel/drivers/virtio" \
 | |
|         -type f | cpio -pd "$tmpdir" >/dev/null 2>&1
 | |
| }
 | |
| 
 | |
| # generate "modules" files
 | |
| generate_depmod() {
 | |
|     msg info "generating dependendies list of drivers"
 | |
|     # 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
 | |
| 	msg info "installing binary $b"
 | |
| 	# check binary existence
 | |
| 	command -v "$b" >/dev/null 2>&1 || msg 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
 | |
| 	msg info "installing library $l"
 | |
| 	# 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 important files used by init
 | |
| install_files() {
 | |
|     msg info "installing files"
 | |
|     # FIXME eof broken
 | |
|     # initialize config
 | |
|     cat <<EOF > "${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_args="$luks_args"
 | |
| EOF
 | |
| 
 | |
|     # needed for devmgr
 | |
|     cat <<EOF > "${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 <<EOF > "${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() {
 | |
|     msg info "creating initramfs image"
 | |
|     {
 | |
| 	( cd "$tmpdir" && {
 | |
| 	    find . | cpio -oH newc | gzip -9
 | |
| 	} ) > "${script_dir}/initramfs-${kernel}.img.gz"
 | |
|     } >/dev/null 2>&1
 | |
| 
 | |
|     [ "$?" = 0 ] || msg panic "failed to generate initramfs image"
 | |
| }
 | |
| 
 | |
| # check root
 | |
| [ "$(id -u)" = 0 ] || msg panic "must be run as root"
 | |
| 
 | |
| # remove tmpdir on exit or unexpected error
 | |
| trap remove_tmpdir EXIT INT
 | |
| 
 | |
| check_currentdir
 | |
| 
 | |
| # source config
 | |
| . ./config || msg panic "./config doesn't exists"
 | |
| 
 | |
| # handle debug mode
 | |
| [ "$debug" = 1 ] && {
 | |
|     # debug shell commands
 | |
|     set -x
 | |
|     # don't remove anything
 | |
|     trap : EXIT INT
 | |
| }
 | |
| 
 | |
| # variables
 | |
| tmpdir="$(mktemp -d /tmp/initramfs.XXXXXXXX)" || msg panic "failed to create working directory"
 | |
| kernel="$(uname -r)"
 | |
| moddir="/lib/modules/"
 | |
| modker="${moddir}${kernel}"
 | |
| 
 | |
| check_requirements
 | |
| 
 | |
| create_structure
 | |
| create_symlinks
 | |
| #parse_fstab
 | |
| #parse_crypttab
 | |
| install_binaries $binaries
 | |
| 
 | |
| if [ "$hostonly" = 1 ]; then
 | |
|     install_drivers
 | |
| else
 | |
|     install_all_drivers
 | |
| fi
 | |
| 
 | |
| generate_depmod
 | |
| 
 | |
| # handle device manager
 | |
| case "$devmgr" in
 | |
|     mdev) install_mdev ;;
 | |
|     mdevd) install_mdevd ;;
 | |
|     udev) install_udev ;;
 | |
|     *) msg panic "devmgr option broken" ;;
 | |
| esac
 | |
| 
 | |
| [ "$use_luks" = 1 ] && install_luks
 | |
| [ "$use_lvm" = 1 ] && install_lvm
 | |
| 
 | |
| install_files
 | |
| create_initramfs
 | |
| 
 | |
| msg info "done! check out initramfs-${kernel}.img.gz"
 |