help-bash
[Top][All Lists]
Advanced

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

[Help-bash] EOF ('\004') was lost if it's sent to bash too quickly


From: Clark Wang
Subject: [Help-bash] EOF ('\004') was lost if it's sent to bash too quickly
Date: Wed, 2 Nov 2016 00:02:13 +0800

Hi,

I'm learning about the mysterious pty things and wrote a small program (a
lot of code from the APUE book) named pty.c (attached). It works like this:

 - The main() process copies data from stdin to ptm (pty master) and from
ptm to stdout. When stdin is EOF then write '\004' to ptm.
 - The child process exec() the specified command on pts (pty slave).

The big loop function:

194 void
195 big_loop(int fd_ptym)
196 {
197     char buf[4096];
198     int nread;
199     int r, status;
200     struct timeval timeout;
201     fd_set readfds;
202     bool stdin_eof = false;
203
204     while (true) {
205         FD_ZERO(&readfds);
206         if (!stdin_eof) {
207             FD_SET(STDIN_FILENO, &readfds);
208         }
209         FD_SET(fd_ptym, &readfds);
210
211         timeout.tv_sec = 0;
212         timeout.tv_usec = 100 * 1000;
213
214         r = select(fd_ptym + 1, &readfds, NULL, NULL, &timeout);
215         if (r == 0) {
216             continue;
217         } else if (r < 0) {
218             if (errno == EINTR) {
219                 continue;
220             } else {
221                 fatal_sys("select error");
222             }
223         }
224
225         if (!stdin_eof && FD_ISSET(STDIN_FILENO, &readfds) ) {
226             nread = read(STDIN_FILENO, buf, sizeof(buf) );
227             if (nread <= 0) { /* EOF from stdin */
228                 stdin_eof = true;
229                 write(fd_ptym, "\004", 1); /* send <CTRL-D> */
230             } else {
231                 write(fd_ptym, buf, nread);
232             }
233         }
234         if (FD_ISSET(fd_ptym, &readfds) ) {
235             nread = read(fd_ptym, buf, sizeof(buf) );
236             if (nread <= 0) { /* child exited */
237                 break;
238             }
239             write(STDOUT_FILENO, buf, nread);
240         }
241     }
242
243     wait(&status);
244     if (WIFEXITED(status) ) {
245         exit(WEXITSTATUS(status) );
246     } else if (WIFSIGNALED(status) ) {
247         exit(status + 128);
248     } else {
249         exit(1);
250     }
251 }

The problem is that on Linux (Debian 8.5, x86_64) the following usage would
not exit:

# echo hello | ./pty bash --noprofile --norc
hello
bash-4.3# hello
bash: hello: command not found
bash-4.3#    <-- It blocks here.

I started gdb on the bash process and the backtrace is like this:

(gdb) bt
#0  0x00007f21fd548ba0 in __read_nocancel () at
../sysdeps/unix/syscall-template.S:81
#1  0x00000000004acbd7 in rl_getc ()
#2  0x00000000004ad4bd in rl_read_key ()
#3  0x0000000000497b50 in readline_internal_char ()
#4  0x00000000004982a5 in readline ()
#5  0x000000000042178e in ?? ()
#6  0x0000000000423abb in ?? ()
#7  0x0000000000426b7a in ?? ()
#8  0x000000000042a2e4 in yyparse ()
#9  0x00000000004210ab in parse_command ()
#10 0x0000000000421178 in read_command ()
#11 0x0000000000421359 in reader_loop ()
#12 0x000000000041fca5 in main ()

It looks to me that bash did not get the EOF (line #229). But the same code
works fine on Mac (10.11.6, EI Capitan) and on Linux it also works fine
with the cat command:

# echo hello | ./pty cat
hello
hello
#

And if I add a sleep(1) before line #229 it would also work fine with bash
on Linux.

Anyone can help what's the problem? (I'm not sure if writing '\004' to ptm
is the correct way to send EOF to the process on pts.)

Thanks.

-clark

Attachment: pty.c
Description: Text Data


reply via email to

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