lkml.org 
[lkml]   [2001]   [Jan]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    SubjectRe: [PATCH] new bug report script
    Date
    On Sun, 07 Jan 2001 06:43:14 -0800, 
    David Ford <david@linux.com> wrote:
    >Matthias Juchem wrote:
    >> My script is intended for the one who likes to provide bug reports but is
    >> too lazy to look up all the information or simply is not sure about what
    >> to include.
    >
    >Why can't it be done in sh?

    In the dim, distant past I did a shell script that reads Changes,
    extracts the lines which identify software versions and verifies that
    your installed products were up to date. I sent it to Linus several
    times and got no response so I dropped it. It was last run against
    2.1.107, this is a quick and dirty upgrade against 2.4.0. A lot of the
    entries are there for historical reasons but are probably worth keeping
    for reference.

    The tricky bit with shell is handling the different output when the
    script is run as sh -x script. Use this script as a starting point if
    you like it, if not, fold spindle and mutilate it.

    --- check_linux_requirements ---

    #!/bin/bash
    #
    # Read Documentation/Changes, extract the required software levels
    # and check that the current system is up to date. Developed for
    # 2.1.107. Will not work on 2.0.x because the Documentation/Changes
    # on 2.0.x systems does not include commands, at least up to 2.0.34.
    #
    # Takes one optional parameter, the path to Documentation/Changes,
    # default is /usr/src/linux/Documentation/Changes.
    #
    # This would be a lot easier in perl but users are not required to
    # have perl to install Linux. awk was a possibility but some versions
    # of awk have been known to break on readline which I needed. So shell
    # it is.
    #
    # Keith Owens <kaos@ocs.com.au>. GPL. Sun Jun 28 21:20:10 EST 1998
    #
    # Updated for 2.4.0 Keith Owens <kaos@ocs.com.au>. Mon Jan 8 10:39:07 EST 2001
    #
    PATH=$PATH:/sbin:/bin:/usr/sbin:/usr/bin # may not have root's path

    required() {
    state=0
    confirm=0

    # NOTE: This code expects to see a line containing
    # "Current Minimal Requirements" on its own, followed by '==='
    # fillowed by each requirement on its own line starting with 'o',
    # terminated by any line starting with at least '===='.

    # Requirement lines must start with "o ".
    # The command to get the version (if any) must be preceded by '#'.
    # The version number must appear just before '#' or as the last field
    # if there is no command.

    while read line
    do
    if [ $state -eq 0 -a "$line" = "Current Minimal Requirements" ]
    then
    state=1
    fi
    if [ $state -ge 1 ]
    then
    if ( expr "$line" : "====" > /dev/null )
    then
    state=$[$state + 1]
    if [ $state -eq 3 ]
    then
    break # end of requirements
    fi
    fi
    if ( ! expr "$line" : "o" > /dev/null )
    then
    continue
    fi
    line=${line#"o "}
    set -- $line
    text=$1
    version1=
    command=
    shift
    while [ -n "$2" -a "$2" != "#" ]
    do
    text="$text $1"
    shift
    done
    version1="$1"
    shift
    if [ "$1" = "#" ]
    then
    shift
    fi
    if [ -n "$1" ]
    then
    # pppd checks for device or tty before printing version.
    # < /dev/null causes an error.
    if [ "$text" = "PPP" ]
    then
    command="$1 < /dev/ttyS0"
    else
    command="$1 < /dev/null"
    fi
    fi
    while [ -n "$2" ]
    do
    if [ "X$2" = "Xor" ]
    then
    command="$command ;"
    else
    command="$command $2"
    fi
    shift
    done
    eval "($command)" 2>&1 | \
    verify "$text" "$version1" "$command"
    if [ $? -ne 0 ]
    then
    confirm=$[$confirm + 1]
    fi
    fi
    done
    if [ $state -ne 3 ]
    then
    echo "No requirements detected, probably an old Documentation/Changes file"
    return 2
    fi
    if [ $confirm -ne 0 ]
    then
    echo "$confirm package(s) to be manually confirmed"
    return 1
    fi
    return 0
    }

    verify() {
    # Extract the version number from program output and verify it
    text="$1"
    textlc=`echo "$1" | tr '[A-Z]' '[a-z]'`
    version1="$2"
    version2=
    command="$3"
    echo "$text"
    echo -ne "\tRequired $version1"
    if [ -z "$command" ]
    then
    echo -e "\t*** No command, unable to verify ***"
    return 1
    fi

    # Amazing how many different ways there are for software to display
    # their version number. Special cases galore.

    case "$textlc" in
    modutils) type=1; field=3;;
    "gnu c") type=1; field=1;;
    "binutils") type=1; field=4;;
    "linux c library") type=2;;
    "linux libc5 c library") type=2;;
    "linux libc6 c library") type=5;;
    "dynamic linker (ld.so)") type=3;;
    "linux c++ library") type=2;;
    "pcmcia-cs") type=1; field=3;;
    "procps") type=1; field=3;;
    "procinfo") type=1; field=5;;
    "psmisc") type=1; field=5;;
    "mount") type=1; field=2;;
    "net-tools") type=1; field=2;;
    "sh-utils") type=1; field=4;;
    "autofs") type=1; field=4;;
    "nfs") type=1; field=-1;; # last field on line
    "bash") type=1; field=4;;
    "ncpfs") type=1; field=3;;
    "ppp") type=1; field=3;;
    "gnu make") type=1; field=4;;
    "util-linux") type=1; field=3;;
    "e2fsprogs") type=1; field=2;;
    "isdn4k-utils") type=1; field=-1;; # last field on line?? Needs to be tested
    *)
    echo -e "\t*** Unknown software '$textlc', unable to verify ***"
    echo " check_linux_requirements might need to be upgraded"
    return 1
    ;;
    esac

    found_version=0
    command_not_found=0
    while read line
    do
    # If running under set -x, the first line is the command
    # preceded by "++ " which confuses some tests. Ignore all
    # lines starting with "++ ".
    if [ `expr "$line" : "++ "` = 3 ]
    then
    continue
    fi
    # Treat "command not found" as warning, not error. Not everybody
    # needs every package.
    if [ `expr "$line" : "${myname}:.*: command not found\$"` -ne 0 ]
    then
    command_not_found=1
    continue
    fi
    set -- $line # tokenize
    case $type in
    1)
    # Version on the first line in a specific field,
    # possibly preceded by "some-text-".
    if [ "X$1" = "XUsage:" -o \
    `expr "$line" : '.*installed suid root'` -ne 0 -o \
    `expr "$line" : '.*invalid option'` -ne 0 ]
    then
    break # some error message instead
    fi
    if [ $field -lt 0 ]
    then
    # field -n from end of line
    field=$[$# + $field + 1]
    fi
    eval "version2=\$$field"
    prefix=`expr "$version2" : '\([a-z]*-\)*'`
    if [ -n "$prefix" ]
    then
    version2=${version2#$prefix} # strip prefix
    fi
    found_version=1
    ;;
    2)
    # libxxx versions. Take the last symbolic link,
    # extract the version number from the file it points to.
    # Special case for libc, if the link is for libc.so.6*,
    # treat the version as 6.xxx, otherwise it complains
    # that you are back level, 2.0.xx is less than 5.x.xx.
    if [ `expr "X$1" : 'Xl'` -eq 2 ]
    then
    while [ "X$2" != "X->" ]
    do
    shift
    done
    version2=`echo "$3" | tr -cd '[.0-9]' | \
    sed -e 's/\.\.*/./g' |
    sed -e 's/^\.//g' |
    sed -e 's/\.$//g'`
    if [ `expr "$1" : '.*libc.so.6'` != '0' ]
    then
    version2="6.$version2"
    fi
    fi
    ;;
    3)
    # Version on first line that starts with ldd, last
    # field on the line.
    # Two different ldd commands are issued so have to read
    # all input. Different versions of ldd have different
    # number of tokens :(.
    # Exclude error lines from old versions of ldd complaining
    # about --version.
    if [ `expr "$line" : '.*illegal option'` -ne 0 -o \
    `expr "$line" : '.*invalid option'` -ne 0 ]

    then
    continue # some error message instead
    fi
    if [ `expr "$1" : 'ldd'` -ne 0 ]
    then
    while [ -n "$2" ]
    do
    shift
    done
    version2=$1
    found_version=1
    fi
    ;;
    4)
    # Version on first line that starts with pppd, made
    # up of fields 3 and 6.
    if [ "X$1" = "Xpppd" ]
    then
    version2="$3.$6"
    found_version=1
    fi
    ;;
    5)
    # glibc versions. Take the last symbolic link,
    # extract the version number from the file it points to.
    if [ `expr "X$1" : 'Xl'` -eq 2 ]
    then
    while [ "X$2" != "X->" ]
    do
    shift
    done
    version2=`echo "$3" | tr -cd '[.0-9]' | \
    sed -e 's/\.\.*/./g' |
    sed -e 's/^\.//g' |
    sed -e 's/\.$//g'`
    fi
    ;;
    *) ;;
    esac
    if [ $found_version -eq 1 ]
    then
    break
    fi
    done
    if [ $type -eq 2 -a -n "$version2" ]
    then
    found_version=1 # take the *last* symlink
    fi
    if [ $found_version -ne 1 ]
    then
    if [ $command_not_found -eq 1 ]
    then
    echo -e "\tPackage probably not installed, ignored"
    return 0 # don't count as an error
    else
    echo -e "\t*** No version number found, cannot verify ***"
    return 1
    fi
    fi
    version2=`echo $version2 | sed -e 's:,$::'`
    echo -ne "\tActual $version2"
    if compare_version "$textlc" "$version1" "$version2"
    then
    echo -e "\tOK"
    return 0
    else
    echo -e "\t*** Possibly back level ***"
    return 1
    fi
    }

    compare_version() {
    # Amazing how many different ways there are for software to create
    # their version number. Special cases galore. Best case, convert
    # special characters such as '.', '(', ')' etc. to spaces, insert a
    # space where the version goes from letter to number or vice versa,
    # tokenize, compare the tokens as numbers or strings, as required.
    # Very, very messy!

    split_version "$1" v1 "$2"
    split_version "$1" v2 "$3"

    if [ $v1_max -lt $v2_max ]
    then
    max=$v2_max
    else
    max=$v1_max
    fi

    n=1
    while [ $n -le $max ]
    do
    eval "v1_token=\$v1_$n"
    eval "v2_token=\$v2_$n"
    if [ `expr "$v1_token" : '[0-9][0-9]*$'` != "0" ]
    then
    v1_digit=1
    else
    v1_digit=0
    fi
    if [ `expr "$v2_token" : '[0-9][0-9]*$'` != "0" ]
    then
    v2_digit=1
    else
    v2_digit=0
    fi
    if [ $v1_digit -eq 1 -a $v2_digit -eq 1 ]
    then
    # Two numeric tokens, compare as numbers. Nobody is
    # going to catch me thinking that 2.1.100 is less than
    # 2.1.99 :).
    if [ $v2_token -lt $v1_token ]
    then
    return 1 # possibly back level
    elif [ $v2_token -gt $v1_token ]
    then
    return 0 # forward level
    fi
    elif [ $v1_digit -eq 0 -a $v2_digit -eq 0 ]
    then
    # Two string tokens. It only makes sense to compare
    # them if both are one character long. Otherwise
    # assume mismatch if they are not equal.
    if [ `expr "$v1_token" : '.*'` = "1" -a \
    `expr "$v2_token" : '.*'` = "1" ]
    then
    if [ `expr "X$v2_token" "<" "X$v1_token"` -eq 1 ]
    then
    return 1 # possibly back level
    elif [ `expr "X$v2_token" ">" "X$v1_token"` -eq 1 ]
    then
    return 0 # forward level
    fi
    elif [ "X$v2_token" != "X$v1_token" ]
    then
    return 1 # possibly back level
    fi
    else
    # Mixed numeric and string tokens, although the string
    # token can be null. If the v1 token is null then
    # assume that v2 has a more recent patch level and
    # accept it, otherwise give up.
    if [ -z "$v1_token" ]
    then
    return 0 # assume v2 has a patch level
    else
    return 1 # possibly back level
    fi
    fi
    n=$[$n + 1]
    done

    return 0
    }

    split_version() {
    # Split a version number into tokens (see compare_version) and store
    # the tokens in $1_n. $1_max is the number of tokens.

    textlc=$1
    prefix=$2
    set -- `echo "$3" |
    tr '[A-Z]' '[a-z]' | tr '[]:;.(),+=-[]' ' ' |
    sed -e 's/\([a-z]\)\([0-9]\)/\1 \2/g' |
    sed -e 's/\([0-9]\)\([a-z]\)/\1 \2/g'`;

    # Special case net-tools. If there are exactly two tokens and the
    # second token is more than 2 digits, split it into two subtokens
    # after the second digit. Otherwise 1.432 is greater than 1.45.
    # Will not work after net-tools 1.99, hopefully the version number
    # problem is fixed by then.

    if [ "X$textlc" = "Xnet-tools" \
    -a -n "$2" -a -z "$3" -a \
    `expr length "$2"` -gt 2 ]
    then
    st1=`expr "$2" : '\(..\)'`
    st2=`expr "$2" : '..\(.*\)'`
    set -- "$1" "$st1" "$st2"
    fi

    n=0
    while [ -n "$1" ]
    do
    n=$[$n + 1]
    eval "${prefix}_$n=$1"
    shift
    done
    eval "${prefix}_max=$n"
    }

    changes=${1:-/usr/src/linux/Documentation/Changes}
    myname=$0

    echo "Verifying your software environment against the levels required"
    echo "in $changes."
    echo "NOTE: There are so many different ways that software can display a"
    echo " version number and they change over time. It is not guaranteed"
    echo " that this script always gets it right. Please manually check"
    echo " anything that says \"Possibly back level\". If this script is"
    echo " wrong, notify the author. Otherwise it is time to upgrade."
    echo

    # Simple, no :)?
    required < $changes
    exit $?

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 12:52    [W:0.056 / U:12.780 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site