#!/bin/sh # # /sbin/init # # This init script can be run from an inittar (or initrd) to boot a system # in the traditional way (i.e. with root=/dev/...) # # It loads all required modules (see /etc/load-modules for explanation), # optionally executes /etc/rc, mounts the fileystem given by $root or in # /proc/sys/kernel/real-root-dev, exchanges the current root (tmpfs or # ramdisk) with $root using pivot_root(8) and chroot(8). # # Filesystem situation before pivot_root/chroot: # # tmpfs tmpfs / # $root any $new_root # # Situation right after pivot_root/chroot: # # $root any / # tmpfs tmpfs $old_root # # where $new_root and $old_root are /mnt per default (on different fileystems, # of course). # # If the kernel starts with a premounted devfs, the script also mounts # a devfs on $root and unmounts the devfs on the tmpfs. # # Note that you still have to unmount $old_root from within /sbin/init on the # new rootfs. # # Matthias Kilian , 30.11.2001 # # TODO: # - pass additional command line arguments to the "real" /sbin/init # - include fancy things like fsck'ing the real root device. version=0.9.1 PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin export PATH # Just a simple echo with RDINIT prefix: say() { echo -n "RDINIT: " echo "$@" } # Who the hell is general failure? fail() { say "Error: $*" >& 2 say Giving up, dropping you into a shell. Good luck! # May be someone wants to check what happened... exec /bin/sh -i } # Should this script exit (for whatever reason), give an error message and # start a shell trap "fail exit." 0 # Some configuration for used mountpoints # $new_root is the mountpoint on tmpfs used for mounting the new rootfs. new_root=mnt # $mntpts contains a space separated list of other valid mountpoints on # $new_root used for the tmpfs mntpts="mnt newroot new-root" # Special mountpoint. If it exists on $new_root, the tmpfs will stay here # after the pivot_root, and it will *not* be unmounted. keep_mntpt=initfs say "initrd/inittar bootup script, version $version" say "2001, Matthias Kilian" say "args: $*" say "press RETURN within 5 seconds to get an interactive shell" ( trap "exit 1" 15; sh -c '( sleep 5 && kill $$ )& read _' ) > /dev/null 2>&1 && exec /bin/sh -i # Run /etc/rc, if it exists if [ -x /etc/rc ]; then say run /etc/rc /etc/rc else # Load modules say load modules /etc/load-modules || fail /etc/load-modules fi # mount /proc test -d /proc || mkdir /proc || fail mkdir /proc test -e /proc/mounts || mount -t proc proc /proc || fail mount -t proc proc /proc # check for devfs unset usedevfs while read dev dir fstype _; do if [ "$dir" = /dev -a "$fstype" = devfs ]; then say "there's a devfs mounted" usedevfs=y break fi done < /proc/mounts # Mount new root filesystem, given in $root or in # /proc/sys/kernel/real-root-dev. if [ -z "$root" ]; then rrd=/proc/sys/kernel/real-root-dev say root not set, looking up $rrd if [ -r "$rrd" ]; then mm=$(cat "$rrd") || fail cannot read $rrd major=$(($mm / 256)) || fail "major=$(($mm / 256))" minor=$(($mm % 256)) || fail "minor=$(($mm % 256))" say found "$major:$minor, creating /dev/root" root=/dev/root mknod $root b $major $minor || fail mknod $root b $major $minor else fail $rrd does not exist fi fi test -d /$new_root || mkdir /$new_root || fail mkdir /$new_root say mounting $root mount -r $root /$new_root || fail mount $root /$new_root # If we've devfs mounted, mount it on the new root, too if [ "$usedevfs" = y ]; then say mount devfs on new rootfs mount -t devfs none /$new_root/dev || fail mount -t devfs none /$new_root/dev fi # Redirect stdin, stdout and stderr to /dev/console on the *new* root # fs. Without this redirection, it would impossible to unmount # $old_root later. say redirect stdin, stdout and stderr to console on /$new_root console=/$new_root/dev/console exec < $console > $console 2>&1 || fail redirection # Now, unmount devfs on initfs if [ "$usedevfs" = y ]; then say unmount devfs from initfs umount /dev || fail umount /dev fi umount /proc || fail umount /proc cd /$new_root || fail cd /$new_root # Check for a valid mountpoint. say -n searching a mountpoint for initfs... for mp in $keep_mntpt $mntpts; do echo -n " $mp" test -d $mp && old_root=$mp && break done echo test -n "$old_root" || fail no valid mountpoint found say mountpoint for initfs: $old_root if [ "$old_root" != "$keep_mntpt" ]; then :> /.dontkeep fi # Exchange current and new root filesystem, leaving current # filesystem in $old_root. say swap initfs and rootfs pivot_root . $old_root || fail pivot_root . $old_root # Some preparation on the new root filesystem. Finally, the *real* # /sbin/init is launched. say chroot to new rootfs exec chroot . /bin/sh <<- EOF if [ -e /$old_root/.dontkeep ]; then echo RDINIT: umount /$old_root umount /$old_root > /dev/null 2>&1 || echo RDINIT: Error: could not unmount /$old_root fi echo INIT: starting /sbin/init "$@" exec /sbin/init "$@" EOF # Should't happen fail either the inittar is broken or /sbin/init is missing.