Why expect makes process open it's STDERR?

2019-05-28 14:55发布

问题:

I want to set timeout for a process, this is my shell. I use expect to do it, in order to avoid other packages dependencies.

test.sh

#!/bin/bash
# $1 timeout in seconds
# $2 command
timeout() {
        time=$1
        shift
        # start the command in a subshell to avoid problem with pipes
        # (spawn accepts one command)                            -noecho 
        command="/bin/sh -c \"$*\""
        expect -c "set echo \"-noecho\";set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"
        if [ $? = 1 ] ; then
            echo "timeout after ${time} seconds"
            exit 1
        fi

}

timeout 120 ./test

test.c

#include <stdlib.h>
int main() {
    sleep(120);
}

And I run a program to fork&exec shell, and I use pipe to catch the shell output.

But I found the facts:

I find shell dup parent pipe to STDOUT, STDERR, this works fine.

lrwx------ 1 root root 64 Sep 13 17:07 0 -> /dev/pts/1
l-wx------ 1 root root 64 Sep 13 17:07 1 -> pipe:[14070157]
l-wx------ 1 root root 64 Sep 13 17:07 2 -> pipe:[14070158]
lr-x------ 1 root root 64 Sep 13 17:07 255 -> /path/to/my/shell

This is expect, it inherits parent (my shell) pipes, and opens 14070167 pipe to catch sleeping program test.c (I guess it pipes child's STDOUT).

lrwx------ 1 root root 64 Sep 13 17:08 0 -> /dev/pts/1
l-wx------ 1 root root 64 Sep 13 17:08 1 -> pipe:[14070157]
l-wx------ 1 root root 64 Sep 13 17:07 2 -> pipe:[14070158]
lr-x------ 1 root root 64 Sep 13 17:08 3 -> pipe:[14070167]
l-wx------ 1 root root 64 Sep 13 17:08 4 -> pipe:[14070167]
lrwx------ 1 root root 64 Sep 13 17:08 5 -> /dev/tty
lrwx------ 1 root root 64 Sep 13 17:08 6 -> /dev/ptmx

But what makes me confused is that test.c does not dup 1 to pipe[140167]. Until now it works fine. ( while, this is not the point causing problem)

But I have a BUG, if the test.c is a daemon program, it gets fd 5 which is pipe 14070158, (this is test.sh STDERR dupped before). And after expect exits. If I poll STDERR for the test.sh, it will block, because the sender port is a daemon program. ( assuming test.c is that daemon program).

lrwx------ 1 root root 64 Sep 13 17:07 0 -> /dev/pts/2
lrwx------ 1 root root 64 Sep 13 17:07 1 -> /dev/pts/2
lrwx------ 1 root root 64 Sep 13 17:07 2 -> /dev/pts/2
lr-x------ 1 root root 64 Sep 13 17:07 3 -> pipe:[14070167]
l-wx------ 1 root root 64 Sep 13 17:07 4 -> pipe:[14070167]
l-wx------ 1 root root 64 Sep 13 17:07 5 -> pipe:[14070158]

My question is how does expect work? Can I let it not give the pipe [14070158] to test.c so that I can fix my BUG?

My expect version is 5.43