#!/bin/sh VERSION=0.10 HELP="init for early userspace v$VERSION, (c) Denis Kaganovich, Anarchy or GPLv2 license Main goal: scan '/sys/*/uevent' for MODALIASes (without grep, sed...) and load via external insmod only (trying to use standard modprobe and kernel configuration). And standard bootload.. Moving all pseudofs to newroot controlled by pre-created empty /dev. Usage: as /sbin/init, + /etc/modprobe.d, etc; or symlink to /sbin/modprobe; or \"$0 --sort .../modules.alias [slow] >modules.alias\" - to make new better modules order; or \"$0 --dry-run []\" - to scan /sys/devices -> modules [] -> stdout." #[ -e /dev/shm ] && : ${TMPDIR:=/dev/shm} tmp="${TMPDIR:-/tmp}/init_" BOOT=false MOUNTED=false modprobe="$0" mod=mod A=a [ -e /bin/nuke ] && rm=/bin/nuke || rm=rm # fast moved from my other place, better to overcode here last="usb_storage nvidiafb radeonfb intelfb snd_pcsp ata_generic pata_acpi ide_core sound" # for sort barrier=256 first="tpm_tis" msg=true _i(){ $rm -f "install/$1" "remove/$1" } KV(){ read KV "options/$n.${i%%=*}" done $cmd "$n" $mod "$n" fi } mdevs(){ local i s for i in /sys/class/*/*/uevent; do [ -e "$tmp$1$i" ] && continue mkdir -p "$tmp$1$i" local DEVNAME='' MAJOR='' MINOR='' FIRMWARE='' DEVPATH='' DEVMODE='' x='' t=c while read s; do x="${s%%=*}" case "$x" in DEVNAME|MAJOR|MINOR|FIRMWARE|DEVPATH|DEVMODE)eval "$x='${s#*=}'";; esac done <$i if [ -n "$FIRMWARE" ] && [ -z "$1" ] && echo 1 >/sys/$DEVPATH/loading; then [ -e /lib/firmware/$FIRMWARE ] && cat /lib/firmware/$FIRMWARE >/sys/$DEVPATH/data && echo 0 >/sys/$DEVPATH/loading || echo -1 >/sys/$DEVPATH/loading fi if [ -n "$DEVNAME" ] && ! [ -e "$1/dev/$DEVNAME" ]; then DEVNAME="$1/dev/$DEVNAME" [ -z "${i##/sys/class/block/*}" ] && t=b i="${DEVNAME%/*}" [ -e "$i" ] || mkdir -p "$i" mknod -m ${DEVMODE:-0600} "$DEVNAME" $t $MAJOR $MINOR fi done } modp(){ if [ -e "alias/$1" ]; then [ -L "alias/$1" ] && readlink "alias/$1" >>modules.lst || echo "$1" >>modules.lst fi [ -e "$A/$1" ] || mkdir -p "$A/$1" } sys_modalias(){ local i x if [ -e "$1/uevent" ] && i=" `cat "$1/uevent"`"; then i=" $i" x="${i#* MODALIAS=}" [ "$i" != "$x" -a -n "${i##* DRIVER=*}" ] && modp "${x%% *}" elif [ -e "$1/modalias" ] && read x <"$1/modalias"; then modp "$x" fi for i in "$1"/* ; do [ -d "$i" ] && [ ! -L "$i" ] && sys_modalias "$i" done } early_huge(){ local d=/sys/kernel/mm/transparent_hugepage [ "${_cmd_transparent_hugepage_misc}" = true -a -d $d ] || return case "`cat $d/enabled`" in *\[never\]*)return;; esac echo defer+madvise >$d/defrag 2>/dev/null||echo defer >$d/defrag||return echo always >$d/shmem_enabled } init(){ local i='-o nosuid,nodev,noexec' l mount -t proc $i proc /proc && mount -t sysfs $i sys /sys || return KV BOOT=true mkdir /newroot [ -e /bin/busybox ] && /bin/busybox --install -s mdevs if ! [ -e /dev/loop1 ]; then insmod $libmod/kernel/drivers/block/loop.ko insmod $libmod/kernel/fs/squashfs/squashfs.ko mdevs fi for i in /*loop* /*.squahfs; do [ -e "$i" ] || continue l="${i##*.}" [ -b "$l" ] || l=`losetup -f` losetup $l $i && mount -r -t squashfs $l /${i%.*} done 2>/dev/null mount -a 2>/dev/null echo "$modprobe" >/proc/sys/kernel/modprobe #echo "$0" >/proc/sys/kernel/hotplug } cmd(){ local i x xx y yy m c='' for i in "${@}"; do x="${i%%=*}" if [ "$x" = "$i" ]; then xx='_cmd_' yy='' x="${x#!}" [ "$x" = "$i" ] && y=true || y=false else xx='cmd_' y="${i#*=}" yy="=$y" fi m="${x%%.*}" if [ "$m" = "$x" ]; then case "${x#real_}" in # [^...] broken in klibc quiet|root|init|rw|ro|resume|resume_offset|nfsroot|ip|rootdelay|rootwait|rootflags|rootfstype|loop|transparent_hugepage_misc)export $xx$x="$y";; esac elif ! [ -e cmdline ]; then [ -d options ] && echo -n " ${x#*.}$yy" >"options/$x" || echo -n "options $m ${x#*.}$yy" >>"/etc/modprobe.d/initrd_$x.conf" fi done #cmd_init=/sbin/init #cmd_root="${cmd_real_root:-${cmd_root:-$root}}" #cmd_init="${cmd_real_init:-${cmd_init:-$init}}" #cmd_resume="${cmd_real_resume:-${cmd_resume:-$resume}}" init=/sbin/init cmd_root="${cmd_real_root:-$root}" cmd_init="${cmd_real_init:-$init}" cmd_resume="${cmd_real_resume:-$resume}" ${_cmd_quiet:-true} || msg=echo } cmdline(){ [ $modprobe != /sbin/modprobe ] && mkdir -p options read cmdline cmdline } mod(){ local l='' i m ok err=true [ -z "$*" ] && return for i in "${@}"; do read i <"alias/$i" && i=" $i" && while [ -n "$i" ]; do l="$l ${i##* }" i="${i% *}" done done cd $A && mkdir -p "${@}" while $err; do cd $libmod ok=false err=false for m in $l; do i="${m##*/}" i="${i%%.*}" [ -e "$tmp/alias/$i" ] || continue CMDLINE_OPTS=`cat "$tmp/options/$1."* 2>/dev/null` $msg -n " $i" if [ -e "$tmp/install/$m" ]; then read i <"$tmp/install/$m" eval "$i" && ok=true || err=true elif insmod "$m" "$CMDLINE_OPTS"; then ok=true $rm "$tmp/alias/$i" # $rm "`readlink -f "$tmp/alias/$i"`" else err=true fi done $msg $ok || break cd "$tmp/alias" && $rm -f `cd /sys/module && echo *` done cd $tmp || exit 1 } dep1(){ [ -s modules.lst ] || return mod `cat modules.lst` $rm -f modules.lst modules/* } conf(){ [ -e alias ] && return local i m cmd x d mkdir -p a alias modules options install remove softdep later echo -n >>modules.lst while read m d; do m="${m%:}" x="${m##*/}" x="${x%%.*}" i="$x" while [ -z "${i##*-*}" ]; do i="${i%%-*}_${i#*-}" done [ -e "/sys/module/$i" ] && ${1:-continue} echo "$m $d" >>"alias/$i" [ "$x" != "$i" ] && ln -s "$i" "alias/$x" done <$libmod/modules.dep for i in /etc/modprobe.d/*; do [ -e "$i" ] && while read cmd m i; do case "$cmd" in alias) echo "alias $m $i" >>conf;; options)echo -n " $i" >"options/$m.${i%%=*}";; blacklist) [ -L "$m" ] && m=`readlink "alias/$m"` $rm -f "alias/$m" ;; install|remove|softdep)echo " $i" >"$cmd/$m";; esac done <$i done cat $libmod/modules.alias >>conf 2>/dev/null # ( cd alias && mv $last ../later/ 2>/dev/null ) #bug for i in $last; do mv -f alias/$i later/ 2>/dev/null done } dep(){ local i m cmd x d mod=mod dep1 while read cmd m i; do set $A/$m [ -e "$1" ] && [ -e "$cmd/$i" ] && ! [ -e "modules/$i" ] && echo "$i" >>modules.lst 2>"modules/$i" done /dev/null } fs_loop(){ mkdir -p /looproot local l i for i in /newroot/$1; do [ -e "$i" ] && l=`losetup -f` && losetup "$l" "$i" || continue mount -r -t squashfs "$l" /looproot && mount -o move /newroot /looproot/boot && mount -o move /looproot /newroot && return 0 umount /looproot losetup -d "$l" done return 1 } fs(){ if [ -e "$1" ]; then [ -e "$tmp/mnt/$1" ] && return 1 ${_cmd_rootwait:-false} || mkdir -p "$tmp/mnt/$1" elif $MOUNTED; then return 1 elif [ "$1" = /dev/nfs ]; then #nfsmount -p /pmap_lock -o lock $cmd_nfsroot /newroot || nfsmount $cmd_nfsroot /newroot || return 1 [ -z "$2" ] || fs_loop "$2" || ! umount /newroot && MOUNTED=true return $? elif [ -z "$cmd_rootfstype" ]; then return 1 fi local i x y o="${cmd_rootflags:+-o $cmd_rootflags}" fs="`cat /proc/filesystems` t="${cmd_rootfstype:+TYPE=$cmd_rootfstype}" unknown " ! ${_cmd_rw:-false} || ${_cmd_ro:-false} && o="$o -r" [ -n "$cmd_rootdelay" ] && sleep $cmd_rootdelay for i in ${t:-`{ fstype "$1";blkid "$1";} 2>/dev/null`}; do #` case "$i" in FSTYPE=*|TYPE=*) i="${i#*=}" i="${i#\"}" i="${i%\"}" [ -n "${fs##* $i *}" ] && [ -e "alias/$i" ] && mod "$i" ! $BOOT || $MOUNTED && continue mount $o -t $i "$1" /newroot 2>/dev/null || continue if [ -n "$2" ]; then fs_loop "$2" && MOUNTED=true else [ "$cmd_root" = "$1" ] && MOUNTED=true && continue if [ -z "${1##$cmd_root}" ] && [ -e "/newroot/$cmd_init" ] && [ -e /newroot/etc/fstab ]; then while read i x y; do [ "$i:$x" = "$cmd_root:/" ] && MOUNTED=true && break done "$i" && r=0 done 2>/dev/null return $r } modaliases(){ local i mm="`cat /proc/modules`" m1='-' fs m d p n='/newroot' sm=/sys/module/scsi_mod/parameters sms= smf= cnt= mkdir -p "$tmp/sys/class/*/*/uevent" "$tmp/options" cd $tmp||exit 1 echo -n '^' conf cmdline early_huge own 2>/dev/null while [ "$m1" != "$mm" -o "${_cmd_rootwait}:$MOUNTED" = 'true:false' ]; do echo -n "*" mod=modp sys_modalias /sys/devices 2>/dev/null echo -n "#" dep echo -n "+" for i in scsi_wait_scan scsi_mod; do m="$libmod/kernel/drivers/scsi/$i.ko" [ -e $m ] && insmod $m "`cat "$tmp/options/$1."* 2>/dev/null`" && [ $i = scsi_wait_scan ] && rmmod $i done resume "$cmd_resume" $cmd_resume_offset 2>/dev/null flags `cd /sys/module && echo *` 2>/dev/null mdevs if [ -n "$cmd_ip" ] && ! [ -e "$tmp/ip/$cmd_ip" ] && ipconfig "$cmd_ip"; then mkdir -p "$tmp/ip/$cmd_ip" ipconfig 127.0.0.1:::::lo:none fi if [ "$cmd_root" = "*" ]; then while read i i i i; do fs "/dev/$i" "$cmd_loop" done $sm/default_dev_flags && m1="$m1+" && echo 'try scsi_mod.default_dev_flags=0x240';; .|...) read sms <$sm/scan && [ "$sms" = async ] && echo sync >$sm/scan _tee '- - -' /sys/class/scsi_host/host*/scan && m1="$m1+" #_tee 1 /sys/class/scsi_device/*/device/rescan && m1="$m1+" #_tee 1 /sys/class/scsi_disk/*/device/rescan && m1="$m1+" [ "$sms" = async ] && echo async >$sm/scan ;; *)break;; esac done fi done echo '' if $BOOT; then echo /sbin/modprobe >/proc/sys/kernel/modprobe if ! [ -e "$n/$cmd_init" ]; then echo "Not found '$n/$cmd_init' - try shell:" exec sh fi for i in /dev /proc /sys; do mkdir -p $n$i mount --move $i $n$i || break rmdir $i && ln -s $n$i $i done 2>/dev/null [ -e $n/dev ] && [ ! -e $n/dev/console ] && (mount -t devtmpfs -o exec,nosuid,mode=0755,size=10M udev $n/dev || mount -t tmpfs dev $n/dev) [ -e /dev/console ] || mdevs $n p="$n/usr/src/linux-$KV" [ -L "$n/$libmod/kernel" ] && [ -e "$p.squashfs" ] && i=`losetup -f` && losetup $i $p.squashfs && mount -r -t squashfs $i $p echo -n "Boot: [$cmd_root] " cat /proc/uptime cat /proc/mounts|while read d p i; do case "$d:$p" in rootfs:/);; *:/newroot*)echo " $p $d $i";; /dev/loop*)umount $p&&losetup -d $d;; *:/dev)mount --move $p /newroot/$p;; *)umount $p 2>/dev/null;; esac done i=/sbin/switch_root [ -e $i ] || i=run-init exec $i -c /dev/console $n $cmd_init fi } # main idea to load more unique IDs first # (some of non-unique are bad "common" choice, but some - required) # # ideally to count cross-matches and move most uniue first & # some too common better be first ( > $barrier) # # but faster (and good here) to count only non-wildcard ("id") characters sortaliases(){ local cmd a m mm tmp="$tmp$$" $rm -Rf "$tmp/aa" "$tmp/aaa" "$tmp/a0" "$tmp/a9" mkdir -p "$tmp/aa" "$tmp/aaa" "$tmp/a0" "$tmp/a9" cd "$tmp/a0" && mkdir $first && cd "$tmp/a9" && mkdir $last || return 1 case "$2" in slow) cd "$tmp"||return 1 while read cmd a m; do [ "$cmd" != alias ] && continue aa="$a" while [ -z "${aa##*\[*\]*}" ]; do aa="${aa%%\[*\]*}?${aa#*\[*\]}" done while [ -z "${aa##*/*}" ]; do aa="${aa%%/*}\\${aa#*/}" done echo "$a $m" >>"aa/$aa"||return 1 done <$1 for aa in aa/*; do set $aa [ -e "$1" ] || exit 1 m="$#" [ $m -gt $barrier ] && m=0 read a mm <"$aa" [ -e "a0/$mm" ] && m=0 [ -e "a9/$mm" ] && m=9999 m="00000$m" echo "alias $a $mm" >>"aaa/${m#${m%?????}}" done <$1 cat aaa/* ;; *) cd $tmp/aa||return 1 while read cmd a m; do [ "$cmd" != alias ] && continue aa="$a" while [ -z "${aa##*\[*\]*}" ]; do aa="${aa%%\[*\]*}${aa#*\[*\]}" done while [ -z "${aa##*\**}" ]; do aa="${aa%%\**}${aa#*\*}" done while [ -z "${aa##*[^x]*}" ]; do aa="${aa%%[^x]*}x${aa#*[^x]}" done [ -e "$tmp/a0/$m" ] && aa=z [ -e "$tmp/a9/$m" ] && aa=a echo "alias $a $m" >>"$aa"||return 1 done <$1 i=`ls -1r`||return 1 cat $i /dev/null dep rm -rf $tmp } doinit=true case $0 in */kpnp)doinit=false;; */modprobe) KV A="a$$" modprobe "${@}" dep $rm -Rf "$tmp/$A" exit ;; esac [ -e /proc/version ] && KV || init false && if /sbin/modprobe -aVA >/dev/null 2>&1; then modprobe=/sbin/modprobe $BOOT && echo /sbin/modprobe >/proc/sys/kernel/modprobe modprobe(){ /sbin/modprobe "${@}";} modp(){ modprobe -- "$1";} mod(){ modprobe -a -- "${@}";} dep(){ return;} conf(){ return;} if [ "`readlink /sbin/modprobe`" = /etc/modprobe.sh ]; then . /etc/modprobe.sh fi fi case "$1" in -q) if [ "$2" = '--' ]; then modprobe "${@}" >/dev/null >&1 else modaliases fi ;; --sort) shift sortaliases "${@}"||{ echo ERROR >&2 exit 1 } ;; --dry-run) shift dry "${@}" ;; -h|--help)echo "$HELP";; *)if $doinit || $BOOT; then modaliases else echo "$HELP" fi ;; esac