#!/bin/sh # $Id$ # # Written by Alexander Kriegisch (user 'kriegaex', ip-phone-forum.de) # # Handle boot loader environment 'kernel_args' variables which can either have # an integer value >= 1 or values of 'y'|'n'. # # General information # - Setting the environment variable KERNEL_ARGS_READ_PROC != "" activates # reading variable values from /proc/sys/urlader/environment, even though # this might seem more complicated than necessary, because key-value pairs # like FooBar=bla can easily be taken from the shell environment during # the system init process. The author wants to provide a way to read/write # those variables later, too, i.e. outside the init process when they have # already vanished from the environment. # - Setting the environment variable KERNEL_ARGS_VERBOSE != "" activates # somewhat more verbose output on stdout and error messages on stderr. # - So as not make things more complicated than necessary, the author # assumes that variables exist only once within 'kernel_args' when # determining values: no doubles like 'foo=y bar=n foo=n'. When updating # values, though, multiple possibly existing key-value pairs for one # variable name are deleted before the new value is appended to the end of # 'kernel_args'. # Caveat # - The maximum string length of 'kernel_args' is 64 characters! ka_mountProc() { # Description # Mount /proc, if necessary. If a mount was necessary AND successful, # write "y" to stdout, otherwise write nothing (except possible errors # in verbose mode). # Parameters # none # Return value # 0, if /proc was already mounted and boot loader environment exists. # 1, if /proc was not mounted before, has just been mounted successfully # and boot loader environment exists. This return values is important # for procedures which want to unmount a temporarily mounted /proc. # 99 on error (failed mount or non-existent boot loader environment). if [ ! -e /proc/mounts ]; then local no_proc=y mount proc fi if [ ! -e /proc/sys/urlader/environment ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_mountProc - error: cannot access /proc/sys/urlader/environment" >&2 return 99 fi if [ "$no_proc" ]; then echo "y" return 1 fi return 0 } ka_getArgs() { # Description # Read 'kernel_args' directly from boot loader environment and print # value to stdout. # Parameters # none # Return value # 0, if value was read successfully. # 1 on error (boot loader environment inaccessible). local no_proc=$(ka_mountProc) if [ "$?" == "99" ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_getArgs - error: cannot access /proc/sys/urlader/environment" >&2 return 99 fi cat /proc/sys/urlader/environment | sed -nr 's/^kernel_args[[:space:]]+(.*)/\1/p' [ "$no_proc" ] && umount proc return 0 } ka_isValidName() { # Description # Check if variable name is C-style (alphanumeric + '_') # Parameters # $1 - variable name # Return value # 0 (true), if variable name is C-style. # 1 (false), if it is not. # 99 on error. if [ -z "$1" ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_isValidName - error: no variable name specified" >&2 return 99 fi var=$(echo "$1" | sed -nr 's/^(\w+)$/\1/p') if [ "$1" != "$var" ]; then return 1 fi return 0 } ka_isValidValue() { # Description # Verify a value's validity # Parameters # $1 - value to be verified # Return value # 0 (true), if value is an integer >= 1 or one of 'y|n' (case-sensitive). # 1 (false), if it is not. # 99 on error. if [ -z "$1" ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_isValidValue - error: no value specified" >&2 return 99 fi val=$(echo "$1" | sed -nr 's/^([yn]|([0-9]+))$/\1/p') if [ -z "$val" -o "$val" = "0" ]; then return 1 fi return 0 } ka_getKeyValuePair() { # Description # Check if variable + value exist in boot loader 'kernel_args' and print # the key-value pair (e.g. "MyVariable=12") to stdout # Parameters # $1 - variable name # Return value # 0 (true), if a valid key-value pair exists for the variable. # 1 (false), if the variable name is valid, but not part of a key-value # pair. # 99 on error (invalid name or value). if ! ka_isValidName "$1"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_getKeyValuePair - error: invalid variable name \"$1\"" >&2 return 99 fi kv_pair=$(ka_getArgs | sed -nr "s/.*\b($1=\w*)\b.*/\1/p") if [ -z "$kv_pair" ]; then return 1 fi if ! ka_isValidValue $(echo "$kv_pair" | sed -r "s/$1=//"); then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_getKeyValuePair - error: invalid value" >&2 return 99 fi echo "$kv_pair" return 0 } ka_getValue() { # Description # Write value of specified variable to stdout. By default, the value is # retrieved from the shell environment, assuming we are withing the init # process. If KERNEL_ARGS_READ_PROC != "", the value is retrieved # directly from the boot loader environment, though. # Caveat: # If KERNEL_ARGS_READ_PROC == "" or undefined and you happend to have a # variable in your current environment which conforms to both # ka_isValidName and ka_isValidValue, this variable's value will be # retrieved even if it did not come from kernel_args. # Parameters # $1 - variable name # Return value # 0 (true), if variable exists and has a valid value according to # ka_verifyValue. # 99 on error (key-value pair not found or invalid value). if [ -z "$KERNEL_ARGS_READ_PROC" ]; then # Tricky & ugly nested expansion (not directly supported by ash) val=$(eval echo $(echo "\$$1")) else if ! kv_pair=$(ka_getKeyValuePair "$1"); then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_getValue - error: found no valid key-value pair for variable \"$1\"" >&2 return 99 fi val=$(echo "$kv_pair" | sed -r "s/$1=//") fi if ! ka_isValidValue "$val"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_getValue - error: found invalid value \"$val\" for variable \"$1\"" >&2 return 99 fi echo "$val" return 0 } ka_setValue() { # Description # Set variable to specified value. # The new kernel_args value list is subsequently printed to stdout. # Parameters # $1 - variable name # $2 - value (must be 'y', 'n' or integer >= 1) # Return value # 0 (true), if value is valid as required by ka_verifyValue and was set # successfully. If variable does not exist in environment, it will be # created automatically. # 99 on error (invalid variable name or value). if ! ka_isValidName "$1"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_setValue - error: invalid variable name \"$1\"" >&2 return 99 fi if ! ka_isValidValue "$2"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_setValue - error: invalid value \"$2\" for variable \"$1\"" >&2 return 99 fi new_args=$(ka_removeVariableNoUpdate "$1") new_args="$new_args $1=$2" if [ "$?" == "99" ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_setValue - error: cannot access /proc/sys/urlader/environment" >&2 return 99 fi echo "kernel_args $new_args" > /proc/sys/urlader/environment [ "$KERNEL_ARGS_VERBOSE" ] && \ ka_getArgs [ "$no_proc" ] && umount proc return 0 } ka_removeVariable() { # Description # Remove variable from environment by deleting it from 'kernel_args', # even multiple occurrences of key-value pairs with the same variable # name and/or with invalid values. Stand-alone variables without values # will also be eliminated. For example, 'kernel_args' list # 'foo=1 bar foo=y foo zot=234 foo=bla' will be stripped down to # 'bar zot=234' upon the calling 'ka_removeVariable foo'. # The new kernel_args value list is subsequently printed to stdout. # Parameters # $1 - variable name to be stripped from 'kernel_args' # Return value # 0, if variable with a valid name according to ka_isValidName was # removed successfully or did not exist anyway. # Otherwise, a non-zero value will be returned. if ! new_args=$(ka_removeVariableNoUpdate "$1"); then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_removeVariable - error: cannot remove variable \"$1\"" >&2 return 1 fi if [ "$?" == "99" ]; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_removeVariable - error: cannot access /proc/sys/urlader/environment" >&2 return 99 fi echo "kernel_args $new_args" > /proc/sys/urlader/environment [ "$KERNEL_ARGS_VERBOSE" ] && \ ka_getArgs [ "$no_proc" ] && umount proc return 0 } ka_removeVariableNoUpdate() { # Description # Do basically the same as ka_removeVariable, but do not update # 'kernel_args'. Instead, print hypothetical new value of 'kernel_args' # to stdout, i.e. the value as it would look like after removing all # occurrences of the specified variable. # Actually, this function is used as a helper by ka_removeVariable. # Parameters # $1 - variable name to be stripped from 'kernel_args' # Return value # 0 (true), if variable with a valid name according to ka_isValidName # was removed successfully or did not exist anyway. # 99 on error (invalid variable name). if ! ka_isValidName "$1"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_removeVariableNoUpdate - error: invalid variable name \"$1\"" >&2 return 99 fi new_args=$(\ ka_getArgs \ | sed -r "s/\b($1\b(=\w*)?)\b//g" \ | sed -r 's/[[:space:]]+/ /g' \ | sed -r 's/^[[:space:]](.*)/\1/' \ | sed -r 's/(.*)[[:space:]]$/\1/'\ ) echo "$new_args" return 0 } ka_isPositiveInteger() { # Description # Check if specified variable's value is an integer >= 1 # Parameters # $1 - value to be checked # Return value # 0 (true), if value is an integer >= 1. # 1 (false), if value is valid, but no integer >= 1 # 99 on error (invalid value). if ! ka_isValidValue "$1"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_isPositiveInteger - error: invalid value \"$1\"" >&2 return 99 fi if [ "$1" = "y" ] || [ "$1" = "n" ] || [ "$1" -le 0 ]; then return 1 fi return 0 } ka_isActiveVariable() { # Description # Check if specified variable's value exists, is valid and != 'n' # (i.e. 'y' or an integer >= 1) # Parameters # $1 - variable to be checked # Return value # 0 (true), if variable is either always on ('y') or has a count >= 1. # 1 (false), if value is 'n'. # 99 on error. if ! val=$(ka_getValue "$1"); then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_isActiveVariable - error: could not determine value of variable \"$1\"" >&2 return 99 fi if [ "$val" = "n" ]; then return 1 fi return 0 } ka_decreaseValue() { # Description # Decrease numeric variable value by 1. # The new kernel_args value list is subsequently printed to stdout. # Parameters # $1 - variable name whose value is to be decreased # Return value # 0 (true), if value was updated successfully or was left unchanged # (non-numeric). Any integer value > 1 will be decreased by 1. The # value 1 will be turned into 'n' (instead of zero), thus effectively # decativating the variable. Non-numeric values will be left untouched, # not yielding an error as long as they are valid (i.e. equal to 'y|n'). # 99 on error (invalid or non-existent current value or error during # update to new value). local KERNEL_ARGS_READ_PROC=1 if ! val=$(ka_getValue "$1"); then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_decreaseValue - error: could not determine value of variable \"$1\"" >&2 return 99 fi unset KERNEL_ARGS_READ_PROC if ! ka_isPositiveInteger "$val" 2>/dev/null; then [ "$KERNEL_ARGS_VERBOSE" ] && \ ka_getArgs return 0 fi old_val="$val" [ $((--val > 0)) == 0 ] && val="n"; if [ "$val" != "$old_val" ] && ! ka_setValue "$1" "$val"; then [ "$KERNEL_ARGS_VERBOSE" ] && \ echo "ka_decreaseValue - error: could not update variable \"$1\" with value \"$val\"" >&2 return 99 fi # Do not call ka_getArgs here, because ka_setValue already prints the new # value of kernel_args in verbose mode return 0 }