bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Questions to bash "read" builtin functionality (and supposed problem


From: Linus Swälas
Subject: Re: Questions to bash "read" builtin functionality (and supposed problem with while).
Date: Thu, 17 Jan 2013 15:24:14 +0100

I have a similar problem to report as Fiedler Roman regarding read and also
another problem regarding while. Maybe the while case is intended behavior
though. =)

See comments in the script below.


bash --version
GNU bash, version 4.2.39(1)-release (x86_64-redhat-linux-gnu)

Example script starts here.
#!/bin/bash -x


fifo_dir=`mktemp -d`
xl_console_input="$fifo_dir/fifo_in"
xl_console_output="$fifo_dir/fifo_out"

function domain_running
{
        local domain="$1"

        xl list "$domain" >/dev/null 2>&1
}

# I've also tried variants like:
# IFS= read -N 16384 -r -t 2 -d '' data
# which neither put anything into $data.

function poke_console
{
        local data
        local ret

        # Pole the console, see what happens.
        echo

        # Now read all data available from the console.
        while :
        do
                # Now, read from the console, with \n as delimiter.
                read -t 2 data
                ret=$?

                # Problem is here, $data is empty when read has timed
out, i.e, not
                # read a complete line. I expect data to contain the
line read so
                # far.
                echo "$data" >&2

                # If we didn't time out, there's more data available
                # that we want to flush.
                [[ $ret -gt 128 ]] || continue

                # Ok, so we've timed out, I already know that $data
doesn't contain the
                # reminder of the line, let's try getting it by
looking for another delimiter.
                # : is the delimiter we expect if we're seeing the
login prompt which should
                # be the usual case.
                read -d':' -t 1 data
                # Data is still empty here ...
                if [[ -n "$data" ]]
                then
                        [[ "$data" =~ "login" ]] && return 0
                fi

                # And this delimiter is if someone has left the
console logged in.
                read -d'#' -t 1 data
                # ... and here too.
                if [[ -n "$data" ]]
                then
                        [[ "$data" =~ 'root@' ]] && return 1
                fi

                # And data is empty on the next iteration of the loop too.

        done < "$xl_console_output"

        # Console is in an unknown state.
        return 100
}

function parse_until
{
# Cut away for brevity.
}

function remove_pipe_dir
{
        rm -r "$fifo_dir"
}

trap remove_pipe_dir TERM

# It the below also a bug?
# while can't handle nulls, this doesn't work:
# while read -d \x00 cfg
# while this does work:
# read -d \x00 test < <(find . -name some_file -print0) ; echo $test
while read cfg
do
        name=`sed -rn 's/name.*=[[:space:]]*"(.*)"/\1/p' "$cfg"`

        domain_running "$name" || continue

        mkfifo "$xl_console_input"
        mkfifo "$xl_console_output"

        xl console "${name}" < "$xl_console_input" > "$xl_console_output" &

        (
                poke_console
                case $? in
                0)
                        echo root
                        parse_until 'assword'
                        echo password
                        ;;
                1)
                        echo "\`date\` ': BAD YOU! CONSOLE WAS NOT
LOGGED OUT!' >> /root/I_will_never_again_leave_my_computer_unlocked"
                        ;;
                100)
                        echo "Can't find login prompt nor root prompt." >&2
                esac

                parse_until 'root@' '#' || exit $? # Exit if we can't login.
                echo date -u -s \""`date -u "+%Y-%m-%d %H:%M:%S.%N
UTC" -d "now"`"\"

                parse_until 'root@' '#'
                echo exit

        ) > "$xl_console_input"

        rm "$xl_console_input" "$xl_console_output"

# This doesn't work, combined with the read -r \x00 above.
#done < <(find /guests/vmname -name "xl.config" -print0)
done < <(find /guests/vmname -name "xl.config")

End of script here.

Sample output, supposed error marked in the output below:
[root@machine ~]# sync_time
++ mktemp -d
+ fifo_dir=/tmp/tmp.SbGOeR3Nk1
+ xl_console_input=/tmp/tmp.SbGOeR3Nk1/fifo_in
+ xl_console_output=/tmp/tmp.SbGOeR3Nk1/fifo_out
+ trap remove_fifo_dir TERM INT
+ read cfg
++ find /guests/vmname -name xl.config
++ sed -rn 's/name.*=[[:space:]]*"(.*)"/\1/p' /guests/vmname/xl.config
+ name=vmname
+ domain_running vmname
+ local domain=vmname
+ xl list vmname
+ mkfifo /tmp/tmp.SbGOeR3Nk1/fifo_in
+ mkfifo /tmp/tmp.SbGOeR3Nk1/fifo_out
+ xl console vmname
+ poke_console
+ local data
+ local ret
+ echo
+ :
+ read -t 2 data
+ ret=0
+ echo $'\r'

+ [[ 0 -gt 128 ]]
+ continue
+ :
+ read -t 2 data
+ ret=0
+ echo $'\r\r'

+ [[ 0 -gt 128 ]]
+ continue
+ :
+ read -t 2 data
+ ret=0
' echo 'Fedora release 17 (Beefy Miracle)
Fedora release 17 (Beefy Miracle)
+ [[ 0 -gt 128 ]]
+ continue
+ :
+ read -t 2 data
+ ret=0
' echo 'Kernel 3.6.6-1.fc17.x86_64 on an x86_64 (hvc0)
Kernel 3.6.6-1.fc17.x86_64 on an x86_64 (hvc0)
+ [[ 0 -gt 128 ]]
+ continue
+ :
+ read -t 2 data
+ ret=0
+ echo $'\r'

+ [[ 0 -gt 128 ]]
+ continue
+ :
+ read -t 2 data
+ ret=142
# The line below is the line that I consider to be an error, it's
empty and should contain
# "vmname login: "
+ echo ''

+ [[ 142 -gt 128 ]]
+ echo
+ read -N 4096 -r -d : -t 1 data
+ [[ -n '' ]]
+ echo
+ read -n 4096 -r -d '#' -t 1 data
+ [[ -n '' ]]
+ :
+ read -t 2 data
+ ret=142
+ echo ''

+ [[ 142 -gt 128 ]]
+ echo
+ read -N 4096 -r -d : -t 1 data
^C++ remove_fifo_dir
++ rm -r /tmp/tmp.SbGOeR3Nk1
++ exit

[user@machine user]$

So, did I do anything wrong or is this a bug with read? =)
I could not find anything in the man page for bash regarding while
exiting upon receiving \0. Is there any specific reason for it to exit
on \0 instead of exiting at EOF?

Regards

    /  Linus



reply via email to

[Prev in Thread] Current Thread [Next in Thread]