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); }
