For some reason a Terminal started by Tracker or Deskbar does not have a

valid stderr. Thus one of the FDs for the pipes created for the initial
handshake with the fork()ed child process exec()ing the shell would have
number 2 and would be closed when the child process set up the
stdin/out/err environment for the shell, leading to the child and the
parent being killed by a SIGPIPE when they tried to access the pipes.

This change replaces the pipes mechanism by one using send/receive_data(),
which is probably even faster. I also reduced the handshake_t::msg field
to 128 bytes and replaced the sprintf()s writing to it by snprintf()s.

Fixes bug #627. Although they looked related, bugs #113 and #928 still
persist.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20393 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-03-19 18:25:56 +00:00
parent a38ee20f99
commit 467b8adffa

View File

@ -96,15 +96,11 @@ setenv(const char *var, const char *value, bool overwrite)
* execute SHELL program.
*/
/* This pipe use handshake on exec. */
int pc_pipe[2]; /* this pipe is used for parent to child transfer */
int cp_pipe[2]; /* this pipe is used for child to parent transfer */
/* handshake interface */
typedef struct
{
int status; /* status of child */
char msg[256]; /* error message */
char msg[128]; /* error message */
int row; /* terminal rows */
int col; /* Terminal columns */
} handshake_t;
@ -118,6 +114,22 @@ typedef struct
pid_t sh_pid;
static status_t
send_handshake_message(thread_id target, const handshake_t& handshake)
{
return send_data(target, 0, &handshake, sizeof(handshake_t));
}
static void
receive_handshake_message(handshake_t& handshake)
{
thread_id sender;
receive_data(&sender, &handshake, sizeof(handshake_t));
}
int
spawn_shell(int row, int col, const char *command, const char *coding)
{
@ -128,7 +140,7 @@ spawn_shell(int row, int col, const char *command, const char *coding)
signal(SIGTTOU, SIG_IGN);
/*
* Get a psuedo-tty. We do this by cycling through files in the
* Get a pseudo-tty. We do this by cycling through files in the
* directory. The oparationg system will not allow us to open a master
* which is already in use, so we simply go until the open succeeds.
*/
@ -160,8 +172,8 @@ spawn_shell(int row, int col, const char *command, const char *coding)
}
if (master < 0) {
printf("didn't find any available pesudo ttys.");
return -1;
printf("didn't find any available pesudo ttys.");
return -1;
}
/*
@ -169,11 +181,7 @@ spawn_shell(int row, int col, const char *command, const char *coding)
* on the pseudo terminal.
*/
/* Create pipe that be use to handshake */
if (pipe(pc_pipe) || pipe(cp_pipe)) {
printf ("Could not create handshake pipe.");
return -1;
}
thread_id terminalThread = find_thread(NULL);
/* Fork a child process. */
if ((sh_pid = fork()) < 0) {
@ -189,15 +197,12 @@ spawn_shell(int row, int col, const char *command, const char *coding)
* we cleared our original controlling terminal above.
*/
// ToDo: why two of them in the first place?
close(cp_pipe[0]);
close(pc_pipe[1]);
/* Set process session leader */
if (setsid() < 0) {
handshake.status = PTY_NG;
sprintf(handshake.msg, "could not set session leader.");
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
snprintf(handshake.msg, sizeof(handshake.msg),
"could not set session leader.");
send_handshake_message(terminalThread, handshake);
exit(1);
}
@ -209,8 +214,9 @@ spawn_shell(int row, int col, const char *command, const char *coding)
int slave = -1;
if ((slave = open(tty_name, O_RDWR)) < 0) {
handshake.status = PTY_NG;
sprintf(handshake.msg, "can't open tty (%s).", tty_name);
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
snprintf(handshake.msg, sizeof(handshake.msg),
"can't open tty (%s).", tty_name);
send_handshake_message(terminalThread, handshake);
exit(1);
}
@ -295,8 +301,9 @@ spawn_shell(int row, int col, const char *command, const char *coding)
*/
if (tcsetattr (0, TCSANOW, &tio) == -1) {
handshake.status = PTY_NG;
sprintf(handshake.msg, "failed set terminal interface (TERMIOS).");
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
snprintf(handshake.msg, sizeof(handshake.msg),
"failed set terminal interface (TERMIOS).");
send_handshake_message(terminalThread, handshake);
exit(1);
}
@ -305,13 +312,14 @@ spawn_shell(int row, int col, const char *command, const char *coding)
*/
handshake.status = PTY_WS;
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
read(pc_pipe[0], (char *)&handshake, sizeof (handshake));
send_handshake_message(terminalThread, handshake);
receive_handshake_message(handshake);
if (handshake.status != PTY_WS) {
handshake.status = PTY_NG;
sprintf(handshake.msg, "missmatch handshake.");
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
snprintf(handshake.msg, sizeof(handshake.msg),
"mismatch handshake.");
send_handshake_message(terminalThread, handshake);
exit(1);
}
@ -328,19 +336,16 @@ spawn_shell(int row, int col, const char *command, const char *coding)
pid_t processGroup = getpid();
if (setpgid(processGroup, processGroup) < 0) {
handshake.status = PTY_NG;
sprintf(handshake.msg, "can't set process group id.");
write(cp_pipe[1], (char *)&handshake, sizeof(handshake));
snprintf(handshake.msg, sizeof(handshake.msg),
"can't set process group id.");
send_handshake_message(terminalThread, handshake);
exit(1);
}
tcsetpgrp(0, processGroup);
/* mark the pipes as close on exec */
fcntl(cp_pipe[1], F_SETFD, FD_CLOEXEC);
fcntl(pc_pipe[0], F_SETFD, FD_CLOEXEC);
/* pty open and set termios successful. */
handshake.status = PTY_OK;
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
send_handshake_message(terminalThread, handshake);
/*
* setenv TERM and TTY.
@ -415,17 +420,13 @@ spawn_shell(int row, int col, const char *command, const char *coding)
* that they can write and read the pseudo terminal.
*/
/* close childs's side of the pipe */
close(cp_pipe[1]);
close(pc_pipe[0]);
/*
* close parent control tty.
*/
int done = 0;
while (!done) {
read (cp_pipe[0], (char *)&handshake, sizeof (handshake));
receive_handshake_message(handshake);
switch (handshake.status) {
case PTY_OK:
@ -441,7 +442,7 @@ spawn_shell(int row, int col, const char *command, const char *coding)
handshake.row = row;
handshake.col = col;
handshake.status = PTY_WS;
write(pc_pipe[1], (char *)&handshake, sizeof (handshake));
send_handshake_message(sh_pid, handshake);
break;
}
}