diff options
author | John Bowler <jbowler@nslu2-linux.org> | 2005-05-23 18:02:35 +0000 |
---|---|---|
committer | John Bowler <jbowler@nslu2-linux.org> | 2005-05-23 18:02:35 +0000 |
commit | 4b72cfb3f2a471ece09a87321a790c92cfe6966f (patch) | |
tree | 49b8bd2df4c5800fa98a5e20f6def71886227a4f /packages/openslug-init/openslug-init-0.10/turnup | |
parent | 25282cd2b0ad770927943ef428f7f4eca869cb98 (diff) |
New /linuxrc boot mechanism
Use "turnup help" to find out how to do turnup now!
BKrev: 42921abbPAuC7JcmxHiVNgYZgCeE5A
Diffstat (limited to 'packages/openslug-init/openslug-init-0.10/turnup')
-rw-r--r-- | packages/openslug-init/openslug-init-0.10/turnup | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/packages/openslug-init/openslug-init-0.10/turnup b/packages/openslug-init/openslug-init-0.10/turnup index e69de29bb2..b688bc3051 100644 --- a/packages/openslug-init/openslug-init-0.10/turnup +++ b/packages/openslug-init/openslug-init-0.10/turnup @@ -0,0 +1,612 @@ +#!/bin/sh +# turnup +# See the help block at the end for documentation. +# +. /etc/default/functions + +# +# force: override certain checks +force= +# +# check_rootfs [-i] <root fs directory> +# Make sure the candidate rootfs is empty +check_rootfs() { + local fcount + + case "$1" in + -i) shift + case "$force" in + -f) return 0;; + esac + + fcount="$(find "$1" ! -type d -print | wc -l)" + test "$fcount" -eq 0 && return 0 + + echo "turnup: $1: partition contains existing files, specify -f to overwrite" >&2 + return 1;; + *) checkmount "$1" && return 0 + + echo "turnup: $1: partition does not seem to be a valid root partition" >&2 + if test -f "$1"/.recovery + then + echo " $1/.recovery exists: fix the partition then remove it" >&2 + fi + return 1;; + esac +} +# +# copy_rootfs old new +# Make a copy of the given root file system, copying only the +# directories needed. The root must be the flash file system +copy_rootfs() { + local old new + old="$1" + new="$2" + test -d "$old" -a -d "$new" || { + echo "turnup: rootfs: copy $old $new: not a directory" >&2 + return 1 + } + # + # There are no problem file names in the flash file system, so + # it is possible to use -print, not -print0. The following + # files and directories are not copied: + # + # /dev/* + # /boot, /boot/* + # /linuxrc* + # /var/* + echo "turnup: copying root file system" >&2 + ( cd "$1" + find . -mount -print | + sed '\@^./dev/@d;\@^./boot/@d;\@^./boot$@d;\@^./linuxrc@d;\@^./var/@d' | + cpio -p -d -m -u "$2" + ) || { + echo "turnup: rootfs: cpio $old $new failed" >&2 + return 1 + } + echo "done" >&2 +} + +# +# setup_dev new device_table +# Populates the /dev directory, removes the ramfs mount of /dev by +# removing the links to the devices startup file. +setup_dev() { + test -n "$1" -a -d "$1"/dev -a -r "$2" || { + echo "turnup: setup_dev($1,$2): expected a directory and a file" >&2 + return 1 + } + # at present the device_table is not used because it is incomplete, + # /etc/init.d/devices adds extra stuff. So this script copies the + # existing /dev. FIXME. + echo "turnup: copying dev file system" >&2 + ( cd / + find dev -print0 | cpio -p -0 -d -m -u "$1" + ) || { + echo "turnup: rootfs: cpio /dev $1 failed" >&2 + return 1 + } + echo "done" >&2 + # now remove the startup links which mount the ramfs on /dev + rm "$1"/etc/rc?.d/[KS]??devices + return 0 +} + +# +# setup_bootdev new device_table +# As above but actually uses the supplied device table - this is possible if +# the table is just used for boot because the extra setup is not required. +setup_bootdev() { + test -n "$1" -a -d "$1"/dev -a -r "$2" || { + echo "turnup: setup_bootdev($1,$2): expected a directory and a file" >&2 + return 1 + } + # NOTE: this fails silently with 0 return code(!) when a directory + # does not exist yet things are created within it. + makedevs -r "$1" -D "$2" +} + +# +# setup_var new type +# Populates /var. Should only be called for true disk systems and NFS - +# it's a waste on USB memory sticks! Removes the /var tmpfs setting +# for disks, sets it to /var/tmp for NFS. +setup_var() { + test -n "$1" -a -d "$1"/var || { + echo "turnup: setup_var($1,$2): expected a directory" >&2 + return 1 + } + case "$2" in + disk|nfs);; + *) echo "turnup: setup_var($1,$2): expected 'disk' or 'nfs'" >&2 + return 1;; + esac + # + # populate /var, there is a shell script to do this, but it uses + # absolute path names + chroot "$1" /bin/busybox sh /etc/init.d/populate-var.sh || { + echo "turnup: /var: could not populate directory" >&2 + return 1 + } + # and remove the startup links + rm "$1"/etc/rc?.d/[KS]??populate-var.sh + # remove the /var tmpfs entry from the new /etc/fstab + case "$2" in + disk) sed -i '\@\s/var\s\s*tmpfs\s@d' "$1"/etc/fstab + echo "turnup: tmpfs will no longer be mounted on /var" >&2;; + nfs) sed -i '\@\s/var\s\s*tmpfs\s@s@\s/var@&/tmp@' "$1"/etc/fstab + echo "turnup: tmpfs /var mount moved to /var/tmp" >&2;; + esac + # + # warn the user - it's not enough to put the /var mount back, it + # is necessary to reinsert the populate-var.sh links! + echo " If you remount tmpfs on /var it must be populated at boot, use:" >&2 + echo " update-rc.d populate-var.sh start 37 S ." >&2 + return 0 +} + +# +# setup_files new +# At present just puts the rmrecovery links in. +setup_files() { + test -n "$1" -a -d "$1"/etc || { + echo "turnup: setup_files($1): expected a directory" >&2 + return 1 + } + # + # add the script to remove .recovery + update-rc.d -r "$1" rmrecovery start 99 1 2 3 4 5 . + return 0 +} + +# +# setup_syslog new +# Moves the syslog to a file - appropriate for disk and nfs types, not +# otherwise. +setup_syslog() { + test -n "$1" -a -d "$1"/etc || { + echo "turnup: setup_syslog($1): expected a directory" >&2 + return 1 + } + # + # if the syslog is to the buffer redirect it to a file + if egrep -q '^DESTINATION="buffer"' "$1"/etc/syslog.conf + then + if cp "$1"/etc/syslog.conf "$1"/etc/syslog.conf.sav + then + # the busybox syslog will fail with ROTATESIZE and ROTATEGENS + sed -i 's!DESTINATION="buffer"!DESTINATION="file"! + /^ROTATESIZE=/d + /^ROTATEGENS=/d' "$1"/etc/syslog.conf + echo "turnup: /etc/syslog.conf: changed to file buffering" >&2 + echo " Old (buffer) version in /etc/syslog.conf.sav" >&2 + echo " Log messages will be in /var/log/messages" >&2 + else + echo "turnup: /etc/syslog.conf: failed to make a copy" >&2 + echo " syslog will log to a buffer" >&2 + fi + fi + return 0 +} + +# +# setup_rootfs type new device_table +# Populates the /dev and /var directories, alters the startup to +# not mount or populate them further. Does the right thing according +# to the given $type +setup_rootfs() { + local type new table + type="$1" + new="$2" + table="$3" + + test -n "$new" -a -d "$new" -a -f "$table" || { + echo "turnup: setup_rootfs($type,$new,$table): expected a directory and a file" >&2 + return 1 + } + + case "$type" in + flash) return 0;; + disk) setup_dev "$new" "$table" && + setup_var "$new" disk && + setup_files "$new" && + setup_syslog "$new";; + memstick) + setup_bootdev "$new" "$table" && + setup_files "$new";; + nfs) setup_dev "$new" "$table" && + setup_var "$new" nfs && + setup_files "$new" && + setup_syslog "$new";; + *) echo "turnup: setup_rootfs: $type: unknown rootfs type" >&2 + return 1;; + esac + # return code of last setup function +} + +# +# boot_rootfs <boot type> <flash file system> <sleep time> <device> [options] +# Change the flash partition (not the current root!) to boot off +# the new root file system +boot_rootfs() { + local type ffs sleep device opt + + type="$1" + ffs="$2" + sleep="$3" + device="$4" + + # test this first as the test does not depend on the correctness + # of the other arguments + test -n "$ffs" -a -d "$ffs" || { + echo "turnup: boot_rootfs($type, $ffs, $device): expected directory" >&2 + return 1 + } + test -x "$ffs"/boot/"$type" || { + echo "turnup: boot_rootfs($type, $ffs, $device): invalid boot type $type" >&2 + return 1 + } + shift + shift + + case "$type" in + disk) test -n "$device" -a -b "$device" || { + echo "turnup: boot_rootfs($ffs, $type, $device): expected block device" >&2 + return 1 + } + shift 2;; + nfs) shift 2;; + flash) ;; + ram) ;; + *) echo "turnup: boot_rootfs($type, $ffs, $device): unknown type" >&2 + return 1;; + esac + + # + # The /linuxrc records the correct options to mount the device, + # since we have already mounted if correctly with these options + # we can be sure (maybe) that the boot will work. If not /boot/disk + # falls back to flash. + # + # This modifies the boot process, until this point no harm has been + # done to the system, but at this point the boot rootfs will change + rm -f "$ffs"/linuxrc.new || { + echo "turnup: boot_rootfs: failed to remove $ffs/linuxrc.new" >&2 + return 1 + } + case "$type" in + flash) ln -s "boot/flash" "$ffs"/linuxrc.new || { + echo "turnup: boot_rootfs: failed to create $ffs/linuxrc.new" >&2 + return 1 + };; + ram) { echo '#!/bin/sh' + echo 'rm -f /linuxrc.new' + echo 'ln -s boot/flash /linuxrc.new' + echo 'mv /linuxrc.new /linuxrc' + echo 'exec /boot/ram /dev/ram0' + echo 'exec /boot/flash' + } >"$ffs"/linuxrc.new && + chmod 744 "$ffs"/linuxrc.new || { + echo "turnup: boot_rootfs: failed to write $ffs/linuxrc.new" >&2 + return 1 + };; + *) { echo '#!/bin/sh' + test "$sleep" -gt 0 && echo -n "sleep='$sleep' " + echo -n "exec '/boot/$type' '$device'" + for opt in "$@" + do + echo -n " '$opt'" + done + echo + echo 'exec /boot/flash' + } >"$ffs"/linuxrc.new && + chmod 744 "$ffs"/linuxrc.new || { + echo "turnup: boot_rootfs: failed to write $ffs/linuxrc.new" >&2 + return 1 + };; + esac + rm -f "$ffs"/linuxrc.sav || { + echo "turnup: boot_rootfs: failed to remove $ffs/linuxrc.sav" >&2 + return 1 + } + ln "$ffs"/linuxrc "$ffs"/linuxrc.sav || { + echo "turnup: boot_rootfs: failed to save /linuxrc.sav" >&2 + return 1 + } + mv -f "$ffs"/linuxrc.new "$ffs"/linuxrc || { + echo "turnup: boot_rootfs: failed to install new /linuxrc" >&2 + return 1 + } + return 0 +} + +# +# mountflash <flash root directory> +# Finds and mounts the flash file system +mountflash() { + local ffsdev + + ffsdev="$(mtblockdev Flashdisk)" + test -n "$ffsdev" -a -b "$ffsdev" || { + echo "turnup disk: unable to find flash file system to copy ($ffsdev)" >&2 + return 1 + } + mount -t jffs2 "$ffsdev" "$1" || { + echo "turnup disk: $ffsdev: unable to mount flash file system on $1" >&2 + return 1 + } + return 0 +} + +# +# disk [-m] [-i] [-s<time>] <device> {options} +# Carefully copy the flash file system to the named device. +disk() { + local setup_type sleep init device new ffs + + setup_type=disk + sleep=0 + init= + while test $# -gt 0 + do + case "$1" in + -f) force="$1" + shift;; + -m) setup_type=memstick + shift;; + -i) init="$1" + shift;; + -s*) sleep="${1#-s}" + sleep="${sleep:-10}" + shift;; + *) break;; + esac + done + + device="$1" + test -n "$device" -a -b "$device" || { + echo "turnup disk: $device: block device required" >&2 + return 1 + } + shift + + # make temporary directories for the mount points + new="/tmp/rootfs.$$" + ffs="/tmp/flashdisk.$$" + mkdir "$new" "$ffs" || { + echo "turnup: disk: failed to create temporary directories" >&2 + return 1 + } + + # make sure we can get to the flash file system first + mountflash "$ffs" || { + rmdir "$new" "$ffs" + return 1 + } + + # Now mount the device with the given options, note that specifying + # read only is *not* an option, this is important because the boot/disk + # script needs a rw file system + status=1 + if mount "$@" "$device" "$new" + then + if check_rootfs $init "$new" && { + test -z "$init" || { + copy_rootfs "$ffs" "$new" && + setup_rootfs "$setup_type" "$new" "$ffs"/etc/device_table + } + } + then + status=0 + fi + + # clean up the disk. It is worrying if this umount fails! + umount "$new" || { + echo "turnup disk: $device: umount failed" >&2 + echo " you must unmount this device cleanly yourself, then use" >&2 + echo " the -i option to boot from the device" >&2 + status=1 + } + + # if everything went ok boot from this disk + if test $status -eq 0 + then + # memsticks boot like disks, so ignore the -m + boot_rootfs disk "$ffs" "$sleep" "$device" "$@" + fi + else + echo "turnup disk: $device($*): unable to mount device on $new" >&2 + fi + + # clean up the flash file system + umount "$ffs" + rmdir "$new" "$ffs" + return $status +} + +# +# boot_reset <type> +# Resets the boot type to flash or ram, as appropriate +boot_reset() { + local ffs typ status + + case "$1" in + flash|ram)type="$1" + shift;; + *) echo "turnup: boot_reset($1): invalid type" >&2 + return 1;; + esac + + ffs="/tmp/flashdisk.$$" + mkdir "$ffs" || { + echo "turnup: $1: failed to create temporary directory" >&2 + return 1 + } + + mountflash "$ffs" || { + rmdir "$ffs" + return 1 + } + + # now try to set the /linuxrc appropriately + boot_rootfs "$type" "$ffs" + status=$? + + # clean up + umount "$ffs" + rmdir "$ffs" + return $status +} + +# +# nfs [-i] <root partition> {options} +# Copy the flash file system to the given NFS root partition. +nfs() { + local init nfsroot new ffs + + init= + while test $# -gt 0 + do + case "$1" in + -i) init="$1" + shift;; + -f) force="$1" + shift;; + *) break;; + esac + done + + nfsroot="$1" + test -n "$nfsroot" || { + echo "turnup nfs: $nfsroot: NFS root file system required" >&2 + return 1 + } + shift + + # make temporary directories for the mount points + new="/tmp/rootfs.$$" + ffs="/tmp/flashdisk.$$" + mkdir "$new" "$ffs" || { + echo "turnup nfs: failed to create temporary directories" >&2 + return 1 + } + + # make sure we can get to the flash file system first + mountflash "$ffs" || { + rmdir "$new" "$ffs" + return 1 + } + + # Now mount the device with the given options, note that specifying + # read only is *not* an option, this is important because the boot/disk + # script needs a rw file system + status=1 + if mount -t nfs -o nolock,noatime,hard,intr,rsize=1024,wsize=1024,"$@" "$nfsroot" "$new" + then + if :>"$new"/ttt && test -O "$new"/ttt && rm "$new"/ttt + then + if check_rootfs $init "$new" && { + test -z "$init" || { + copy_rootfs "$ffs" "$new" && + setup_rootfs nfs "$new" "$ffs"/etc/device_table + } + } + then + status=0 + fi + else + echo "turnup nfs: $nfsroot: partition must be mounted no_root_squash" >&2 + fi + + # clean up the disk. It is worrying if this umount fails! + umount "$new" || { + echo "turnup nfs: $nfsroot: umount failed" >&2 + if test $status -eq 0 + then + echo " you must unmount this partition cleanly yourself, then use" >&2 + echo " the -i option to boot from the NFS root" >&2 + status=1 + fi + } + + # if everything went ok boot from this disk + if test $status -eq 0 + then + # the options used are exactly those which worked before. + boot_rootfs nfs "$ffs" 0 "$nfsroot" -t nfs \ + -o nolock,noatime,hard,intr,rsize=1024,wsize=1024,"$@" + fi + else + echo "turnup disk: $nfsroot($*): unable to mount device on $new" >&2 + fi + + # clean up the flash file system + umount "$ffs" + rmdir "$new" "$ffs" + return $status +} + +# +# Basic command switch (this should be the only thing in this +# script which actually does anything!) +case "$1" in +init) shift + echo "turnup init: NYI" >&2 + exit 1;; +disk) shift + disk "$@";; +memstick) + shift + disk -m "$@" -o noatime;; +nfs) shift + nfs "$@";; +flash) boot_reset flash;; +ram) boot_reset ram;; +*) echo "\ +usage: turnup command [options] + commands: + help + output this help + init + initialise network information when DHCP is not available + disk [-i] [-s<seconds>] <device> [mount options] + With -i make <device> a bootable file system then (with or + without -i) arrange for the next reboot to use that device. + The device must already be formatted as a file system, with + -i it must be completely empty, without it must contain an + apparently bootable file system. -s (for example -s5) + specifies a delay in seconds to wait at boot time before + mounting the device. + memstick [-i] <device> [mount options] + Behaves as disk however options appropriate to a flash memory + stick are automatically added + nfs [-i] <nfs mount path> [mount options] + <nfs mount path> must be a mountable NFS file system. With + -i the partition must be empty and is initialised with a + bootable file system. Without -i the partition must already + contain a bootable file system. In either case the NFS + partition must be available to be mounted without root id + sqashing (i.e. root must be root) and it will be selected + as the root file system for subsequent reboots. + The options are added to the -o list, therefore to give + additional flag arguments specify an empty first option. + The options may be used to override the defaults just by + specifying the new value. + flash + Revert to booting from the flash disk on next reboot. + ram + Boot (once) into a ramdisk, subsequent boots will be to + the flash file system. + disk formatting: + The argument to 'nfs' or 'disk' must be an empty partition + of sufficient size to hold the root file system (at least + 16MByte but more is recommended to allow package installation). + An appropriate ext3 partition can be made using the command: + + mke2fs -j <device> # for example: /dev/sda1 + + An appropriate NFS partition can be emptied using 'rm', but + must be set up (exported) on the NFS server." >&2 + exit 0;; +esac +# Exit with return code from command. |