From 467b8adffa13e903a5348e522c160d1f79ff8b61 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 19 Mar 2007 18:25:56 +0000 Subject: [PATCH] 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 --- src/apps/terminal/spawn.cpp | 81 +++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/src/apps/terminal/spawn.cpp b/src/apps/terminal/spawn.cpp index 21a150f202..b7bc1a9738 100644 --- a/src/apps/terminal/spawn.cpp +++ b/src/apps/terminal/spawn.cpp @@ -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; } }