On 01/18/2013 04:22 PM, Jakub Filak wrote:
- closes trac#949
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
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);
}