On 01/18/2013 04:22 PM, Jakub Filak wrote:
> - closes trac#949
> 
> Signed-off-by: Jakub Filak <[email protected]>

Looks good, how about this slightly tweaked version?

diff -urpN libreport.9/src/cli/run-command.c libreport.b/src/cli/run-command.c
--- libreport.9/src/cli/run-command.c   2013-01-10 14:18:05.000000000 +0100
+++ libreport.b/src/cli/run-command.c   2013-01-18 17:25:17.629369267 +0100
@@ -23,40 +23,102 @@
   http://git.kernel.org/?p=git/git.git;a=blob;f=run-command.c;hb=HEAD
 */

-static pid_t start_command(char **argv)
+struct command {
+    char **argv;
+    pid_t pid;
+    int tty_fd;
+    pid_t bck_tcgrp;            //<< old foreground process group
+    struct termios bck_tmodes;  //<< old configuration
+};
+
+static void start_command(struct command *cmd)
 {
+  cmd->tty_fd = open("/dev/tty", O_RDWR);
+  if (cmd->tty_fd < 0)
+    /* do we want to die if we're in a script and have no controlling tty?
+     *
+     * YES, they can always call 'report-cli -y' from script and it should
+     * not try to open an editor
+     */
+    perror_msg_and_die("open(\"/dev/tty\", O_RDWR)");
+
+  /* save current foreground process group id */
+  cmd->bck_tcgrp = tcgetpgrp(cmd->tty_fd);
+  if (cmd->bck_tcgrp < 0)
+    perror_msg_and_die("tcgetpgrp()");
+
+  /* save tty's attrs */
+  if (tcgetattr(cmd->tty_fd, &cmd->bck_tmodes) < 0)
+    perror_msg_and_die("tcsetattr()");
+
   fflush(NULL);

-  pid_t pid = vfork();
-  if (pid < 0)
+  cmd->pid = vfork();
+  if (cmd->pid < 0)
   {
     perror_msg_and_die("vfork");
   }
-  if (pid == 0)
+  if (cmd->pid == 0)
   {
     /* Child */
-    execvp(argv[0], argv);
+
+    xmove_fd(cmd->tty_fd, 0);
+    xdup2(cmd->tty_fd, 1);
+    xdup2(cmd->tty_fd, 2);
+
+    /* tcsetpgrp() below will send us SIGTTOU if we aren't
+     * foreground process group. Need to ignore it */
+    signal(SIGTTOU, SIG_IGN);
+
+    /* sends SIGTTOU to process group */
+    pid_t pgrp = getpgrp();
+    if (pgrp < 0) {
+      perror_msg("getpgrp()");
+      _exit(127);
+    }
+    if (tcsetpgrp(cmd->tty_fd, pgrp) < 0) {
+      perror_msg("tcsetpgrp()");
+      _exit(127);
+    }
+
+    signal(SIGTTOU, SIG_DFL);
+
+    execvp(cmd->argv[0], cmd->argv);
     /* Better to use _exit (not exit) after vfork:
      * we don't want to mess up parent's memory state
      * by running libc cleanup routines.
      */
     _exit(127);
   }
-  return pid;
 }

-static int finish_command(pid_t pid, char **argv)
+static int finish_command(struct command *cmd)
 {
   int status;
-  pid_t waiting = safe_waitpid(pid, &status, 0);
+  pid_t waiting = safe_waitpid(cmd->pid, &status, 0);
   if (waiting < 0)
     perror_msg_and_die("waitpid");

+  /* tcsetpgrp() below will send us SIGTTOU if we aren't
+   * foreground process group. Need to ignore it */
+  sighandler_t old = signal(SIGTTOU, SIG_IGN);
+
+  /* reset foreground process group */
+  if (tcsetpgrp(cmd->tty_fd, cmd->bck_tcgrp) < 0)
+      perror_msg_and_die("tcsetpgrp()");
+  /* restore old tty attrs (not really needed, but just in case editor mangled 
them) */
+  if (tcsetattr(cmd->tty_fd, TCSADRAIN, &(cmd->bck_tmodes)) < 0)
+      perror_msg_and_die("tcsetattr()");
+
+  signal(SIGTTOU, old);
+
+  close(cmd->tty_fd);
+
   int code;
   if (WIFSIGNALED(status))
   {
     code = WTERMSIG(status);
-    error_msg("'%s' killed by signal %d", argv[0], code);
+    error_msg("'%s' killed by signal %d", cmd->argv[0], code);
     code += 128; /* shells use this convention for deaths by signal */
   }
   else /* if (WIFEXITED(status)) */
@@ -64,7 +126,7 @@ static int finish_command(pid_t pid, cha
     code = WEXITSTATUS(status);
     if (code == 127)
     {
-      error_msg_and_die("Can't run '%s'", argv[0]);
+      error_msg_and_die("Can't run '%s'", cmd->argv[0]);
     }
   }

@@ -73,6 +135,7 @@ static int finish_command(pid_t pid, cha

 int run_command(char **argv)
 {
-  pid_t pid = start_command(argv);
-  return finish_command(pid, argv);
+  struct command cmd = { argv, 0 };
+  start_command(&cmd);
+  return finish_command(&cmd);
 }

Reply via email to