aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/slugos-init/files/functions
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/slugos-init/files/functions')
-rw-r--r--recipes/slugos-init/files/functions427
1 files changed, 427 insertions, 0 deletions
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 "<</etc/init.d/sysconfsetup" prd)" -eq "$ffsno"
+ then
+ echo "$0: $ffsdev is mounted on /, use turnup ram" >&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 </proc/mounts || {
+ echo "$0: umount $ffsdev from all mount points then re-run $0" >&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'
+}