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:
+41
-40
@@ -96,15 +96,11 @@ setenv(const char *var, const char *value, bool overwrite)
|
|||||||
* execute SHELL program.
|
* 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 */
|
/* handshake interface */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int status; /* status of child */
|
int status; /* status of child */
|
||||||
char msg[256]; /* error message */
|
char msg[128]; /* error message */
|
||||||
int row; /* terminal rows */
|
int row; /* terminal rows */
|
||||||
int col; /* Terminal columns */
|
int col; /* Terminal columns */
|
||||||
} handshake_t;
|
} handshake_t;
|
||||||
@@ -118,6 +114,22 @@ typedef struct
|
|||||||
|
|
||||||
pid_t sh_pid;
|
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
|
int
|
||||||
spawn_shell(int row, int col, const char *command, const char *coding)
|
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);
|
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
|
* 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.
|
* 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) {
|
if (master < 0) {
|
||||||
printf("didn't find any available pesudo ttys.");
|
printf("didn't find any available pesudo ttys.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -169,11 +181,7 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
* on the pseudo terminal.
|
* on the pseudo terminal.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Create pipe that be use to handshake */
|
thread_id terminalThread = find_thread(NULL);
|
||||||
if (pipe(pc_pipe) || pipe(cp_pipe)) {
|
|
||||||
printf ("Could not create handshake pipe.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fork a child process. */
|
/* Fork a child process. */
|
||||||
if ((sh_pid = fork()) < 0) {
|
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.
|
* 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 */
|
/* Set process session leader */
|
||||||
if (setsid() < 0) {
|
if (setsid() < 0) {
|
||||||
handshake.status = PTY_NG;
|
handshake.status = PTY_NG;
|
||||||
sprintf(handshake.msg, "could not set session leader.");
|
snprintf(handshake.msg, sizeof(handshake.msg),
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
"could not set session leader.");
|
||||||
|
send_handshake_message(terminalThread, handshake);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +214,9 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
int slave = -1;
|
int slave = -1;
|
||||||
if ((slave = open(tty_name, O_RDWR)) < 0) {
|
if ((slave = open(tty_name, O_RDWR)) < 0) {
|
||||||
handshake.status = PTY_NG;
|
handshake.status = PTY_NG;
|
||||||
sprintf(handshake.msg, "can't open tty (%s).", tty_name);
|
snprintf(handshake.msg, sizeof(handshake.msg),
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
"can't open tty (%s).", tty_name);
|
||||||
|
send_handshake_message(terminalThread, handshake);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,8 +301,9 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
*/
|
*/
|
||||||
if (tcsetattr (0, TCSANOW, &tio) == -1) {
|
if (tcsetattr (0, TCSANOW, &tio) == -1) {
|
||||||
handshake.status = PTY_NG;
|
handshake.status = PTY_NG;
|
||||||
sprintf(handshake.msg, "failed set terminal interface (TERMIOS).");
|
snprintf(handshake.msg, sizeof(handshake.msg),
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
"failed set terminal interface (TERMIOS).");
|
||||||
|
send_handshake_message(terminalThread, handshake);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,13 +312,14 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
handshake.status = PTY_WS;
|
handshake.status = PTY_WS;
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
send_handshake_message(terminalThread, handshake);
|
||||||
read(pc_pipe[0], (char *)&handshake, sizeof (handshake));
|
receive_handshake_message(handshake);
|
||||||
|
|
||||||
if (handshake.status != PTY_WS) {
|
if (handshake.status != PTY_WS) {
|
||||||
handshake.status = PTY_NG;
|
handshake.status = PTY_NG;
|
||||||
sprintf(handshake.msg, "missmatch handshake.");
|
snprintf(handshake.msg, sizeof(handshake.msg),
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
"mismatch handshake.");
|
||||||
|
send_handshake_message(terminalThread, handshake);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,19 +336,16 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
pid_t processGroup = getpid();
|
pid_t processGroup = getpid();
|
||||||
if (setpgid(processGroup, processGroup) < 0) {
|
if (setpgid(processGroup, processGroup) < 0) {
|
||||||
handshake.status = PTY_NG;
|
handshake.status = PTY_NG;
|
||||||
sprintf(handshake.msg, "can't set process group id.");
|
snprintf(handshake.msg, sizeof(handshake.msg),
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof(handshake));
|
"can't set process group id.");
|
||||||
|
send_handshake_message(terminalThread, handshake);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
tcsetpgrp(0, processGroup);
|
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. */
|
/* pty open and set termios successful. */
|
||||||
handshake.status = PTY_OK;
|
handshake.status = PTY_OK;
|
||||||
write(cp_pipe[1], (char *)&handshake, sizeof (handshake));
|
send_handshake_message(terminalThread, handshake);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setenv TERM and TTY.
|
* 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.
|
* 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.
|
* close parent control tty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int done = 0;
|
int done = 0;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
read (cp_pipe[0], (char *)&handshake, sizeof (handshake));
|
receive_handshake_message(handshake);
|
||||||
|
|
||||||
switch (handshake.status) {
|
switch (handshake.status) {
|
||||||
case PTY_OK:
|
case PTY_OK:
|
||||||
@@ -441,7 +442,7 @@ spawn_shell(int row, int col, const char *command, const char *coding)
|
|||||||
handshake.row = row;
|
handshake.row = row;
|
||||||
handshake.col = col;
|
handshake.col = col;
|
||||||
handshake.status = PTY_WS;
|
handshake.status = PTY_WS;
|
||||||
write(pc_pipe[1], (char *)&handshake, sizeof (handshake));
|
send_handshake_message(sh_pid, handshake);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user