From 709c4d66e0b107ca606941b988bad717c0b45d9b Mon Sep 17 00:00:00 2001 From: Denys Dmytriyenko Date: Tue, 17 Mar 2009 14:32:59 -0400 Subject: rename packages/ to recipes/ per earlier agreement See links below for more details: http://thread.gmane.org/gmane.comp.handhelds.openembedded/21326 http://thread.gmane.org/gmane.comp.handhelds.openembedded/21816 Signed-off-by: Denys Dmytriyenko Acked-by: Mike Westerhof Acked-by: Philip Balister Acked-by: Khem Raj Acked-by: Marcin Juszkiewicz Acked-by: Koen Kooi Acked-by: Frans Meulenbroeks --- recipes/slugos-init/files/README | 49 ++ recipes/slugos-init/files/boot/disk | 83 ++ recipes/slugos-init/files/boot/flash | 29 + recipes/slugos-init/files/boot/kexec | 203 +++++ recipes/slugos-init/files/boot/network | 41 + recipes/slugos-init/files/boot/nfs | 31 + recipes/slugos-init/files/boot/ram | 64 ++ recipes/slugos-init/files/boot/udhcpc.script | 17 + recipes/slugos-init/files/conffiles | 55 ++ recipes/slugos-init/files/functions | 427 +++++++++ recipes/slugos-init/files/initscripts/fixfstab | 91 ++ recipes/slugos-init/files/initscripts/leds_startup | 11 + .../slugos-init/files/initscripts/loadmodules.sh | 15 + recipes/slugos-init/files/initscripts/rmrecovery | 4 + recipes/slugos-init/files/initscripts/sysconfsetup | 46 + .../slugos-init/files/initscripts/syslog.buffer | 23 + recipes/slugos-init/files/initscripts/syslog.file | 23 + .../slugos-init/files/initscripts/syslog.network | 28 + .../slugos-init/files/initscripts/umountinitrd.sh | 33 + recipes/slugos-init/files/initscripts/zleds | 45 + recipes/slugos-init/files/leds | 269 ++++++ recipes/slugos-init/files/links.conf | 6 + recipes/slugos-init/files/modulefunctions | 45 + recipes/slugos-init/files/modutils.txt | 1 + recipes/slugos-init/files/reflash | 658 ++++++++++++++ recipes/slugos-init/files/setup-optware.sh | 17 + recipes/slugos-init/files/sysconf | 796 +++++++++++++++++ recipes/slugos-init/files/turnup | 965 +++++++++++++++++++++ recipes/slugos-init/files/usb | 2 + 29 files changed, 4077 insertions(+) create mode 100644 recipes/slugos-init/files/README create mode 100644 recipes/slugos-init/files/boot/disk create mode 100644 recipes/slugos-init/files/boot/flash create mode 100644 recipes/slugos-init/files/boot/kexec create mode 100644 recipes/slugos-init/files/boot/network create mode 100644 recipes/slugos-init/files/boot/nfs create mode 100644 recipes/slugos-init/files/boot/ram create mode 100644 recipes/slugos-init/files/boot/udhcpc.script create mode 100644 recipes/slugos-init/files/conffiles create mode 100644 recipes/slugos-init/files/functions create mode 100644 recipes/slugos-init/files/initscripts/fixfstab create mode 100644 recipes/slugos-init/files/initscripts/leds_startup create mode 100644 recipes/slugos-init/files/initscripts/loadmodules.sh create mode 100644 recipes/slugos-init/files/initscripts/rmrecovery create mode 100644 recipes/slugos-init/files/initscripts/sysconfsetup create mode 100644 recipes/slugos-init/files/initscripts/syslog.buffer create mode 100644 recipes/slugos-init/files/initscripts/syslog.file create mode 100644 recipes/slugos-init/files/initscripts/syslog.network create mode 100644 recipes/slugos-init/files/initscripts/umountinitrd.sh create mode 100644 recipes/slugos-init/files/initscripts/zleds create mode 100644 recipes/slugos-init/files/leds create mode 100644 recipes/slugos-init/files/links.conf create mode 100644 recipes/slugos-init/files/modulefunctions create mode 100644 recipes/slugos-init/files/modutils.txt create mode 100644 recipes/slugos-init/files/reflash create mode 100644 recipes/slugos-init/files/setup-optware.sh create mode 100644 recipes/slugos-init/files/sysconf create mode 100644 recipes/slugos-init/files/turnup create mode 100644 recipes/slugos-init/files/usb (limited to 'recipes/slugos-init/files') diff --git a/recipes/slugos-init/files/README b/recipes/slugos-init/files/README new file mode 100644 index 0000000000..264d4d8f85 --- /dev/null +++ b/recipes/slugos-init/files/README @@ -0,0 +1,49 @@ +OpenSlug-1.x Family Release README + +Warning: OpenSlug is not for the faint of heart! In fact, OpenSlug has a +specific target audience. + +Some background first. According to the NSLU2 - Linux developers, there are 4 +specific types ("camps") of NSLU2 - Linux users: + + Camp #1: Users who want full Linksys compatibility (including for future + Linksys firmware releases). They can load firmware images via + the Linksys web interface and telnet in - to load Optware - + Unslung packages with ipkg, but have no idea what RedBoot is or + does. + + Camp #2: "Camp #1 Plus users." They can telnet into RedBoot (ability + to "self-rescue" a non-working NSLU2), and are comfortable + using Linux. + + Camp #3: Power users! Firmware flashing via any interface is a walk + in the park. They aren't just *users*, but are developers or + administrators of computers and/or computer software. + However, they have no JTAG or custom bootloaders. + + Camp #4: Bleeding edge users. They create and use custom bootloaders, + certainly having no need or desire for Linksys compatibility, + modifying and/or changing the hardware as well. + +With those camps in mind, OpenSlug is targetted toward Camp #3 and Camp #4 +users. If you're not in Camps 3 & 4, then you should be looking to use the +Unslung firmware. If you are a Camp #2 user, and still want to use OpenSlug, +you need to practice gaining RedBoot access, and be able to recover from bad +flashes, "drive not formatted" conditions, and other common mistakes/problems +which are documented in the NSLU2-Linux Wiki at http://www.nslu2-linux.org. +Once you are comfortable doing those things, then you may consider using +OpenSlug. + +If you're still reading - and still intent on using OpenSlug, click through +the Intel license, download the latest OpenSlug binary and flash it to your +NSLU2! (Without any HD attached while flashing!!!) Your next stop should be +the OpenSlug Turnip page at: + + http://www.nslu2-linux.org/wiki/OpenSlug/OpenSlugTurnUp + +Please add your name and information to the OpenSlug database at the yahoo +NSLU2-Linux group at: + + http://groups.yahoo.com/group/nslu2-linux/ + +Happy OpenSlugging! \ No newline at end of file diff --git a/recipes/slugos-init/files/boot/disk b/recipes/slugos-init/files/boot/disk new file mode 100644 index 0000000000..1829033d4e --- /dev/null +++ b/recipes/slugos-init/files/boot/disk @@ -0,0 +1,83 @@ +#!/bin/sh +# boot from the hard disk partition "$1" (which +# must be given) using options from the rest of +# the command line. + +# Use the standard init path (see /etc/init.d/rcS) +export PATH=/sbin:/bin:/usr/sbin:/usr/bin + +# Mount required fileystems if necessary +[ -e /proc/cpuinfo ] || mount -t proc proc /proc +[ -e /sys/class ] || mount -t sysfs sysfs /sys + +# Load the helper functions +. /etc/default/functions +. /etc/default/modulefunctions + +leds boot system + +if test -n "$1" +then + device="$1" + shift + # load USB & SCSI storage modules (/proc required!) + echo "boot: loading modules required for disk boot" + loaddiskmods + # waiting for disk + if test "$sleep" -gt 0 + then + echo "boot: waiting $sleep seconds for disk" + sleep "$sleep" + fi + # Attempt to assemble the RAID if necessary + if (echo $device | grep -q "^/dev/md") + then + if test -n "$MDUUID" + then + echo "boot: assembling RAID array (UUID)" + mdadm -Acpartitions --auto=md --uuid="$MDUUID" $device + else + echo "boot: assembling RAID array (config file)" + mdadm -As --auto=md $device + fi + fi + + # fire the boot + echo "boot: rootfs: mount $* $device [$UUID]" + + # Mount read-write because before exec'ing init + # If a UUID is given (in the environment) this + # is used in preference to the device, but if + # the UUID mount fails a standard device mount + # is attempted. + if test -n "$UUID" && + mount "$@" UUID="$UUID" /mnt || + mount "$@" "$device" /mnt + then + # checkmount checks for sh, chroot, init, /dev + # and /mnt (i.e. /mnt/mnt in this case). + # minimaldevnodes checks (and creates if required) + # a few mandatory /dev nodes we may need. + if checkmount /mnt && minimaldevnodes /mnt + then + # pivot to /initrd if available, else /mnt + cd / + if test -d /mnt/initrd + then + swivel mnt initrd + else + swivel mnt mnt + fi + # swivel failed + fi + # Failure: unmount the partition + umount /mnt + # Remount /proc and /sys if necessary + [ -e /proc/cpuinfo ] || mount -t proc proc /proc + [ -e /sys/class ] || mount -t sysfs sysfs /sys + fi +fi + +# fallback - use the flash boot +leds beep -f 1000 -r 2 +exec /boot/flash diff --git a/recipes/slugos-init/files/boot/flash b/recipes/slugos-init/files/boot/flash new file mode 100644 index 0000000000..01c20e963a --- /dev/null +++ b/recipes/slugos-init/files/boot/flash @@ -0,0 +1,29 @@ +#!/bin/sh +# boot from the current (flash) root partition +# nothing need be done apart from setting the +# system LED status correctly + +# Mount required filesystems if necessary +[ -e /proc/cpuinfo ] || mount -t proc proc /proc +[ -e /sys/class ] || mount -t sysfs sysfs /sys + +leds beep +. /etc/default/functions +leds boot system + +if [ -x /sbin/init ] +then + umount /proc 2>/dev/null + umount /sys 2>/dev/null + exec /sbin/init +fi + +# fallback if /sbin/init has been deleted (bad!) +# Mount required filesystems if necessary +[ -e /proc/cpuinfo ] || mount -t proc proc /proc +[ -e /sys/class ] || mount -t sysfs sysfs /sys +leds boot system panic +exec <>/dev/console >&0 2>&0 +test -x /sbin/sulogin && exec /sbin/sulogin +test -x /bin/sh && exec /bin/sh +exit 1 diff --git a/recipes/slugos-init/files/boot/kexec b/recipes/slugos-init/files/boot/kexec new file mode 100644 index 0000000000..a60be03142 --- /dev/null +++ b/recipes/slugos-init/files/boot/kexec @@ -0,0 +1,203 @@ +#!/bin/sh +# +# Loads the specified kernel and kexecs it. + +# The access method and path from which to fetch the kernel +# is specified in "$1" and "$2": +# +# flash /boot/zImage-ixp4xxbe +# nfs spike:/home/slug/vmlinuz +# wget http://devserv/kernels/vmlinuzbe +# wget ftp://ftpserv/pub/zImage +# /dev/sda1 /kernels/zImage-test +# UUID /kernels/zImage-test +# tftp server:/pub/kernels/vmlinuz +# +# Command-line options for the new kernel are in "$3". + + +# In order to use this, you must exec this script from the /linuxrc file. +# +# This sample linuxrc script boots from external disk. The last line of +# this example (exec /boot/flash) is a fallback; it will not normally be +# executed unless /boot/kexec is missing or damaged. +#-------------------- +# #!/bin/sh +# sleep=8 exec /boot/kexec /dev/sda1 /boot/zImage-ixp4xxbe \ +# "console=ttyS0,115200n8 root=/dev/sda1 rootfstype=ext3 rw init=/linuxrc" +# exec /boot/flash +#-------------------- +# +# This one boots from flash in the normal fashion, except the kernel is +# loaded using wget. This is common for kernel debugging. +#-------------------- +# #!/bin/sh +# exec /boot/kexec wget http://myserver/boot/zImage-ixp4xxbe \ +# "console=ttyS0,115200n8 root=/dev/mtdblock4 rootfstype=jffs2 rw \ +# init=/boot/flash noirqdebug" +# exec /boot/flash +#-------------------- + + +# Use the standard init path (see /etc/init.d/rcS) +export PATH=/sbin:/bin:/usr/sbin:/usr/bin + +# Wait at least a short while for the disks... +if [ ! "$sleep" -gt 0 ] ; then + sleep=1 +fi + +# Load the helper functions +. /etc/default/functions +. /etc/default/modulefunctions + +# Print a distinctive banner to make it easy to separate the in-flash +# kernel boot from the kexec'd kernel boot when looking at logs, etc. +echo '###########################################################' +echo '###################### KEXEC ######################' + +leds boot system + +if [ -n "$1" -a -n "$2" ] ; then + + method="$1" + shift + kpath="$1" + shift + if [ -n "$1" ] ; then + kcmdline="$1" + shift + fi + kexec_image= + need_umount=0 + do_kexec=0 + + mount -t proc proc /proc + + case "$method" in + + flash ) + echo "Loading kexec kernel directly from \"$kpath\"..." + kexec_image="$kpath" + ;; + + wget ) + if /boot/network ; then + echo "mounting tmpfs partition..." + if mount -t tmpfs tmpfs /mnt ; then + need_umount=1 + echo "Loading kexec kernel using wget \"$kpath\"..." + wget -P /mnt "$kpath" + t=`basename "$kpath"` + kexec_image="/mnt/$t" + fi + fi + ;; + + nfs ) + if /boot/network ; then + echo "Loading kexec kernel using nfs \"$kpath\"..." + echo "mounting nfs partition..." + loadnfsmods + if mount -o ro,nolock -t nfs `dirname "$kpath"` /mnt ; then + need_umount=1 + t=`basename "$kpath"` + kexec_image="/mnt/$t" + fi + fi + ;; + + /dev/* ) + echo "Loading kexec kernel using disk \"$kpath\"..." + loaddiskmods + sleep "$sleep" + echo "mounting partition \"$method\"..." + if mount -o ro "$method" /mnt ; then + need_umount=1 + kexec_image="/mnt/$kpath" + fi + ;; + + UUID ) + echo "Loading kexec kernel using disk UUID \"$kpath\"..." + loaddiskmods + sleep "$sleep" + if [ -n "$UUID" ] ; then + echo "mounting partition UUID \"$UUID\"..." + if mount -o ro UUID="$UUID" /mnt ; then + need_umount=1 + kexec_image="/mnt/$kpath" + fi + fi + ;; + + tftp ) + if /boot/network ; then + echo "mounting tmpfs partition..." + if mount -t tmpfs tmpfs /mnt ; then + need_umount=1 + t=`basename "$kpath"` + kexec_image="/mnt/$t" + echo "Loading kexec kernel using tftp \"$kpath\"..." + tftp -g -l "$kexec_image" -r "${kpath#*:}" "${kpath%%:*}" + fi + fi + ;; + + * ) + echo "Unrecognized method: \"$method\"" + ;; + + esac + + if [ -n "$kexec_image" -a -f "$kexec_image" ] ; then + if kexec -l "$kexec_image" ; then + do_kexec=1 + fi + else + echo "Unable to load \"$kexec_image\"" + fi + + if [ $do_kexec -eq 1 -a -n "$kcmdline" ] ; then + echo "Attempting to mount /sys (sysfs)..." + if mount -t sysfs sysfs /sys ; then + echo "Setting command line:" + echo " \"$kcmdline\"" + echo "$kcmdline" > /sys/kernel/kexec_cmdline + echo "unmounting /sys..." + umount /sys + else + do_kexec=0 + fi + fi + + if [ $need_umount -eq 1 ] ; then + echo "unmounting /mnt..." + umount /mnt + fi + + if [ $do_kexec -eq 1 ] ; then + echo "Remounting root as read-only..." + mount -o remount,ro / + echo "Invoking \"kexec -f -e\" ..." + kexec -f -e + echo "ERROR!" + # We should never return here! At this point, things are not + # too well. Remount the root as rw, and fallback. + echo "Remounting root as read-write..." + mount -o remount,rw / + fi +else + echo "Usage: $0 flash|nfs|wget|UUID|/dev/ [cmdline]" +fi + +# fallback - use the flash boot +echo "Falling back to flash boot..." +leds beep -f 1000 -r 2 +exec /boot/flash + +# fallback to the fallback +leds boot system panic +exec <>/dev/console >&0 2>&0 +test -x /bin/sh && exec /bin/sh +exit 1 \ No newline at end of file diff --git a/recipes/slugos-init/files/boot/network b/recipes/slugos-init/files/boot/network new file mode 100644 index 0000000000..b8054a0056 --- /dev/null +++ b/recipes/slugos-init/files/boot/network @@ -0,0 +1,41 @@ +#!/bin/sh +# bring up the network before boot, used to allow +# netconsole logging and NFS boot. This runs out +# of flash, but that's ok because the script doesn't +# leave any process running. + +# NOTE: /etc/default/functions defines ifup as a shell +# function! +. /etc/default/functions + +# We may need to load the network driver modules here +. /etc/default/modulefunctions +loadnetmods + +# Now all the information for booting should be in the configuration +# file. Config the loopback and network interfaces. +ifconfig lo 127.0.0.1 up +iface="$(config iface)" +test -z "$iface" && exit 1 + +# Fire up a process in the background to load the firmware if necessary. +# If this system doesn't require the NPE-B firmware, no problem, the +# background process will simply go away in two seconds. If it requires +# some other firmware, then modification will be required. We probably +# should replace this with mdev or some other hotplug-based technique... +sysf="/sys/class/firmware/$iface" +( + # Wait for the firware to be requested, if required + [ -f $sysf/loading ] || sleep 1 + [ -f $sysf/loading ] || sleep 1 + if [ -f $sysf/loading ] ; then + echo "1" >$sysf/loading + cat /lib/firmware/NPE-B >$sysf/data + echo "0" >$sysf/loading + fi +) & +# Trigger the firmware load proactively +ifconfig "$iface" up + +ifup "$iface" +# exit code is true only if the interface config has succeeded diff --git a/recipes/slugos-init/files/boot/nfs b/recipes/slugos-init/files/boot/nfs new file mode 100644 index 0000000000..7f91889315 --- /dev/null +++ b/recipes/slugos-init/files/boot/nfs @@ -0,0 +1,31 @@ +#!/bin/sh +# boot from the nfs partition "$1" (which +# must be given) using options from the rest of +# the command line. + +# Use the standard init path (see /etc/init.d/rcS) +export PATH=/sbin:/bin:/usr/sbin:/usr/bin + +# Mount required fileystems if necessary +[ -e /proc/cpuinfo ] || mount -t proc proc /proc +[ -e /sys/class ] || mount -t sysfs sysfs /sys + +# Load the helper functions +. /etc/default/functions +. /etc/default/modulefunctions + +leds boot system + +if /boot/network +then + # load the nfs kernel module + loadnfsmods + + # network is up and running, the NFS mount will + # now succeed (possibly), use /boot/disk + exec /boot/disk "$@" +fi + +# fallback - use the flash boot +leds beep -f 1000 -r 2 +exec /boot/flash diff --git a/recipes/slugos-init/files/boot/ram b/recipes/slugos-init/files/boot/ram new file mode 100644 index 0000000000..0a8fe1d25d --- /dev/null +++ b/recipes/slugos-init/files/boot/ram @@ -0,0 +1,64 @@ +#!/bin/sh +# boot from the hard disk partition "$1" (which +# must be given) using options from the rest of +# the command line. + +# Use the standard init path (see /etc/init.d/rcS) +export PATH=/sbin:/bin:/usr/sbin:/usr/bin + +# Mount required fileystems if necessary +[ -e /proc/cpuinfo ] || mount -t proc proc /proc +[ -e /sys/class ] || mount -t sysfs sysfs /sys + +# Load the helper functions +. /etc/default/functions + +leds beep -r 2 +leds boot system + +if test -n "$1" +then + device="$1" + shift + echo "boot: rootfs: mount $* $device" + + # prepare the device. This uses tmpfs to avoid dependency + # on non-built-in file systems and because tmpfs can expand + # to bigger than the 10MByte ram0 partition used before. + # The 'device' is currently unused. + if mount -t tmpfs "$@" tmpfs /mnt + then + cd / + # filter out boot (with zimage), linuxrc and anything + # below /var, keep dev or the boot will fail. Take + # care that nothing is mounted at this point! + umount /proc + umount /sys + find . -xdev -print | + sed '\@^./boot/@d;\@^./boot$@d;\@^./linuxrc@d;\@^./var/@d' | + cpio -p -d -m -u /mnt + # busybox find with -xdev will not print the name of the + # mountpoint, so create the empty dir manually if required. + test -d /mnt/mnt || mkdir /mnt/mnt + # checkmount checks for sh, chroot, init, /dev + # and /mnt (i.e. /mnt/mnt in this case). + # minimaldevnodes checks (and creates if required) + # a few mandatory /dev nodes we may need. + if checkmount /mnt && minimaldevnodes /mnt + then + # pivot to /mnt + cd / + swivel mnt mnt + # swivel failed + fi + # Failure: unmount the partition + umount /mnt + # Remount /proc and /sys if necessary + [ -e /proc/cpuinfo ] || mount -t proc proc /proc + [ -e /sys/class ] || mount -t sysfs sysfs /sys + fi +fi + +# fallback - use the flash boot +leds beep -f 1000 -r 2 +exec /boot/flash diff --git a/recipes/slugos-init/files/boot/udhcpc.script b/recipes/slugos-init/files/boot/udhcpc.script new file mode 100644 index 0000000000..3f437e3143 --- /dev/null +++ b/recipes/slugos-init/files/boot/udhcpc.script @@ -0,0 +1,17 @@ +#!/bin/sh +# executed by udhcpc to do the real work of configuring an interface +# writes the result (if any) to file descriptor 9 +case "$1" in +deconfig) # ignored + :;; +renew|bound) # this gives the real information + test -n "$ip" && { + echo "ip='$ip'" + echo "subnet='$subnet'" + echo "broadcast='$broadcast'" + echo "router='$router'" + } >&9;; +leasefail) # ignore - probably no dhcp server + :;; +*) echo "udhcpc: $*: command not recognised" >&2;; +esac diff --git a/recipes/slugos-init/files/conffiles b/recipes/slugos-init/files/conffiles new file mode 100644 index 0000000000..668f7467a8 --- /dev/null +++ b/recipes/slugos-init/files/conffiles @@ -0,0 +1,55 @@ +# conffiles +# Known SlugOS configuration files. These files are preserved on +# a flash upgrade. Other configuration files, found from: +# +# /usr/lib/opkg/*.conffiles +# /etc/*.conf +# +# are preserved too with an operation of 'diff' if they have been +# changed since /etc/.configured was created. +# +# Lines starting with # are comments, other lines have +# two fields: +# +# operation file +# +# The file must *NOT* have a leading / +# +# operation may be: +# ignore Do not preserve this file +# preserve Preserve this file unconditionally +# diff Compare file with the new version, ask if different +# +preserve linuxrc +preserve etc/.configured +preserve etc/TZ +diff etc/default/conffiles +diff etc/default/devpts +preserve etc/default/rcS +preserve etc/default/sysconf +diff etc/default/usbd +preserve etc/defaultdomain +preserve etc/dropbear/dropbear_dss_host_key +preserve etc/dropbear/dropbear_rsa_host_key +preserve etc/ssh/ssh_host_dsa_key +preserve etc/ssh/ssh_host_dsa_key.pub +preserve etc/ssh/ssh_host_rsa_key +preserve etc/ssh/ssh_host_rsa_key.pub +preserve etc/fstab +preserve etc/group +preserve etc/gshadow +preserve etc/hostname +preserve etc/hosts +preserve etc/localtime +ignore etc/modules +ignore etc/modules.conf +preserve etc/motd +preserve etc/network/interfaces +preserve etc/ntp.drift +preserve etc/passwd +preserve etc/profile +preserve etc/resolv.conf +preserve etc/shadow +preserve etc/syslog.conf +preserve etc/timezone +preserve root/.ssh/authorized_keys diff --git a/recipes/slugos-init/files/functions b/recipes/slugos-init/files/functions new file mode 100644 index 0000000000..38a3b4d166 --- /dev/null +++ b/recipes/slugos-init/files/functions @@ -0,0 +1,427 @@ +#!/bin/sh +# . this file to load the following utility functions +# +# hardware +# the 'Hardware' string from cpuinfo +hardware(){ + sed -n 's!^Hardware *: !!p' /proc/cpuinfo +} +# +# machine +# outputs an identifier of the current machine - i.e. the board +# slugos is running on. +machine(){ + case "$(hardware)" in + *Coyote*) echo coyote;; + *IXDPG425*) echo ixdpg425;; + *WRV54G*) echo wrv54g;; + *IXDP425*) echo ixdp425;; + *IXDP465*) echo ixdp465;; + *IXCDP1100*) echo ixcdp1100*;; + *Avila*) echo avila;; + *Loft*) echo loft;; + *NAS?100d*) echo nas100d;; + *DSM?G600*) echo dsmg600;; + *NSLU2*) echo nslu2;; + *FSG?3*) echo fsg3;; + *) echo unknown;; + esac +} +# +# single_user_ok +# if the machine is capable of single user interaction return +# true, else return false. The result of this function is +# preempted by setting SULOGIN to 'yes' or 'ok' in /etc/default/rcS +single_user_ok() { + # list known good machines in the 'case' + test "$SULOGIN" = yes -o "$SULOGIN" = ok || + case "$(machine)" in + ixdp*|avila|loft) + test "$SULOGIN" != never;; + *) return 1;; + esac +} +# +# load_functions "source" +# load the functions in '/sbin/source' - relies on /sbin/source being +# a shell script and having support for this function. +load_functions(){ + test -n "$1" -a -x "/sbin/$1" && . "/sbin/$1" || { + echo "$0: /sbin/$1: script not found" >&2 + return 1 + } +} +# +# mtdev "name" +# return (output) the character device name for flash parition "name" +# /proc/mtd has the general form: +# dev: size erasesize name +# mtd5: 00020000 00020000 "FIS directory" +# use this rather than hard-wiring the device because the partition +# table can change - looking in /proc/mtd is more reliable. +mtdev(){ + sed -n 's!^\(mtd[0-9][0-9]*\):[^"]*"'"$1"'"$!/dev/\1!p' /proc/mtd +} +# +# mtblockdev "name" +# as mtdev but output the name of the block (not character) device +mtblockdev(){ + sed -n 's!^mtd\([0-9][0-9]*\):[^"]*"'"$1"'"$!/dev/mtdblock\1!p' /proc/mtd +} +# +# mtsize "name" +# the size of the partition as a hexadecimal value (with 0x at the front) +mtsize(){ + sed -n 's!^mtd[0-9][0-9]*: \([^ ]*\)[^"]*"'"$1"'"$!0x\1!p' /proc/mtd +} +# +# sysvalmatch "section" "name" 'pattern' "configuration file" +# sysvalof "section" "name" "configuration file" +# sysval "section" "name" +# outputs the value of the SysConf variable 'name' from section 'section', +# if there are multiple definitions only the last is output +# NOTE: these functions should only be used internally, add entries to 'config' +# below if necessary. This is because 'config' does the defaulting. +sysvalmatch(){ + sed -n '/^\['"$1"'\]$/,/^\[.*\]$/s/^'"$2"'=\('"$3"'\)$/\1/p' "$4" | sed -n '$p' +} +sysvalof(){ + sysvalmatch "$1" "$2" '.*' "$3" +} +sysval(){ + test -r "$config_root/etc/default/sysconf" && + sysvalof "$1" "$2" "$config_root/etc/default/sysconf" +} +# +# syssection "section" +# outputs all the values from the given section changed to the format "name value" +# (i.e. the '=' is dropped). +syssection(){ + test -r "$config_root/etc/default/sysconf" && + sed -n '/^\['"$1"'\]$/,/^\[.*\]$/s/^\([^=]*\)=\(.*\)$/\1 \2/p' "$config_root/etc/default/sysconf" +} +# +# config "value" +# convenience callers for specific values to avoid mis-typing in scripts +# NOTE: this function does the defaulting, 'sysval' does not! +# config_root: if set this will override the root where config/sysval +# looks for /etc/default/sysconf +config(){ + local mac + mac="$(test -r /proc/net/maclist && + sed -n '/^[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]$/p' /proc/net/maclist | + sed -n 1p)" + # + case "$1" in + mac) test -n "$mac" && echo "$mac";; + host) if test -n "$(sysval network disk_server_name)" + then + sysval network disk_server_name + elif test -n "$(sysval network default_server_name)" + then + sysval network default_server_name + elif test -n "$mac" + then + echo "$mac" | sed -n 's/^\(..\):\(..\):\(..\):\(..\):\(..\):\(..\)$/slug\1\2\3\4\5\6/p' + else + # because we want the name to remain constant: + echo "brokenslug" + fi;; + domain) sysval network w_d_name;; + iface) if test -n "$(sysval network lan_interface)" + then + sysval network lan_interface + else + echo eth0 + fi;; + ip) if test -n "$(sysval network ip_addr)" + then + sysval network ip_addr + else + echo 192.168.1.77 + fi;; + netmask)sysval network netmask;; + gateway)sysval network gateway;; + dns) sysval network dns_server1;; + dns2) sysval network dns_server2;; + dns3) sysval network dns_server3;; + boot) if test -n "$(sysval network bootproto)" + then + sysval network bootproto + else + echo dhcp + fi;; + valid) test -r "$config_root/etc/default/sysconf" -a -n "$mac";; + *) return 1;; + esac +} +# +# checkif "iface" +# Validate an interface name by making sure that it exists +# in /proc/net/dev (and is not lo). The listing outputs the +# interface followed by a :, the check function looks for +# something of the form '$1[a-zA-Z0-9]*:' and outputs the +# part preceding the ':' +checkif(){ + sed -n '/^[ ]*lo:/d;s/^[ ]*\('"$1"'[a-zA-Z0-9]*\):.*$/\1/p;tE;d;:E;q' /proc/net/dev +} +# +# checkmount "mountpoint" +# tests an already mounted mountpoint to see whether to attempt to +# boot with this as root. Returns success if it appears ok. +checkmount(){ + # basic test for init (the kernel will try to load this) + # but require a shell in bin/sh too + test \( -d "$1/mnt" \) -a \ + \( -d "$1/dev" \) -a \ + \( -x "$1/bin/sh" -o -h "$1/bin/sh" \) -a \ + \( -x "$1/usr/sbin/chroot" -o -h "$1/usr/sbin/chroot" -o \ + -x "$1/sbin/chroot" -o -h "$1/sbin/chroot" \) -a \ + \( -x "$1/sbin/init" -o -h "$1/sbin/init" -o \ + -x "$1/etc/init" -o -h "$1/etc/init" -o \ + -x "$1/bin/init" -o -h "$1/bin/init" \) +} +# +# minimaldevnodes "mountpoint" +# tests an already mounted mountpoint to see if a very minimal +# set of devices exists or can be created in dev, and returns +# failure if not. This is required for booting to an nfsroot +# with an empty dev directory, as commonly occurs when the rootfs +# is created from a tar.gz image. This is also required for mdev. +minimaldevnodes(){ + [ -c "$1/dev/console" ] || mknod -m 600 "$1/dev/console" c 5 1 || return 1 + [ -c "$1/dev/null" ] || mknod -m 666 "$1/dev/null" c 1 3 || return 1 + [ -c "$1/dev/tty0" ] || mknod -m 644 "$1/dev/tty0" c 4 0 || return 1 + return 0 +} +# +# swivel "new root" "old root" +# NOTE: the arguments must be paths relative to /, bad things +# will happen if the arguments themselves start with / +# Pivot to a new root. This does all the fancy pivot_root stuff +# including closing streams and does a umount of /proc and /sys - +# it doesn't matter if this fails (failure codes are ignored), +# but if /proc and/or /sys was mounted it must be restored by the +# caller on return. Normally this function never returns! +# On return 0,1,2 are connected to /dev/console - this may not +# have been true before! +swivel(){ + cd "$1" + exec <&- >&- 2>&- + # This is just-in-case the caller mounted either /proc or + # /sys, and was unable to close them + umount /sys 2>/dev/null + umount /proc 2>/dev/null + if pivot_root . "$2" + then + # everything must move out of the old root, this process + # is $2/bin/sh so it must die, IO is redirected + # just in case - typically it will be to a device so it + # won't hold the old root open. + # the exec here is the first point at which the old root + # is unused - before the exec regardless of the close of + # 0,1,2 above ash still has *this* shell script open! + # (it's on fd 10). + # init closes all file descriptors, there's no point + # supplying it with fds. + # NOTE: this used to use $2/usr/sbin/chroot, however on + # linux / is already . when the command is executed + # therefore it is essential to use the local (new root) + # chroot to ensure it gets the correct shared libraries. + if test -x usr/sbin/chroot -o -h usr/sbin/chroot + then + chroot=usr/sbin/chroot + elif test -x sbin/chroot -o -h sbin/chroot + then + chroot=sbin/chroot + else + chroot=chroot + fi + # + exec "$chroot" . bin/sh -c "\ + test -x sbin/init && exec sbin/init + test -x etc/init && exec etc/init + test -x bin/init && exec bin/init + # Problematic failure! The chroot worked, but the + # exec failed. Nothing to do but blink the LEDs. + # (Use a wildcard because the LED names depend on + # the version of the kernel in use.) + mount -t sysfs sysfs /mnt + for i in /mnt/class/leds/*[ready\|status] + do + echo -n timer >$i/trigger + echo -n 60 >$i/delay_on + echo -n 30 >$i/delay_off + done + umount /mnt + sync;sync;sync + exit 1" + fi + # + # recovery - must restore the old root + cd "$2" + sbin/pivot_root . "$1" + # cd is back to $1 - either pivot_root doesn't change it and the + # chroot above was not executed, or pivot_root does change it and + # has just changed it back! + exec <>/dev/console >&0 2>&0 +} +# +# ifup "interface" +# bring that interface up with the configured ip and other +# information +ifup(){ + local ip hostname router subnet iface HOSTNAME NETMASK BROADCAST + + iface="$1" + ip="$(config ip)" + hostname="$(config host)" + router="$(config gateway)" + broadcast= + + if test -n "$ip" + then + # only if an ip was specified + subnet="$(config netmask)" + else + ip=192.168.1.77 + fi + + # First try udhcpc - note that the /boot/udhcpc.script + # simply records the values returned and the udhcpc + # is not left running so this will only work for + # the lease length time! + ifconfig "$iface" up + if test "$(config boot)" != static + then + test -n "$hostname" && HOSTNAME="-H $hostname" + # Pause a moment in case link negotiation takes a while + sleep 3 + # The script writes the required shell variable assignments + # to file descriptor 9 + eval $(udhcpc -i "$iface" -n -q -r "$ip" $HOSTNAME -s /boot/udhcpc.script 9>&1 >/dev/null) + fi + + test -n "$broadcast" && BROADCAST="broadcast $broadcast" + test -n "$subnet" && NETMASK="netmask $subnet" + + if ifconfig "$iface" "$ip" $NETMASK $BROADCAST + then + for route in $router + do + route add default gw "$route" dev "$iface" + done + return 0 + else + ifconfig "$iface" down + return 1 + fi +} +# +# ifdown "interface" +# take the interface down +ifdown(){ + ifconfig "$1" down +} +# +# mountflash "flash device" "flash root directory" {mount options} +# Finds and mounts the flash file system on the given directory +mountflash(){ + local ffsdev ffsdir + + ffsdev="$1" + test -n "$ffsdev" -a -b "$ffsdev" || { + echo "$0: unable to find flash file system to copy ($ffsdev)" >&2 + return 1 + } + shift + + ffsdir="$1" + test -n "$ffsdir" -a -d "$ffsdir" || { + echo "$0: mountflash $ffsdir: not a directory (internal error)" >&2 + return 1 + } + shift + + mount -t jffs2 "$@" "$ffsdev" "$ffsdir" || { + echo "$0: $ffsdev: unable to mount flash file system on $ffsdir" >&2 + return 1 + } + return 0 +} +# +# umountflash [-r] "flash device" +# unmount any instance of the given flash device, if -r is specified a mount on +# root is an error, otherwise a mount on root is ignored (and remains). +umountflash(){ + local rootok ffsno ffsdev + rootok=1 + case "$1" in + -r) rootok= + shift;; + esac + # + # The argument is ffsdev + ffsdev="$1" + ffsno="$(devio "<<$ffsdev" prd)" + test -n "$ffsno" -a "$ffsno" -ge 0 || { + echo "$0: $ffsdev: device number $ffsno is not valid, cannot continue." >&2 + return 1 + } + # + # Make sure that Flashdisk isn't mounted on / + if test -z "$rootok" -a "$(devio "<&2 + return 1 + fi + # + # The function is currently always used interactively, so output + echo "$0: umounting any existing mount of $ffsdev" >&2 + # + # check each mount point, do this last first because otherwise nested + # mounts of ffsdev cannot be umounted. + ffs_umount() { + local device mp type options stuff + + read device mp type options stuff + test -z "$device" && return 0 + + # handle following entries first + ffs_umount || return 1 + + # handle this entry, since this is currently only used for unmounting + # the flash root partition we know a file which must exist... + case "$mp/$type" in + //jffs2);; # skip / + */jffs2)test "$(devio "<<$mp/etc/init.d/sysconfsetup" prd 2>/dev/null)" -ne "$ffsno" || + umount "$mp" || { + echo "$0: $mp: unable to umount $ffsdev" >&2 + return 1 + };; + esac + + return 0 + } + # + ffs_umount &2 + return 1 + } + + return 0 +} + +# +# uuid_by_partition +# output a list of partitions and their UUIDs +uuid_by_partition() { + blkid -c /dev/null -s UUID | sed -n 's/^\([^:]*\): .*UUID="\([^"]*\)".*$/\1 \2/p' +} + +# +# partition_of uuid +# return the partition corresponding to the UUID +partition_of() { + sed -n 's/^\([^ ]*\) '"$1"'$/\1/p' +} diff --git a/recipes/slugos-init/files/initscripts/fixfstab b/recipes/slugos-init/files/initscripts/fixfstab new file mode 100644 index 0000000000..67116a12fd --- /dev/null +++ b/recipes/slugos-init/files/initscripts/fixfstab @@ -0,0 +1,91 @@ +#!/bin/sh +# validate /etc/fstab against the current UUID list in +# /etc/uuid_by_partition +# +. /etc/default/functions +pfile=/etc/uuid_by_partition + +# +# use debug to find out what is going on +test "$1" = start -o "$1" = debug || exit 0 + +# +# obtain the current list of parititions with UUIDs +newlist="$(uuid_by_partition)" + +if test -r "$pfile" +then + # read the old list + oldlist="$(cat "$pfile")" + # + # if it hasn't changed nothing need be done + test "$newlist" = "$oldlist" && exit 0 + # + # it has changed, but this only matters if + # a previously existing uuid has moved, build + # a list of old device vs new device for every + # uuid which has moved + changedlist="$( + { echo "$oldlist" + echo "$newlist" + } | awk 'device[$2] == ""{device[$2] = $1} + device[$2] != $1{print device[$2], $1}')" + + if test -n "$changedlist" + then + # at least one partition has moved, scan the + # current fstab to see if it has a reference + # to this partition + changedfstab="$( + { echo "$changedlist" + echo '#fstab' + cat /etc/fstab + } | awk 'BEGIN{list=1} + list==1 && $0=="#fstab"{list=0; continue} + list==1{new[$1] = $2; continue} + new[$1] != ""{print $1, new[$1]}')" + + # if this list is not empty edit the fstab + if test -n "$changedfstab" + then + rm -f /tmp/fstab.$$ + # if the edit fails then do not overwrite the old + # partition list - just exit with an error + { echo "$changedlist" + echo '#fstab' + cat /etc/fstab + } | awk 'BEGIN{list=1} + list==1 && $0=="#fstab"{list=0; continue} + list==1{new[$1] = $2; continue} + new[$1] != ""{$1 = new[$1]} + {print}' >/tmp/fstab.$$ || { + if test "$1" = start + then + logger -s "/etc/init.d/fixfstab: /tmp/fstab.$$: awk failed" + else + echo "debug: awk script failed with:" >&2 + echo "$changedlist" >&2 + echo "output in /tmp/fstab.$$" >&2 + fi + exit 1 + } + + if test "$1" = start + then + mv /tmp/fstab.$$ /etc/fstab || { + logger -s "/etc/init.d/fixfstab: /tmp/fstab.$$: update failed" + exit 1 + } + else + echo "debug: fstab changed:" + diff -u /etc/fstab /tmp/fstab.$$ + fi + fi + fi +fi + +# write the new list to the file, only if we +# are doing something... +test "$1" = start && echo "$newlist" >"$pfile" + +exit 0 diff --git a/recipes/slugos-init/files/initscripts/leds_startup b/recipes/slugos-init/files/initscripts/leds_startup new file mode 100644 index 0000000000..945d75bd02 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/leds_startup @@ -0,0 +1,11 @@ +#!/bin/sh +# Bug fix: during the initial boot sysvinit sets PREVLEVEL to +# nothing in rcS and to 'N' in the transition from rcS to the +# user state. This script runs on that transition and, if +# the PREVLEVEL is 'N', sets 'previous' (as in /etc/init.d/rc) +# to 'S' +if test "$PREVLEVEL" = N +then + previous=S exec /etc/init.d/zleds stop +fi +exit 0 diff --git a/recipes/slugos-init/files/initscripts/loadmodules.sh b/recipes/slugos-init/files/initscripts/loadmodules.sh new file mode 100644 index 0000000000..e80f995598 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/loadmodules.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# This script is used for loading modules required by SlugOS +# This script may not be necessary if udev is present, but is included +# for 'backup' purposes in case udev is playing silly buggers + +. /etc/default/modulefunctions # Load module loading logic + +loadnetmods + +loaddiskmods + +loadmiscmods + +exit 0 diff --git a/recipes/slugos-init/files/initscripts/rmrecovery b/recipes/slugos-init/files/initscripts/rmrecovery new file mode 100644 index 0000000000..eec822b154 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/rmrecovery @@ -0,0 +1,4 @@ +#!/bin/sh +# Run to remove /.recovery if the boot seems to have succeeded +test -e /.recovery && rm -f /.recovery +exit 0 diff --git a/recipes/slugos-init/files/initscripts/sysconfsetup b/recipes/slugos-init/files/initscripts/sysconfsetup new file mode 100644 index 0000000000..a4f9074d9c --- /dev/null +++ b/recipes/slugos-init/files/initscripts/sysconfsetup @@ -0,0 +1,46 @@ +#!/bin/sh +# This script is run once when the system first boots. Its sole +# purpose is to create /etc/default/sysconf (the overall system +# configuration file) and other files derived from this. +# +# The script runs immediately after S10checkroot.sh - this is the +# point at which the rootfs will be mounted rw even if the kernel +# booted with it ro. +# +# rm or mv the file (/etc/default/sysconf) to recreate it, run this +# script with the reload option to overwrite the system files. The +# configuration files described in sysconf_reload (in +# /sbin/sysconf) will be overwritten on reload. +# +# start: standard startup, do a complete (auto) restore if necessary +# reinit: always do a complete auto restore +# reload: just reload sysconf (no config files!) +# +# /etc/default/functions contains useful utility functions - it's +# in a separate file so that it can be loaded by any script +. /etc/default/functions +load_functions sysconf || exit 1 +# +case "$1" in +start) test -s /etc/default/sysconf || { + if sysconf_read + then + if sysconf_valid + then + sysconf_restore auto + else + sysconf_reload + fi + else + sysconf_default + sysconf_reload + fi + };; + +reload) test -s /etc/default/sysconf || sysconf_read || sysconf_default + sysconf_reload;; + +reinit) sysconf_restore auto;; + +*) ;; +esac diff --git a/recipes/slugos-init/files/initscripts/syslog.buffer b/recipes/slugos-init/files/initscripts/syslog.buffer new file mode 100644 index 0000000000..9285c02946 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/syslog.buffer @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Invoke the syslog startup if the configuration +# uses (only) 'buffer' as the DESTINATION +DESTINATION= +test -f /etc/syslog.conf && . /etc/syslog.conf +doit= + +for d in $DESTINATION +do + case "$d" in + buffer) doit=1;; + file) exit 0;; + remote) exit 0;; + *) echo "/etc/syslog.conf: $d: unknown destination" >&2 + exit 1;; + esac +done + +test -n "$doit" -a -x /etc/init.d/syslog && + exec /etc/init.d/syslog "$@" + +exit 0 diff --git a/recipes/slugos-init/files/initscripts/syslog.file b/recipes/slugos-init/files/initscripts/syslog.file new file mode 100644 index 0000000000..80ee5f0174 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/syslog.file @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Invoke the syslog startup if the configuration +# uses 'file' (and, optionally, buffer) as the DESTINATION +DESTINATION= +test -f /etc/syslog.conf && . /etc/syslog.conf +doit= + +for d in $DESTINATION +do + case "$d" in + buffer) :;; + file) doit=1;; + remote) exit 0;; + *) echo "/etc/syslog.conf: $d: unknown destination" >&2 + exit 1;; + esac +done + +test -n "$doit" -a -x /etc/init.d/syslog && + exec /etc/init.d/syslog "$@" + +exit 0 diff --git a/recipes/slugos-init/files/initscripts/syslog.network b/recipes/slugos-init/files/initscripts/syslog.network new file mode 100644 index 0000000000..3d7f4ab8e6 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/syslog.network @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Invoke the syslog startup if the configuration +# uses 'remote', or doesn't use 'buffer' or 'file' +DESTINATION= +test -f /etc/syslog.conf && . /etc/syslog.conf +doit= +doneit= + +for d in $DESTINATION +do + case "$d" in + buffer) doneit=1;; + file) doneit=1;; + remote) doit=1;; + *) doit=1 + echo "/etc/syslog.conf: $d: unknown destination" >&2 + exit 1;; + esac +done + +# One of doneit or doit is set unless the DESTINATION value +# is empty (which is probably an error), let syslog handle +# the error. +test \( -n "$doit" -o -z "$doneit" \) -a -x /etc/init.d/syslog && + exec /etc/init.d/syslog "$@" + +exit 0 diff --git a/recipes/slugos-init/files/initscripts/umountinitrd.sh b/recipes/slugos-init/files/initscripts/umountinitrd.sh new file mode 100644 index 0000000000..93f05a00f6 --- /dev/null +++ b/recipes/slugos-init/files/initscripts/umountinitrd.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# umount /mnt, which is where the initrd ends up mounted +# if the directory /initrd is not present, if this fails +# then the /initrd is mounted and we want to remount that +# ro - this works round the shutdown -r hang problem +. /etc/default/functions + +case "$(machine)" in +nslu2) + ffspart="Flashdisk";; +*) + ffspart="filesystem";; +esac + +while read device directory remainder +do + case "$directory" in + /mnt) echo "InitRD: unmount initrd on /mnt" >&2 + umount /mnt;; + /initrd)# need the device for a remount + ffsdev="$(mtblockdev $ffspart)" + [ -n "$ffsdev" ] || \ + ffsdev="$(mtblockdev rootfs)" + echo "Remounting $ffsdev read-only on /initrd" >&2 + if test -n "$ffsdev" -a -b "$ffsdev" + then + mount -o remount,ro "$ffsdev" /initrd + else + echo "$ffspart: $ffsdev: flash device not found" >&2 + fi;; + esac +done &2 + echo system;; + esac +} + +# trumpet "beeps" an announcement on systems with such support. +l=120 # Long beep time +s=40 # Try to keep a 3:1 ratio +trumpet(){ + case "$1" in + k) leds beep -l $l; leds beep -l $s; leds beep -l $l;; + n) leds beep -l $l; leds beep -l $s;; + *) leds beep;; + esac +} + +case "$1" in +start) leds "$(state "$runlevel")" + if [ "$(state "$runlevel")" == "user" ]; then + trumpet "k" + fi + ;; +stop) leds boot "$(state "$runlevel")" + ;; +*) echo "led change: $1: command ignored" >&2 + ;; +esac diff --git a/recipes/slugos-init/files/leds b/recipes/slugos-init/files/leds new file mode 100644 index 0000000000..b40d5d874e --- /dev/null +++ b/recipes/slugos-init/files/leds @@ -0,0 +1,269 @@ +#!/bin/sh +# leds +# +# utilities to manipulate the settings of the system leds +# +# load the utility functions unless this script is being called +# just to load its own functions. +case "$1" in +leds) ;; +*) . /etc/default/rcS + . /etc/default/functions;; +esac + +# +# led_set led-dir off|on|slow|fast|panic|blink|flash|* +# set the given LED (expressed as a directory) to the +# given status. +# +led_set(){ + local setting + # expect led-dir state + if test -d "$1" + then + setting="$2" + case "$setting" in + off|on) echo -n none + + case "$setting" in + on) echo -n 255;; + off) echo -n 0;; + esac >"$1/brightness";; + + slow|fast|panic|blink|flash) + echo -n timer + + case "$setting" in + flash) echo -n 60;; + blink) echo -n 540;; + slow) echo -n 500;; + fast) echo -n 1500;; + panic) echo -n 3000;; + esac >"$1/delay_on" + + case "$setting" in + flash) echo -n 540;; + blink) echo -n 60;; + slow) echo -n 500;; + fast) echo -n 1500;; + panic) echo -n 3000;; + esac >"$1/delay_off";; + + *) echo -n "$setting";; + esac >"$1/trigger" + else + echo "leds: $1: no such directory" >&2 + return 1 + fi +} + +# +# sysled [boot] system|user|singleuser|shutdown [error|panic|*] +# set the system LEDs to indicate the given boot state, the function +# will temporarily mount sysfs is necessary (using /mnt) +# +# the cases for two LEDs (ready+status) +sysled_readystatus(){ + local ready status + # expect dir [boot](system|user) [error|panic] + case "$3" in + error) ready=fast; status=off;; + panic) ready=fast; status=fast;; + *) case "$2" in + bootsystem) ready=slow; status=slow;; + system) ready=on; status=on;; + bootuser) ready=on; status=slow;; + user) ready=user; status=off;; + bootsingleuser) ready=on; status=slow;; + singleuser) ready=user; status=user;; + bootshutdown) ready=on; status=slow;; + shutdown) ready=slow; status=on;; + esac;; + esac + + led_set "$1/$ready_led_name" "$ready" + led_set "$1/$status_led_name" "$status" +} +# +# the cases for one LED (just ready) +sysled_ready(){ + local ready + # expect dir [boot](system|user) [error|panic] + case "$3" in + error) ready=fast;; + panic) ready=panic;; + *) case "$2" in + bootsystem) ready=flash;; + system) ready=blink;; + bootuser) ready=slow;; + user) ready=user;; + bootsingleuser) ready=flash;; + singleuser) ready=blink;; + bootshutdown) ready=slow;; + shutdown) ready=blink;; + esac;; + esac + + led_set "$1/$ready_led_name" "$ready" +} +# +# the cases for one blue flashing LED (just power) +sysled_power(){ + local power + # expect dir [boot](system|user) [error|panic] + case "$3" in + error) power=off;; + panic) power=off;; + *) case "$2" in + bootsystem) power=off;; # blinking + system) power=off;; # blinking + bootuser) power=on;; + user) power=on;; + bootsingleuser) power=off;; # blinking + singleuser) power=off;; # blinking + bootshutdown) power=off;; # blinking + shutdown) power=off;; # blinking + esac;; + esac + + led_set "$1/$power_led_name" "$power" +} +# +sysled(){ + local mp st boot isst + mp=/sys + st=1 + boot= + + # validate arguments + if test "$1" = boot + then + shift + boot=boot + fi + case "$1" in + system|user|singleuser|shutdown) :;; + *) echo "sysled: unknown option '$1'" >&2 + echo " usage: sysled [boot] system|user|singleuser|shutdown [error|panic|*]" >&2 + return 1;; + esac + + if test ! -d "$mp/class/leds" && mount -t sysfs sysfs /mnt + then + mp=/mnt + fi + # + # check for the 'ready' LED - otherwise check for a 'power' LED + if test -d "$mp/class/leds/$ready_led_name" + then + if test -d "$mp/class/leds/$status_led_name" + then + sysled_readystatus "$mp/class/leds" $boot"$@" + else + sysled_ready "$mp/class/leds" $boot"$@" + fi + else + if test -d "$mp/class/leds/$power_led_name" + then + sysled_power "$mp/class/leds" $boot"$@" + fi + fi + # + # clean up + test "$mp" = /mnt && umount /mnt + return "$st" +} + +# +# beep {arguments} +# emit a beep +# does nothing if there is no beep executable, is very +# quiet in the presence of errors +beep(){ + local arg devices module + arg= + test "$1" = beep && shift + if test -x /bin/beep + then + devices=`ls -d /sys/class/input/event* 2>/dev/null` + for device in $devices + do + module=`egrep PHYSDEVDRIVER $device'/uevent' | cut -d '=' -f 2` + if test "$module" = "ixp4xx-beeper"; + then + devnode=`echo "$device" | cut -d '/' -f 5` + arg="-e /dev/input/"$devnode + break + fi + done + /bin/beep $arg "$@" 2>/dev/null + fi + return 0 +} + +# +# leds_help +# be helpful +# leds off|on|slow|fast|panic|blink|flash|user|* +# leds [boot] system|user|singleuser|shutdown [error|panic|*] +leds_help(){ + echo "leds: change the setting of the LEDs" >&2 + echo " usage:" >&2 + echo " leds [boot] system|user|singleuser|shutdown [error|panic|*]" >&2 + echo " set leds during system boot to indicate a particular boot" >&2 + echo " state. 'boot' means that the system is transitioning to" >&2 + echo " the new state. 'error' or 'panic' means a (potentially)" >&2 + echo " recoverable error or an unrecoverable error ('panic') has" >&2 + echo " occured." >&2 + echo " off|on|slow|fast|panic|blink|flash" >&2 + echo " set the named led to the given display." >&2 + echo " beep {args}" >&2 + echo " if possible cause the machine to emit a beep" >&2 +} + +# Define the LED names based on kernel version. +version=$(uname -r | cut -c -6) +if [ "$version" \< "2.6.25" ]; then + status_led_name="status" + ready_led_name="ready" + power_led_name="power" +else + case "$(machine)" in + dsmg600) + status_led_name="none" + ready_led_name="none" + power_led_name="dsmg600:green:power" + ;; + fsg3) + status_led_name="none" + ready_led_name="fsg:blue:sync" + power_led_name="none" + ;; + nas100d) + status_led_name="none" + ready_led_name="none" + power_led_name="nas100d:blue:power" + ;; + nslu2) + status_led_name="nslu2:red:status" + ready_led_name="nslu2:green:ready" + power_led_name="none" + ;; + esac +fi + +# the real command, if required +case "$1" in +boot|system|user|singleuser|shutdown) + sysled "$@";; + +beep) beep "$@";; + +""|-*) leds_help;; +help) leds_help;; + +leds) # just load the functions + ;; + +*) led_set /sys/class/leds/"$@" +esac diff --git a/recipes/slugos-init/files/links.conf b/recipes/slugos-init/files/links.conf new file mode 100644 index 0000000000..fdd1f3ce23 --- /dev/null +++ b/recipes/slugos-init/files/links.conf @@ -0,0 +1,6 @@ +# This file does not exist. Please do not ask the debian maintainer about it. +# You may use it to do strange and wonderful things, at your risk. + +# The new RTC class does not create the /dev/rtc symlink, and udev rules don't get run for built-in modules. +# So it looks like we have to do this here for the moment, until someone comes up with a better idea ... +L rtc rtc0 diff --git a/recipes/slugos-init/files/modulefunctions b/recipes/slugos-init/files/modulefunctions new file mode 100644 index 0000000000..02bfccb500 --- /dev/null +++ b/recipes/slugos-init/files/modulefunctions @@ -0,0 +1,45 @@ +#!/bin/sh +# . this file to load the functions for automatically loading modules +# NB: /proc must be mounted for correct evaluation of "$(machine)". + +. /etc/default/functions + +loaddiskmods(){ + case "$(machine)" in + nslu2) + [ -d /sys/module/ehci_hcd ] || modprobe ehci-hcd + [ -d /sys/module/ohci_hcd ] || modprobe ohci-hcd + ;; + nas100d) + [ -d /sys/module/ehci_hcd ] || modprobe ehci-hcd + [ -d /sys/module/uhci_hcd ] || modprobe uhci-hcd + [ -d /sys/module/pata_artop ] || modprobe pata-artop + ;; + dsmg600) + [ -d /sys/module/ehci_hcd ] || modprobe ehci-hcd + [ -d /sys/module/uhci_hcd ] || modprobe uhci-hcd + [ -d /sys/module/pata_artop ] || modprobe pata-artop + ;; + + esac +} + +loadnetmods(){ + case "$(machine)" in + dsmg600) + [ -d /sys/module/via_velocity ] || modprobe via-velocity + ;; + *) + true + ;; + esac +} + +loadnfsmods(){ + [ -d /sys/module/nfs ] || modprobe nfs +} + +loadmiscmods(){ + true +} + diff --git a/recipes/slugos-init/files/modutils.txt b/recipes/slugos-init/files/modutils.txt new file mode 100644 index 0000000000..a73b480efe --- /dev/null +++ b/recipes/slugos-init/files/modutils.txt @@ -0,0 +1 @@ +# Adding modules to be automatically loaded via update-modules diff --git a/recipes/slugos-init/files/reflash b/recipes/slugos-init/files/reflash new file mode 100644 index 0000000000..22a18bb068 --- /dev/null +++ b/recipes/slugos-init/files/reflash @@ -0,0 +1,658 @@ +#!/bin/sh +# reflash +# ensure the flash disk is not mounted +# save configuration files +# update the kernel +# update the flashdisk +# restore the saved configuration files +# the set of configuration files is described by +# /etc/default/conffiles. +# +# /etc/default/functions contains useful utility functions +. /etc/default/functions +load_functions sysconf +# +# NSLU2 flash layout is non-standard. +case "$(machine)" in +nslu2) + isnslu2=1 + isdsmg600= + isnas100d= + imageok=1 + apexpart="Loader" + usrpart= + kpart="Kernel" + ffspart="Flashdisk";; +nas100d) + isnslu2= + isdsmg600= + isnas100d=1 + imageok=1 + apexpart= + usrpart="usr" + kpart="kernel" + ffspart="filesystem";; +dsmg600) + isnslu2= + isdsmg600=1 + isnas100d= + imageok=1 + apexpart= + usrpart="usr" + kpart="kernel" + ffspart="filesystem";; +*) + isnslu2= + isdsmg600= + isnas100d= + imageok= + apexpart= + usrpart= + kpart="kernel" + ffspart="filesystem";; +esac +# +# CHECKING FOR INPUT (ARGUMENTS ETC) +# ---------------------------------- +# +# find the kernel and the new flash file system, an image file can +# be used to specify both images. +ffsfile= +kfile= +imgfile= +preserve_config=1 +while test $# -gt 0 +do + case "$1" in + -n) preserve_config= + shift;; + -k) shift + test $# -gt 0 || { + echo "reflash: -k: give the file containing the kernel image" >&2 + exit 1 + } + kfile="$1" + shift;; + -[jr]) shift + test $# -gt 0 || { + echo "reflash: -j: give the file containing the root jffs2 image" >&2 + exit 1 + } + ffsfile="$1" + shift;; + -i) shift + test -n "$imageok" || { + echo "reflash: -i: only supported on the LinkSys NSLU2," >&2 + echo " Iomega NAS 100d and D-Link DSM-G600 systems; use -k and -j" >&2 + echo " to specify the kernel and root file system instead." >&2 + exit 1 + } + test $# -gt 0 || { + echo "reflash: -i: give the file containing the complete flash image" >&2 + exit 1 + } + imgfile="$1" + shift;; + *) if test -n "$imageok" + then + echo "reflash: usage: $0 [-n] [-k kernel] [-j rootfs] [-i image]" >&2 + else + echo "reflash: usage: $0 [-n] [-k kernel] [-j rootfs]" >&2 + fi + echo " -n: do not attempt to preserve the configuration" >&2 + echo " -k file: the new compressed kernel image ('zImage')" >&2 + echo " -j file: the new root file system (jffs2)" >&2 + test -n "$imageok" && + echo " -i file: a complete flash image (gives both kernel and jffs2)" >&2 + echo " The current jffs2 will be umounted if mounted." >&2 + exit 1;; + esac +done +# +# Sanity check on the arguments (note that the first case can only fire +# on NSLU2 or DSM-G600 because of the check for -i above.) +if test -n "$imgfile" -a -n "$ffsfile" -a -n "$kfile" +then + echo "reflash: specify at most two files" >&2 + echo " -i has both a kernel and rootfs, the kernel from -k and" >&2 + echo " the rootfs from -j override the one in the image (if given)" >&2 + exit 1 +elif test -z "$imgfile" -a -z "$ffsfile" -a -z "$kfile" +then + echo "reflash: specify at least one file to flash" >&2 + exit 1 +fi +# +# Perform basic checks on the input (must exist, size must be ok). +if test -n "$imgfile" +then + if test -r "$imgfile" -a -n "$isnslu2" + then + # read the partition table and from this find the offset + # and size of $kpart and $ffspart partitions. The following + # devio command just dumps the partition table in a format + # similar to /proc/mtd (but it outputs decimal values!) + #NOTE: this uses a here document because this allows the while + # loop to set the variables, a pipe would put the while in + # a sub-shell and the variable settings would be lost. This + # works in ash, no guarantees about other shells! + while read size base name + do + if test "$name" = "$apexpart" + then + imgapexsize="$size" + imgapexoffset="$base" + elif test "$name" = "$kpart" + then + imgksize="$size" + imgkoffset="$base" + elif test "$name" = "$ffspart" -o "$name" = "rootfs" + then + imgffssize="$size" + imgffsoffset="$base" + fi + done <') +EOI + # check the result + test "$imgksize" -gt 0 -a "$imgkoffset" -ge 0 || { + echo "reflash: $imgfile: failed to find $kpart partition in image" >&2 + exit 1 + } + # the kernel is after a 16 byte header which holds the + # values length,0,0,0 Get the true size. + ktmp="$(devio "<<$imgfile" "L=$imgksize" "O=$imgkoffset" ' + $( OL+$>! + <= O + A= b + $( AL>! + pr A + $) 0 + $) 0')" + test "$ktmp" -gt 0 || { + echo "reflash: $imgfile($imgkoffset,$imgksize): invalid kernel offset/size" >&2 + exit 1 + } + # update the size and offset to these values (the offset is 16+ because + # of the header). + imgksize="$ktmp" + imgkoffset="$(devio "O=$imgkoffset" 'pr O16+')" + # just test the size for the rootfs + test "$imgffssize" -gt 0 -a "$imgffsoffset" -ge 0 || { + echo "reflash: $imgfile: failed to find $ffspart" >&2 + exit 1 + } + elif test -r "$imgfile" -a \( -n "$isdsmg600" -o -n "$isnas100d" \) + then + # + # For the DSM-G600, this is really easy - the image is just + # a tar file. So, extract the contents of the tar file, and + # set the kernel and filesystem variables (if not already set) + # to point to the extracted content. Content will look like: + # + # drwxr-xr-x 500/500 0 2006-11-25 23:47:59 firmupgrade + # -rw-r--r-- 500/500 4718592 2006-12-02 16:32:51 firmupgrade/rootfs.gz + # -rw-r--r-- 500/500 40 2006-11-25 22:15:41 firmupgrade/version.msg + # -rw-r--r-- 500/500 0 2006-11-25 23:47:59 firmupgrade/usr.cramfs + # -rw-rw-r-- 500/500 1306872 2006-12-02 16:33:37 firmupgrade/ip-ramdisk + # + # Heuristic: if the size of usr.cramfs is zero, the firmware + # is not a D-Link firmware for the device. (The version.msg + # file is not useful for this purpose; it describes the hardware, + # not the firmware version in the image!) + # + # TODO: If usr.cramfs is non-zero, we should flash that, too, just + # to make sure that it matches the native firmware's kernel + # and rootfs that we're now flashing back onto the device. + + echo "reflash: unpacking DSM-G600/NAS-100d image file" >&2 + tar -x -f "$imgfile" -C /var/tmp || { + echo "reflash: unable to unpack image file to be flashed" >&2 + exit 1 + } + + if test -z "$kfile" + then + kfile="/var/tmp/firmupgrade/ip-ramdisk" + fi + + if test -z "$ffsfile" + then + ffsfile="/var/tmp/firmupgrade/rootfs.gz" + fi + + if test -s "/var/tmp/firmupgrade/usr.cramfs" + then + echo "reflash: Native flash being restored" >&2 + usrfile="/var/tmp/firmupgrade/usr.cramfs" + preserve_config= + fi + + else + echo "reflash: $imgfile: image file not found" >&2 + exit 1 + fi +fi +if test -n "$kfile" +then + if test ! -r "$kfile" + then + echo "reflash: $kfile: kernel file not found" >&2 + exit 1 + fi + # the file values override anything from the image. + imgksize="$(devio "<<$kfile" 'pr$')" + imgkoffset=0 +else + kfile="$imgfile" +fi +if test -n "$ffsfile" +then + if test ! -r "$ffsfile" + then + echo "reflash: $ffsfile: root file system image file not found" >&2 + exit 1 + fi + # values override those from the image + imgffssize="$(devio "<<$ffsfile" 'pr$')" + imgffsoffset=0 +else + ffsfile="$imgfile" +fi +if test -n "$usrfile" +then + if test ! -r "$usrfile" + then + echo "reflash: $usrfile: usr file system image file not found" >&2 + exit 1 + fi + # values override those from the image + imgusrsize="$(devio "<<$usrfile" 'pr$')" + imgusroffset=0 +else + usrfile= +fi +# +# INPUTS OK, CHECKING THE ENVIRONMENT +# ----------------------------------- +# basic setup. This could be parameterised to use different partitions! +# +kdev= +ksize=0 +if test -n "$kfile" +then + # we have a new kernel + kdev="$(mtblockdev $kpart)" + test -n "$kdev" -a -b "$kdev" || { + echo "reflash: $kpart($kdev): cannot find $kpart mtd partition." >&2 + echo " check /proc/mtd, either the partition does not exist or there is no" >&2 + echo " corresponding block device." >&2 + exit 1 + } + ksize="$(devio "<<$kdev" 'pr$')" + # + # check the input file size + test -n "$imgksize" -a "$imgksize" -gt 0 -a "$imgksize" -le "$ksize" || { + echo "reflash: $kfile: bad $kpart size ($imgksize, max $ksize)" >&2 + exit 1 + } +fi +# +ffsdev= +ffssize=0 +if test -n "$ffsfile" +then + ffsdev="$(mtblockdev $ffspart)" + [ -n "$ffsdev" ] || \ + ffsdev="$(mtblockdev rootfs)" + test -n "$ffsdev" -a -b "$ffsdev" || { + echo "reflash: $ffspart($ffsdev): cannot find $ffspart mtd partition." >&2 + echo " check /proc/mtd, either the partition does not exist or there is no" >&2 + echo " corresponding block device." >&2 + exit 1 + } + ffssize="$(devio "<<$ffsdev" 'pr$')" + # + # check the input file size + test -n "$imgffssize" -a "$imgffssize" -gt 0 -a "$imgffssize" -le "$ffssize" || { + echo "reflash: $ffsfile: bad $ffspart size ($imgffsize, max $ffssize)" >&2 + exit 1 + } +fi +# +usrdev= +usrsize=0 +if test -n "$usrfile" +then + usrdev="$(mtblockdev $usrpart)" + test -n "$usrdev" -a -b "$usrdev" || { + echo "reflash: $usrpart($usrdev): cannot find $usrpart mtd partition." >&2 + echo " check /proc/mtd, either the partition does not exist or there is no" >&2 + echo " corresponding block device." >&2 + exit 1 + } + usrsize="$(devio "<<$usrdev" 'pr$')" + # + # check the input file size + test -n "$imgusrsize" -a "$imgusrsize" -gt 0 -a "$imgusrsize" -le "$usrsize" || { + echo "reflash: $usrfile: bad $usrpart size ($imgusrsize, max $usrsize)" >&2 + exit 1 + } +fi + +# +# INPUTS OK, ENVIRONMENT OK, UMOUNT ANY EXISTING MOUNT OF THE FLASHDISK +# --------------------------------------------------------------------- +# This is only required if the device is going to be used +if test -n "$ffsdev" +then + # -r causes this to fail if the flash device is mounted on / + umountflash -r "$ffsdev" || exit 1 + # + # Everything is umounted, now remount on a temporary directory. + ffsdir="/tmp/flashdisk.$$" + mkdir "$ffsdir" || { + echo "reflash: $ffsdir: failed to create temporary directory" >&2 + exit 1 + } + # + mountflash "$ffsdev" "$ffsdir" -o ro || { + rmdir "$ffsdir" + exit 1 + } + # + # this is a utility function to make the cleanup easier + errorexit() { + umount "$ffsdir" && rmdir "$ffsdir" || + echo "reflash: $ffsdir: temporary directory cleanup failed" >&2 + exit 1 + } + # + test -r "$ffsdir/etc/default/conffiles" || { + echo "reflash: [/initrd]/etc/default/conffiles: file not found" >&2 + errorexit + } +else + errorexit() { + exit 1 + } +fi +# +# PRESERVE EXISTING CONFIGURATION +# ------------------------------- +# Only required if the flash partition will be written +if test -n "$ffsdev" -a -n "$preserve_config" +then + echo "reflash: preserving existing configuration file" >&2 + # + # This step produces /tmp/preserve.$$ and /tmp/cpio.$$, the former is + # a list of the preserved configuration files together with the processing + # option, the latter is a directory tree of the preserved files (a directory + # tree makes the restore step easier.) + saved=/tmp/cpio.$$ + list=/tmp/preserve.$$ + mkdir "$saved" || { + echo "reflash: $saved: could not create save directory" >&2 + errorexit + } + # + # sysconf_save_conffiles + sysconf_save_conffiles "$ffsdir" "$saved" "$list" || { + echo "reflash: $saved: copy of saved configuration files failed" >&2 + rm -rf "$saved" + rm "$list" + errorexit + } + # + # If this umount fails do not try to continue... + umount "$ffsdir" || { + echo "reflash: $ffsdir: temporary mount point umount failed" >&2 + echo " No changes have been made." >&2 + rm -rf "$saved" + rm "$list" + exit 1 + } +fi +# +# FLASH THE NEW IMAGES +# -------------------- +echo "reflash: about to flash new image" >&2 +# +# There are four possibilities here - kernel only, flashdisk only, then +# kernel&flashdisk in either one or two different files. The code used +# to attempt to do everything in one step, but this complicates it, +# so two steps are used (as required). A failure between the two +# steps is a problem, but then so is a failure in a partial write. +# Write the flashdisk first because this is larger (most likely to +# fail). +# +# -p causes the progress indicator to be displayed +progress=-p +do_kernel() { + local cmd + if test -n "$isnslu2" + then + # NSLU2: write length,0,0,0 header, then fill + cmd="wb L,4; fb 12,0; cpL" + else + # Other: just write the kernel bytes + cmd="cpL" + fi + devio $progress "$@" "<<$kfile" ">>$kdev" ' + # kernel is at imgkoffset[imgksize] + ' "<= $imgkoffset" "L=$imgksize" "$cmd" ' + # fill with 255 + fb #t-,255' +} +# +do_ffs() { + devio $progress "$@" "<<$ffsfile" ">>$ffsdev" ' + # rootfs is at imgffsoffset[imgffssize] + ' "<= $imgffsoffset" "cp $imgffssize" ' + # fill with 255 + fb #t-,255' +} +# +do_usr() { + devio $progress "$@" "<<$usrfile" ">>$usrdev" ' + # usrfs is at imgusroffset[imgusrsize] + ' "<= $imgusroffset" "cp $imgusrsize" ' + # fill with 255 + fb #t-,255' +} +# +# check_status $? type file(offset,size) device +# check the devio status code (given in $1) +check_status() { + case "$1" in + 0) echo " done" >&2;; + 1) echo " failed" >&2 + echo "reflash: $3: flash $2 failed, no changes have been made to $4" >&2 + if test "$2" = rootfs + then + rm -rf "$saved" + rm "$list" + exit 1 + else + echo "reflash: $2: continuing with rootfs changes" >&2 + echo " NOTE: the old kernel is still in $4!" >&2 + fi;; + 3) echo " failed" >&2 + echo "reflash: $3: WARNING: partial flash of $2 to $4 the system is unbootable" >&2 + echo " Reflash from RedBoot or correct the problem here." >&2 + if test "$2" = rootfs + then + exit 3 + else + echo "reflash: $2: continuing with rootfs changes" >&2 + echo " NOTE: the kernel in $4 must be reflashed!" >&2 + fi;; + *) echo " failed" >&2 + echo "reflash($1): $3: internal error flashing $2 to $4" >&2 + exit $1;; + esac +} +# +if test -n "$usrdev" +then + echo -n "reflash: writing usrfs to $usrdev " >&2 + do_usr + check_status $? usrfs "$usrfile($imgusroffset,$imgusrsize)" "$usrdev" +fi +# +if test -n "$ffsdev" +then + echo -n "reflash: writing rootfs to $ffsdev " >&2 + do_ffs + check_status $? rootfs "$ffsfile($imgffsoffset,$imgffssize)" "$ffsdev" +fi +# +if test -n "$kdev" +then + echo -n "reflash: writing kernel to $kdev " >&2 + do_kernel + check_status $? kernel "$kfile($imgkoffset,$imgksize)" "$kdev" +fi +# +# verify - this just produces a warning +if test -n "$usrdev" +then + echo -n "reflash: verifying new usr image " >&2 + if do_usr -v + then + echo " done" >&2 + else + echo " failed" >&2 + echo "reflash: WARNING: usrfs flash image verification failed" >&2 + echo " The system is may be bootable." >&2 + fi +fi +# +if test -n "$ffsdev" +then + echo -n "reflash: verifying new flash image " >&2 + if do_ffs -v + then + echo " done" >&2 + else + echo " failed" >&2 + echo "reflash: WARNING: rootfs flash image verification failed" >&2 + echo " The system is probably unbootable." >&2 + echo " System configuration files will be restored but this may fail" >&2 + echo " Starting a shell for user recovery (exit to continue)" >&2 + PS1='badflash$ ' sh -i <>/dev/tty >&0 2>&0 + fi +fi +# +if test -n "$kdev" +then + echo -n "reflash: verifying new kernel image " >&2 + if do_kernel -v + then + echo " done" >&2 + else + echo " failed" >&2 + echo "reflash: WARNING: kernel flash image verification failed" >&2 + echo " The system is probably unbootable." >&2 + echo " System configuration files will be restored in the rootfs." >&2 + fi +fi +# +# RESTORE THE OLD CONFIGURATION +# ----------------------------- +# If not write the rootfs none of the following is required - exit now. +test -n "$ffsdev" -a -n "$preserve_config" || exit 0 +# +echo "reflash: restoring saved configuration files" >&2 +# +# the file /etc/.configured is the datestamp file used to ensure that +# changed configuration files can be recognised. It is created by +# /etc/rcS.d/S99finish on first boot (if it does not exist). We need +# a timestamp earlier than any files we create so touch it here, this +# also acts as a test on the mounted file system +mountflash "$ffsdev" "$ffsdir" && :>"$ffsdir/etc/.configured" || { + rmdir "$ffsdir" + echo "reflash: mount of new flash root file system failed" >&2 + if test -d "$ffsdir/etc" + then + echo " The file system does not seem to be writeable." >&2 + echo " The mounted file system is in $ffsdir" >&2 + fi + echo " WARNING: the kernel and root file system have been reflashed," >&2 + echo " HOWEVER the new root file system seems to be unuseable." >&2 + echo " Saved configuration files are in $saved" >&2 + echo " The list of saved configuration files is in $list" >&2 + echo " You should determine the reason for the failed mount, mount the new" >&2 + echo " file system and restore the configuration from $saved - it's just a" >&2 + echo " matter of copying the saved files where required." >&2 + exit 1 +} +# +# sysconf_restore_conffiles +restore="/tmp/restore.$$" +sysconf_restore_conffiles "$ffsdir" "$saved" "$restore" <"$list" || { + echo "reflash: $saved: restore of saved configuration files failed" >&2 + echo " The new flash file system is mounted on $ffsdir" >&2 + echo " The saved files are in $saved and the list in $list, the list of" >&2 + echo " files selected for restore is in $restore" >&2 + echo " You should restore any required configuration from $saved," >&2 + echo " then umount $ffsdir and reboot." >&2 + exit 1 +} +# +# remove the copied files (i.e. the ones which were preserved) +( cd "$saved" + exec rm $(cat "$restore") +) +rm "$restore" +# +# clean up, files left in $saved need to be handled by the user +files="$(find "$saved" ! -type d -print)" +if test -n "$files" +then + echo "reflash: the following saved configuration files remain:" >&2 + echo "$files" >&2 + echo "The full list of preserved files is in $list. To alter the" >&2 + echo "new root file system use the command:" >&2 + echo "" >&2 + echo " mount -t jffs2 $ffsdev /mnt" >&2 + echo "" >&2 + echo "The saved files are in the temporary directory, they will not" >&2 + echo "be retained across a system boot. Copy them elsewhere if you" >&2 + echo "are unsure whether they are needed" >&2 +else + rm -rf "$saved" + rm "$list" +fi +# +# now the final umount +if umount "$ffsdir" +then + rmdir "$ffsdir" + echo "reflash: system upgrade complete. Reboot to continue." >&2 + exit 0 +else + echo "reflash: $ffsdir: temporary mount point umount failed" >&2 + echo " ALL changes have been made successfully, however the umount of" >&2 + echo " the new root file system has failed. You should determine the" >&2 + echo " cause of the failure, umount $ffsdir, then reboot the system (this" >&2 + echo " will use the upgraded kernel and root file system)" >&2 + exit 1 +fi diff --git a/recipes/slugos-init/files/setup-optware.sh b/recipes/slugos-init/files/setup-optware.sh new file mode 100644 index 0000000000..d4ae619491 --- /dev/null +++ b/recipes/slugos-init/files/setup-optware.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +if test 0 != `id -u`; then + echo 'Please run as root' + exit 1 +fi + +optware_target=slugos5be +feed=http://ipkg.nslu2-linux.org/feeds/optware/${optware_target}/cross/unstable +latest_xsh=`wget -q -O- ${feed} | grep '\.xsh' | sed -e 's/.*xsh">//' -e 's/<.*//'` + +if test -n "${latest_xsh}"; then + cd /tmp + rm -f ${latest_xsh} + wget ${feed}/${latest_xsh} + sh ${latest_xsh} +fi diff --git a/recipes/slugos-init/files/sysconf b/recipes/slugos-init/files/sysconf new file mode 100644 index 0000000000..8d59d5d6f3 --- /dev/null +++ b/recipes/slugos-init/files/sysconf @@ -0,0 +1,796 @@ +#!/bin/sh +# sysconf +# +# utility to manipulate system configuration information help +# in a RedBoot SysConf partition +# +# load the utility functions (unless this is being called just +# to load these functions!) +test "$1" != sysconf && . /etc/default/functions + +case "$(machine)" in +nslu2) + kpart="Kernel" + syspart="SysConf" + ffspart="Flashdisk";; +*) + kpart="kernel" + syspart="sysconfig" + ffspart="filesystem";; +esac +# +# sysconf_valid +# return true if the SysConf partition exists and seems to be +# potentially valid (it starts with a reasonable length). +sysconf_valid(){ + local sysdev + sysdev="$(mtblockdev $syspart)" + test -n "$sysdev" -a -b "$sysdev" && + devio "<<$sysdev" '!! b.10>s32768<&!' +} + +# +# sysconf_read [prefix] +# read the $syspart partition (if present) writing the result into +# /etc/default/sysconf, if the result is empty it will be removed. +sysconf_read(){ + local sysdev sedcmd mac config_root + config_root="$1" + rm -f /tmp/sysconf.new + sysdev="$(mtblockdev $syspart)" + if sysconf_valid + then + # Read the defined part of $syspart into /etc/default/sysconf. + # $syspart has lines of two forms: + # + # [section] + # name=value + # + # In practice $syspart also contains other stuff, use the command: + # + # devio '</tmp/sysconf.new + fi + # + # test the result - sysconf must be non-empty + if test -s /tmp/sysconf.new + then + mv /tmp/sysconf.new "$config_root/etc/default/sysconf" + else + rm -f /tmp/sysconf.new + return 1 + fi +} + +# +# sysconf_default [prefix] +# Provde a default /etc/default/sysconf when there is no $syspart partition, +# or when it is invalid, this function will read from an existing sysconf, +# copying the values into the new one. +# sysconf_line tag config-tag +# write an appropriate line if the config value is non-empty +sysconf_line(){ + config "$2" | { + local value + read value + test -n "$value" && echo "$1"="$value" + } +} +# +sysconf_default(){ + local config_root + config_root="$1" + { echo '[network]' + sysconf_line hw_addr mac + sysconf_line disk_server_name host + sysconf_line w_d_name domain + sysconf_line lan_interface iface + sysconf_line ip_addr ip + sysconf_line netmask netmask + sysconf_line gateway gateway + sysconf_line dns_server1 dns + sysconf_line dns_server2 dns2 + sysconf_line dns_server3 dns3 + sysconf_line bootproto boot + } >/tmp/sysconf.new + mv /tmp/sysconf.new "$config_root/etc/default/sysconf" +} + +# +# sysconf_reload [prefix] +# read the values from /etc/default/sysconf and use these values to set +# up the following system files: +# +# /etc/hostname +# /etc/defaultdomain +# /etc/resolv.conf +# /etc/network/interfaces +# /etc/motd +# +sysconf_reload(){ + local config_root host domain iface boot ip netmask gateway ifname iftype + config_root="$1" + host="$(config host)" + test -n "$host" && echo "$host" >"$config_root/etc/hostname" + domain="$(config domain)" + test -n "$domain" && echo "$domain" >"$config_root/etc/defaultdomain" + # + # The DNS server information gives up to three nameservers, + # but this currently only binds in the first. + { + test -n "$domain" && echo "search $domain" + test -n "$(config dns)" && echo "nameserver $(config dns)" + test -n "$(config dns2)" && echo "nameserver $(config dns2)" + test -n "$(config dns3)" && echo "nameserver $(config dns3)" + } >"$config_root/etc/resolv.conf" + # + # Ethernet information. This goes into /etc/network/interfaces, + # however this is only used for static setup (and this is not + # the default). With dhcp the slugos udhcp script, + # /etc/udhcpc.d/50default, loads the values from sysconf. + iface="$(config iface)" + boot="$(config boot)" + # Only dhcp and static are supported at present - bootp + # support requires installation of appropriate packages + # dhcp is the fail-safe + case "$boot" in + dhcp|static) ;; + *) boot=dhcp;; + esac + # + ip="$(config ip)" + netmask="$(config netmask)" + gateway="$(config gateway)" + { + echo "# /etc/network/interfaces" + echo "# configuration file for ifup(8), ifdown(8)" + echo "#" + echo "# The loopback interface" + echo "auto lo" + echo "iface lo inet loopback" + echo "#" + echo "# The interface used by default during boot" + echo "auto $iface" + echo "# Automatically generated from /etc/default/sysconf" + echo "# address, netmask and gateway are ignored for 'dhcp'" + echo "# but required for 'static'" + echo "iface $iface inet $boot" + # The following are ignored for DHCP but are harmless + test -n "$ip" && echo " address $ip" + test -n "$netmask" && echo " netmask $netmask" + test -n "$gateway" && echo " gateway $gateway" + # + # Now read all the other ARPHRD_ETHER (type=1) interfaces + # and add an entry for each. + for ifname in $(test -d /sys/class/net && ls /sys/class/net) + do + if test -r "/sys/class/net/$ifname/type" -a "$ifname" != "$iface" + then + read iftype <"/sys/class/net/$ifname/type" + case "$iftype" in + 1) echo "#" + echo "# /sys/class/net/$ifname:" + echo "auto $ifname" + echo "iface $ifname inet dhcp";; + esac + fi + done + } >"$config_root/etc/network/interfaces" + # + # Finally rewrite /etc/motd + { echo "Host name: $host" + echo "Domain name: $domain" + echo "Host MAC: $(config mac)" + echo "Network boot method: $boot" + case "$boot" in + static) echo "Host IP address: $ip";; + esac + echo "Use 'turnup init' to reset the configuration" + echo "Use 'turnup preserve' to save the configuration permanently" + echo "Use 'turnup restore' to restore a previously saved configuration" + echo "Use 'turnup disk|nfs -i options to initialise a non-flash root" + echo "Use 'turnup help' for more information" + } >"$config_root/etc/motd" +} + +# +# sysconf_save_conffiles +# preserve the configuration files in a directory or in a CPIO archive +# (which is *not* compressed). If is a directory the files are +# copied, otherwise a CPIO archive is made with that name. is +# the listing file giving the preserved files and the processing option. +sysconf_save_conffiles(){ + local ffsdir dest list file + ffsdir="$1" + saved="$2" + list="$3" + test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -n "$saved" -a -n "$list" || { + echo "sysconf_save_conffiles: invalid arguments: '$*'" >&2 + echo " usage sysconf_save_conffiles " >&2 + return 1 + } + # + ( cd "$ffsdir" + find etc/*.conf $(sed 's!^/!!' usr/lib/opkg/info/*.conffiles) ! -type d -newer etc/.configured -print | + sed 's/^/diff /' + exec sed 's/#.*$//;/^[ ]*$/d' etc/default/conffiles + ) | sed 's!^/*!!' | + awk '{ op=$1; $1=""; file[$0]=op } + END{ for (f in file) if (file[f] != "ignore") print file[f] f }' | + while read op file + do + if test -e "$ffsdir/$file" + then + echo "$op $file" >&3 + echo "$file" + fi + done 3>"$list" | ( + cd "$ffsdir" + if test -d "$saved" + then + exec cpio -p -d -m -u "$saved" + else + exec cpio -o -H crc >"$saved" + fi + ) +} + +# +# sysconf_verify file +# this is called with the name of a 'diff' file which is, indeed, +# different and with all the std streams connected to the tty. It +# returns a status code to say whether (0) or not (1) to copy the +# file over. +# +# globals: the following must be defined in the calling context! +# saved: the directory containing the unpacked saved files +# ffsdir: the flash directory to which the files are being restored (/) +# +sysconf_verify_help() { + echo "Please specify how to handle this file or link, the options are as follows," + echo "two character abbreviations may be used:" + echo + echo " keep: retain the old file, overwrite the new flash image file" + echo " upgrade: retain the new file, the old (saved) file is not used" + echo " diff: display the differences between the old and the new using diff -u" + echo " shell: temporarily start an interactive shell (sh -i), exit to continue" + echo " skip: ignore this file for the moment. The file is left in the directory" + echo " $saved and many be handled after this script has completed" +} +# +sysconf_verify() { + local command file + + # return 1 here causes the file not to be overwritten, + # control should never get here! + test -n "$sysconf_noninteractive" && { + echo "$0: $*: changed file cannot be handled non-interactively" >&2 + return 1 + } + + file="$1" + echo "$0: $file: configuration file changed." + sysconf_verify_help "$file" + while : + do + echo -n "option: " + read command + case "$command" in + ke*) return 0;; + up*) rm "$saved/$file" + return 1;; + di*) echo "DIFF OLD($saved) NEW($ffsdir)" + diff -u "$saved/$file" "$ffsdir/$file";; + sh*) PS1="$file: " sh -i;; + sk*) return 1;; + *) sysconf_verify_help "$file";; + esac + done +} +# the same, but for a link +sysconf_verify_link() { + local command link + + # return 1 here causes the file not to be overwritten, + # control should never get here! + test -n "$sysconf_noninteractive" && { + echo "$0: $*: changed link cannot be handled non-interactively" >&2 + return 1 + } + + link="$1" + echo "reflash: $link: configuration link changed." + sysconf_verify_help "$link" + while : + do + echo -n "option: " + read command + case "$command" in + ke*) return 0;; + up*) rm "$saved/$link" + return 1;; + di*) echo "DIFF:" + echo "OLD($saved): $link -> $(readlink "$saved/$link")" + echo "NEW($ffsdir): $link -> $(readlink "$ffsdir/$link")";; + sh*) PS1="$link: " sh -i;; + sk*) return 1;; + *) sysconf_verify_help "$link";; + esac + done +} + +# +# sysconf_restore_conffiles +# restore the configuration files from a directory. 'source-dir' +# If is a directory of files from sysconf_save_conffiles. The +# list of files restored is written to the third argument (restore), +# but is not required (/dev/null would be ok). +# +# the list of files to restore is read from stdin, along with the +# processing option for each file (the format is as produced by +# sysconf_save_conffiles in the 'list' output). +sysconf_restore_conffiles(){ + local ffsdir saved restore + # these are the globals used by the above function + ffsdir="$1" + saved="$2" + restore="$3" + test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -d "$saved" -a -n "$restore" || { + echo "restore_conffiles: invalid arguments: '$*'" >&2 + echo " usage sysconf_restore_conffiles " >&2 + return 1 + } + # + # read the list and process each given file + while read op file + do + # handle .configured specially (to preserve the original datestamp) + if test "$file" = "etc/.configured" + then + # this should definately not fail because of the test above! + if cp -a "$saved/$file" "$ffsdir/$file" + then + echo "$file" >&3 + else + echo "sysconf_restore_conffiles: $file: timestamp copy failed (ignored)" >&2 + fi + elif test -h "$saved/$file" -o -h "$ffsdir/$file" + then + # new or old symbolic link + if test -h "$saved/$file" -a -h "$ffsdir/$file" && + test "$(readlink "$saved/$file")" = "$(readlink "$ffsdir/$file")" + then + # no change + echo "$file" >&3 + else + # assume a change regardless + case "$op" in + preserve) + echo "$file" + echo "$file" >&3;; + diff) # need user input + if sysconf_verify_link "$file" /dev/tty 2>&1 + then + echo "$file" + echo "$file" >&3 + fi;; + esac + fi + else + # only overwrite if necessary + if test -e "$ffsdir/$file" && cmp -s "$saved/$file" "$ffsdir/$file" + then + # do not overwrite + echo "$file" >&3 + elif test ! -e "$ffsdir/$file" + then + # always preserve + echo "$file" + echo "$file" >&3 + else + case "$op" in + preserve) + echo "$file" + echo "$file" >&3;; + diff) # the files are different, get user input + if sysconf_verify "$file" /dev/tty 2>&1 + then + echo "$file" + echo "$file" >&3 + fi;; + esac + fi + fi + done 3>"$restore" | (cd "$saved"; exec cpio -p -d -u "$ffsdir") +} + +# +# sysconf_test_restore +# return true only if the restore does not need to do an interactive +# compare +sysconf_test_restore(){ + local ffsdir saved + # these are the globals used by the above function + ffsdir="$1" + saved="$2" + # this is an error case, but return 0 so that the error is + # detected later + test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -d "$saved" || + return 0 + # + # read the list and check each diff file (this is just a copy of the + # logic above with all the work removed!) + while read op file + do + # handle .configured specially (to preserve the original datestamp) + if test "$op" != diff + then + : # no diff required + elif test "$file" = "etc/.configured" + then + : # special handling + elif test -h "$saved/$file" -o -h "$ffsdir/$file" + then + # new or old symbolic link + if test -h "$saved/$file" -a -h "$ffsdir/$file" && + test "$(readlink "$saved/$file")" = "$(readlink "$ffsdir/$file")" + then + : # no change + else + # assume a change regardless + return 1 + fi + else + # only overwrite if necessary + if test -e "$ffsdir/$file" && cmp -s "$saved/$file" "$ffsdir/$file" + then + : # do not overwrite + elif test ! -e "$ffsdir/$file" + then + : # always preserve + else + # a change + return 1 + fi + fi + done + + return 0 +} + +# +# sysconf_save +# save the system configuration to $syspart - $syspart must exist and +# there must be a writeable device for it. +sysconf_save(){ + local sysdev ffsdev ffsdir saved list size status + ffsdev="$(mtblockdev $ffspart)" + [ -n "$ffsdev" ] || \ + ffsdev="$(mtblockdev rootfs)" + sysdev="$(mtblockdev $syspart)" + status=1 + if test -n "$sysdev" -a -b "$sysdev" -a -n "$ffsdev" -a -b "$ffsdev" + then + # this will succeed silently if the flash device is on / + umountflash "$ffsdev" || exit 1 + # + # Everything is umounted, now remount on a temporary directory. + ffsdir="/tmp/flashdisk.$$" + mkdir "$ffsdir" || { + echo "$0: $ffsdir: failed to create temporary directory" >&2 + exit 1 + } + # + mountflash "$ffsdev" "$ffsdir" -o ro || { + rmdir "$ffsdir" + exit 1 + } + # need temporary files for the cpio output and the listing + saved=/tmp/cpio.$$ + list=/tmp/preserve.$$ + rm -rf "$saved" "$list" + sysconf_save_conffiles "$ffsdir" "$saved" "$list" || { + echo "$0: $saved: archive of saved configuration files failed" >&2 + rm -rf "$saved" + rm "$list" + umount "$ffsdir" && rmdir "$ffsdir" || + echo "$0: $ffsdir: temporary directory cleanup failed" >&2 + return 1 + } + # ignore the error in this case: + umount "$ffsdir" && rmdir "$ffsdir" || + echo "$0: $ffsdir: temporary directory cleanup failed" >&2 + # + # we now have: + # /etc/default/sysconf the basic config + # /tmp/preserve.$$ the list of saved files + # /tmp/cpio.$$ the CPIO archive of those files + # + # make one big file with the sysconf data followed by the + # compressed archive in /tmp/sysconf.$$ + { { cat /etc/default/sysconf + echo '[preserve]' + } | sed -n '1,/^\[preserve\]^/p' + while read op file + do + echo "$op"="$file" + done <"$list" + } >/tmp/sysconf.$$ + size="$(devio "<>/tmp/sysconf.$$ + # + # more cleanup, then try to write the new sysconf to $syspart + # the format is a 4 byte big-endian length then the text data + # if the data won't fit exit with error code 7 + rm "$saved" "$list" + devio -p "<>$sysdev" ' + $( $4+ # > + !! 7 + $) 0 + wb '"$size"',4 + cp $' + case $? in + 0) echo " done" >&2 + status=0;; + 1) echo " failed" >&2 + echo " $syspart could not be written (no changes made)" >&2;; + 3) echo " failed" >&2 + echo " $syspart partially written, you may want to reset it" >&2;; + 7) echo " failed" >&2 + echo " $syspart is too small: $size bytes required" >&2 + echo " No change made" >&2;; + *) echo " failed" >&2 + echo " Internal error writing $syspart" >&2;; + esac + # + rm -f /tmp/sysconf.$$ + else + echo "sysconf save: $syspart or $ffspart partition not found" >&2 + echo " A RedBoot partition named '$syspart' must exist in the system" >&2 + echo " flash memory for this command to work, and there must be a" >&2 + echo " block device to access this partition (udev will normally" >&2 + echo " create this automatically. The flash partition contents must" >&2 + echo " also be accessible in a partition called '$ffspart'" >&2 + echo + echo " To create the $syspart partition use the 'fis create' command" >&2 + echo " in the RedBoot boot loader, it is sufficient to make the" >&2 + echo " partition one erase block in size unless you have substantially" >&2 + echo " increased the size of the files listed in /etc/default/conffiles" >&2 + fi + + return $status +} + +# +# sysconf_restore [auto] +# restore previously saved configuration information from $syspart +sysconf_restore_error(){ + local root + root="$1" + shift + # ------------------------------------------------------------------------------- + { echo " WARNING: saved configuration files not restored" + test -n "$1" && echo "$*" + echo + echo "The configuration of this machine has been reinitialised using the values" + echo "from /etc/default/sysconf, however configuration files saved in the $syspart" + echo "partition have not been restored." + echo + echo "You can restore these files by correcting any reported errors then running" + echo + echo " sysconf restore" + echo + echo "from the command line. This will completely reinitialise the configuration" + echo "using the information in the $syspart partition." + } >"$root/etc/motd" + cat "$root/etc/motd" >&2 +} +# +sysconf_restore(){ + local sysdev ffsdev ffsdir saved restore size status sysconf_noninteractive config_root + + # if set this means 'do no diff' - this avoids the code above which + # would open /dev/tty and therefore allows this stuff to be done from + # an init script + sysconf_noninteractive= + test "$1" = auto && sysconf_noninteractive=1 + + ffsdev="$(mtblockdev $ffspart)" + [ -n "$ffsdev" ] || \ + ffsdev="$(mtblockdev rootfs)" + sysdev="$(mtblockdev $syspart)" + status=1 + if test -n "$sysdev" -a -b "$sysdev" -a -n "$ffsdev" -a -b "$ffsdev" && + sysconf_valid + then + # this will succeed silently if the flash device is on / + umountflash "$ffsdev" || exit 1 + # + # Everything is umounted, now remount on a temporary directory. + ffsdir="/tmp/flashdisk.$$" + config_root="$ffsdir" + mkdir "$ffsdir" || { + echo "$0: $ffsdir: failed to create temporary directory" >&2 + exit 1 + } + # + mountflash "$ffsdev" "$ffsdir" || { + rmdir "$ffsdir" + exit 1 + } + # + # first restore the $syspart section + sysconf_read "$ffsdir" || sysconf_default "$ffsdir" + # + # now use this to regenerate the system files + sysconf_reload "$ffsdir" + # + # now examine the [preserve] section, if it is there restore + # it if possible. + if test -n "$(syssection preserve)" + then + # 'saved' is a directory, 'restore' is a file (which is + # used to detect unrestored files). The directory needs + # to be populated with files. + saved=/tmp/cpio.$$ + restore=/tmp/restore.$$ + rm -rf "$saved" "$restore" + # + mkdir "$saved" || { + sysconf_restore_error "$ffsdir" "$saved: failed to create temporary directory" + umount "$ffsdir" && rmdir "$ffsdir" || + echo "$0: $ffsdir: temporary directory cleanup failed" >&2 + return 1 + } + # + # the CPIO archive is gzip compressed after the text part + # of sysconf, gzip will handle the LZ stream termination + # correctly (and break the pipe) so we don't need to know + # the real length of the data + devio "<<$sysdev" '<=b4+.' 'cp $s-' | gunzip | ( + cd "$saved" + exec cpio -i -d -m -u + ) || { + rm -rf "$saved" + sysconf_restore_error "$ffsdir" "$saved: cpio -i failed" + umount "$ffsdir" && rmdir "$ffsdir" || + echo "$0: $ffsdir: temporary directory cleanup failed" >&2 + return 1 + } + # either there must be no 'diff' files or it must + # be possible to interact with a real user. + if test -z "$sysconf_noninteractive" || + syssection preserve | sysconf_test_restore "$ffsdir" "$saved" + then + # + # remove the 'init' motd from sysconf_reload + rm "$ffsdir/etc/motd" + # + # now restore from the directory, using the information in + # the preserve section, if this fails in a non-interactive + # setting the system might not reboot + syssection preserve | + sysconf_restore_conffiles "$ffsdir" "$saved" "$restore" || { + # there is a chance of the user cleaning this up +#------------------------------------------------------------------------------ + sysconf_restore_error "$ffsdir" \ +"$0: $saved: restore of saved configuration files failed. + The flash file system is mounted on $ffsdir. + The saved files are in $saved and the list of files selected for + restore is in $restore. + You should restore any required configuration from $saved, then umount + $ffsdir and reboot." + # this prevents cleanup/umount + return 1 + } + # + # remove the copied files (i.e. the ones which were preserved) + ( cd "$saved" + exec rm $(cat "$restore") + ) + rm "$restore" + # + # clean up, files left in $saved need to be handled by the user + files="$(find "$saved" ! -type d -print)" + if test -n "$files" + then +#------------------------------------------------------------------------------ + sysconf_restore_error "$ffsdir" \ +"$0: some saved configuration files have not been handled: + +$files + +These files can be examined in $saved and restored to +$ffsdir if required. The saved files are in a temporary +directory and will not be retained across a reboot - copy then elsewhere if +you are unsure whether they are needed." + return 1 + fi + # + # so this is safe now (no files, links etc) + rm -rf "$saved" + else + rm -rf "$saved" + # non-interactive and some changed diff files + sysconf_restore_error "$ffsdir" \ +"$0: some of the saved configuration files must be +examined before restoration" + # but continue to the umount + fi + fi + # + # ignore the error in this case: + umount "$ffsdir" && rmdir "$ffsdir" || + echo "$0: $ffsdir: temporary directory cleanup failed" >&2 + status=0 + else + echo "sysconf restore: $syspart or $ffspart partition not found" >&2 + echo " You must have used 'sysconf save' to save configuration data" >&2 + echo " into the $syspart partition before using this command. The command" >&2 + echo " will restore the configuration data to the flash root partition" >&2 + echo " named '$ffspart' - this must also be accessible." >&2 + fi + + return $status +} + +# +# sysconf_help +# help text +sysconf_help(){ + # ------------------------------------------------------------------------------- + echo "sysconf: usage: sysconf read|default|reload|save|restore" >&2 + echo " read: the current $syspart partition is read into /etc/default/sysconf" >&2 + echo " default: a default /etc/default/sysconf is created" >&2 + echo " reload: system configuration files are recreated from /etc/default/sysconf" >&2 + echo " save: /etc/default/sysconf and the files listed in /etc/default/conffiles" >&2 + echo " are written to the $syspart partition" >&2 + echo " restore: the configuration information in the $syspart partition saved by" >&2 + echo " 'sysconf save' is restored" >&2 +} + +# +# the real commands +sysconf_command="$1" +test $# -gt 0 && shift +case "$sysconf_command" in +read) sysconf_read "$@";; +default)sysconf_default "$@";; +reload) sysconf_reload "$@";; +save) sysconf_save "$@";; +restore)sysconf_restore "$@";; +valid) sysconf_valid "$@";; + +sysconf)# just load the functions + ;; + +*) # help text + sysconf_help "$@";; +esac diff --git a/recipes/slugos-init/files/turnup b/recipes/slugos-init/files/turnup new file mode 100644 index 0000000000..118a57d808 --- /dev/null +++ b/recipes/slugos-init/files/turnup @@ -0,0 +1,965 @@ +#!/bin/sh +# turnup +# See the help block at the end for documentation. +# +. /etc/default/functions + +# +# configuration +# The following variables control which directories in /var end +# up on the rootfs and which end up in a temporary file system. +INRAM_MEMSTICK="\ +### SlugOS from-memory-stick boot. +d root root 0755 /var/backups none +d root root 0755 /var/volatile/cache none +l root root 0755 /var/cache /var/volatile/cache +d root root 0755 /var/lib none +d root root 2755 /var/local none +d root root 1777 /var/volatile/lock none +l root root 1777 /var/lock /var/volatile/lock +d root root 0755 /var/volatile/log none +l root root 0755 /var/log /var/volatile/log +d root root 0755 /var/volatile/run none +l root root 0755 /var/run /var/volatile/run +d root root 0755 /var/spool none +d root root 1777 /var/volatile/tmp none +l root root 1777 /var/tmp /var/volatile/tmp +d root root 0755 /var/lock/subsys none +d root root 0755 /var/lib/dropbear none +d root root 0755 /var/lib/misc none +f root root 0664 /var/log/wtmp none +f root root 0664 /var/log/lastlog none +f root root 0664 /var/run/utmp none" + +INRAM_NFS="\ +### SlugOS from-NFS boot. +d root root 0755 /var/backups none +d root root 0755 /var/volatile/cache none +l root root 0755 /var/cache /var/volatile/cache +d root root 0755 /var/lib none +d root root 2755 /var/local none +d root root 1777 /var/volatile/lock none +l root root 1777 /var/lock /var/volatile/lock +d root root 0755 /var/log none +d root root 0755 /var/volatile/run none +l root root 0755 /var/run /var/volatile/run +d root root 0755 /var/spool none +d root root 1777 /var/volatile/tmp none +l root root 1777 /var/tmp /var/volatile/tmp +d root root 0755 /var/lock/subsys none +d root root 0755 /var/lib/dropbear none +d root root 0755 /var/lib/misc none +d root root 0755 /var/lib/opkg none +f root root 0664 /var/log/wtmp none +f root root 0664 /var/log/lastlog none +f root root 0664 /var/run/utmp none" + +INRAM_DISK="\ +### SlugOS from-disk boot. +d root root 0755 /var/backups none +d root root 0755 /var/cache none +d root root 0755 /var/lib none +d root root 2755 /var/local none +d root root 1777 /var/lock none +d root root 0755 /var/log none +d root root 0755 /var/run none +d root root 0755 /var/spool none +d root root 1777 /var/tmp none +d root root 0755 /var/lock/subsys none +d root root 0755 /var/lib/dropbear none +d root root 0755 /var/lib/misc none +d root root 0755 /var/lib/opkg none +f root root 0664 /var/log/wtmp none +f root root 0664 /var/log/lastlog none +f root root 0664 /var/run/utmp none" + +INRAM_HEADER="\ +# This configuration file lists filesystem objects that should get verified +# during startup and be created if missing. +# +# Every line must either be a comment starting with # +# or a definition of format: +# +# where the items are separated by whitespace ! +# +# : d|f|l : (d)irectory|(f)ile|(l)ink +# +# A linking example: +# l root root 0777 /var/test /tmp/testfile +# f root root 0644 /var/test none +# +# Understanding links: +# When populate-volatile is to verify/create a directory or file, it will first +# check it's existence. If a link is found to exist in the place of the target, +# the path of the target is replaced with the target the link points to. +# Thus, if a link is in the place to be verified, the object will be created +# in the place the link points to instead. +# This explains the order of \"link before object\" as in the example above, where +# a link will be created at /var/test pointing to /tmp/testfile and due to this +# link the file defined as /var/test will actually be created as /tmp/testfile. +#" + +# +# force: override certain checks +force= + +# +# pfile: the uuid/partition file +pfile=/etc/uuid_by_partition + +# +# fstype new +# The type of the file system mounted on "new" Outputs the last +# piece of information found, which should be the one for the +# currently visible mount! +fstype() { + local cwd dev mp type options pass freq result + cwd="$(cd "$1"; /bin/pwd)" + result= + while read dev mp type options pass freq + do + case "$mp" in + "$cwd") result="$type";; + esac + done {mount options} +# mount the flash device, writeable, on the given directory +get_flash() { + local ffsdir ffspart ffsdev + + ffsdir="$1" + shift + test -n "$ffsdir" -a -d "$ffsdir" || { + echo "$0: $ffsdir: internal error, flash mount point not a directory" >&2 + return 1 + } + + case "$(machine)" in + nslu2) ffspart="Flashdisk";; + *) ffspart="filesystem";; + esac + ffsdev="$(mtblockdev $ffspart)" + [ -n "$ffsdev" ] || \ + ffsdev="$(mtblockdev rootfs)" + umountflash "$ffsdev" && + mountflash "$ffsdev" "$ffsdir" "$@" +} + +# +# check_rootfs [-i] +# Make sure the candidate rootfs is empty +# Environment: rootdev=device or NFS root path +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: $rootdev: partition contains existing files, specify -f to overwrite" >&2 + return 1;; + *) checkmount "$1" && return 0 + + echo "turnup: $rootdev: partition does not seem to be a valid root partition" >&2 + echo " The partition must contain a full operating system. To ensure that" >&2 + echo " this is the case it is checked for the following, all of which must" >&2 + echo " exist for the bootstrap to work:" >&2 + echo + echo " 1) A directory /mnt." >&2 + echo " 2) A command line interpreter program in /bin/sh." >&2 + echo " 3) The program chroot in /sbin or /usr/sbin." >&2 + echo " 4) The program init in /sbin, /etc or /bin." >&2 + echo + echo " One or more of these items is missing. Mount $rootdev on /mnt" >&2 + echo " and examine its contents. You can use turnup disk|nfs -i -f" >&2 + echo " to copy this operating system onto the disk, but it may overwrite" >&2 + echo " files on the disk." >&2 + 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 . -xdev -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 +# In flash file systems /dev is in ramfs, in disk systems /dev +# can be populated permanently. This is done by creating a +# single entry '.noram' in /dev - the devices init script will +# then populate the directory without overmounting it. The +# devices in the passed in device table are also created, but +# note that this is insufficient, /etc/init.d/devices must +# also run. +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 + } + echo "turnup: initialising dev file system" >&2 + # init tries to open the following devices: + # /dev/console + # /dev/tty0 + # /dev/null + # syslog, and maybe other things, only work if fd 1 is valid, therefore + # we must create these devices here... + # (if makedevs is a symlink, it's the busybox version, different syntax) + if [ -h /sbin/makedevs ] + then + makedevs -d "$2" "$1" + else + makedevs --root="$1" --devtable="$2" + fi + :>"$1"/dev/.noram + 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. + # (if makedevs is a symlink, it's the busybox version, different syntax) + if [ -h /sbin/makedevs ] + then + makedevs -d "$2" "$1" + else + makedevs -r "$1" -D "$2" + fi +} + +# +# setup_var new type +# Populates /var. +# Removes the /var tmpfs entry from /etc/fstab. +# Creates links from /var into /media/ram for NFS and Memstick. +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|memstick);; + *) echo "turnup: setup_var($1,$2): expected 'disk', 'nfs' or 'memstick'" >&2 + return 1;; + esac + + # populate /var. We just need to create the /var/volatile mount + # point, the populate-volatile script does the work at boot time. + #QUIET: echo "turnup: ensuring /var/volatile mountpoint exists" >&2 + test -d "$1"/var/volatile || mkdir "$1"/var/volatile + + # we need to put in place the correct configuration file for + # the populate-volatile script to use at boot time. The config + # file is already in place for the flash boot, and it's the same + # file for the ram boot. + case "$2" in + disk) echo "$INRAM_HEADER" > "$1"/etc/default/volatiles/00_core + echo "$INRAM_DISK" >>"$1"/etc/default/volatiles/00_core;; + nfs) echo "$INRAM_HEADER" > "$1"/etc/default/volatiles/00_core + echo "$INRAM_NFS" >>"$1"/etc/default/volatiles/00_core;; + memstick) echo "$INRAM_HEADER" > "$1"/etc/default/volatiles/00_core + echo "$INRAM_MEMSTICK" >>"$1"/etc/default/volatiles/00_core;; + esac + + # remove the /var tmpfs entry from the new /etc/fstab, if it is + # present in the first place. + sed -i '\@[ ]/var[ ][ ]*tmpfs[ ]@d' "$1"/etc/fstab + #QUIET: echo "turnup: ensuring tmpfs will not be mounted on /var" >&2 + # + 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 + #QUIET: echo "turnup: /etc/syslog.conf: changed to file buffering" >&2 + #QUIET: echo " Old (buffer) version in /etc/syslog.conf.sav" >&2 + #QUIET: 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" "$type" && + setup_syslog "$new";; + memstick) + setup_bootdev "$new" "$table" && + setup_var "$new" "$type" ;; + nfs) setup_dev "$new" "$table" && + setup_var "$new" "$type" && + setup_syslog "$new";; + *) echo "turnup: setup_rootfs: $type: unknown rootfs type" >&2 + return 1;; + esac + # return code of last setup function +} + +# +# setup_fstab new fsdev fstype fsoptions +# Alters the /etc/fstab entry for / to refer to the correct device and +# have the correct type and options. Essential for checkroot to remount +# / with the correct options. Writes the initial uuid file. +# bad, since sed won't fail even if it changes nothing. +setup_fstab() { + sed -i '\@^[^ ]*[ ][ ]*/[ ]@s@^.*$@'"$2 / $3 $4 1 1"'@' "$1"/etc/fstab + egrep -q "^$2 / $3 $4 1 1\$" "$1"/etc/fstab || { + echo "turnup: /etc/fstab: root(/) entry not changed" >&2 + echo " you probably need to check the options in /etc/fstab" >&2 + echo " to ensure that the root partition is mounted correctly" >&2 + return 1 + } + # + # build $pfile + uuid_by_partition >"$1""$pfile" || + echo "turnup: $pfile: blkid failed (ignored)" >&2 + return 0 +} + +# +# boot_rootfs ( |) [options] +# Change the flash partition (not the current root!) to boot off +# the new root file system +boot_rootfs() { + local type ffs sleep device uuid opt + + type="$1" + ffs="$2" + sleep="$3" + device="$4" + uuid= + mduuid= + + # 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 + } + uuid="$3" + if (echo "$device" | grep -q '^/dev/md') + then + # FIXME: should use awk to do the below extraction + mduuid=`mdadm --detail --brief "$device" | sed 's/^.*UUID=//'` + fi + shift 3;; + 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 'mount -t proc proc /proc' + echo 'mount -t sysfs sysfs /sys' + echo 'leds beep' + 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' + echo 'mount -t proc proc /proc' + echo 'mount -t sysfs sysfs /sys' + echo 'leds beep' + test "$sleep" -gt 0 && echo -n "sleep='$sleep' " + test -n "$uuid" && echo -n "UUID='$uuid' " + test -n "$mduuid" && echo -n "MDUUID='$mduuid' " + 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 +} + +# +# disk [-m] [-i] [-s