#!/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' }