aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/main.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2015-11-20 21:59:54 +0000
committerIngo Schwarze <schwarze@openbsd.org>2015-11-20 21:59:54 +0000
commita121fde484ea2d14b80a55edbc89155192ed5364 (patch)
tree82f0568c203cc75ebe3f11bea8cf457f2c2ce704 /main.c
parent15be0ab8c964a27a1e5cfa3fdf7a8d5c5a94718b (diff)
downloadmandoc-a121fde484ea2d14b80a55edbc89155192ed5364.tar.gz
mandoc-a121fde484ea2d14b80a55edbc89155192ed5364.tar.zst
mandoc-a121fde484ea2d14b80a55edbc89155192ed5364.zip
Fix multiple issues regarding process group and signal mask handling
found by tb@ and millert@; parts of the code, in particular in tag.c, by millert@; OK millert@.
Diffstat (limited to 'main.c')
-rw-r--r--main.c61
1 files changed, 42 insertions, 19 deletions
diff --git a/main.c b/main.c
index ecdf4eb2..09dbfbe2 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.258 2015/11/14 23:57:47 schwarze Exp $ */
+/* $Id: main.c,v 1.259 2015/11/20 21:59:54 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -132,9 +132,9 @@ main(int argc, char *argv[])
int show_usage;
int options;
int use_pager;
- int status;
+ int status, signum;
int c;
- pid_t pager_pid;
+ pid_t pager_pid, tc_pgid, man_pgid, pid;
#if HAVE_PROGNAME
progname = getprogname();
@@ -530,11 +530,43 @@ out:
if (tag_files != NULL) {
fclose(stdout);
tag_write();
- pager_pid = spawn_pager(tag_files);
+ man_pgid = getpgid(0);
+ tag_files->tcpgid = man_pgid == getpid() ?
+ getpgid(getppid()) : man_pgid;
+ pager_pid = 0;
+ signum = SIGSTOP;
for (;;) {
- if (waitpid(pager_pid, &status, WUNTRACED) == -1) {
- if (errno == EINTR)
- continue;
+
+ /* Stop here until moved to the foreground. */
+
+ tc_pgid = tcgetpgrp(STDIN_FILENO);
+ if (tc_pgid != man_pgid) {
+ if (tc_pgid == pager_pid) {
+ (void)tcsetpgrp(STDIN_FILENO,
+ man_pgid);
+ if (signum == SIGTTIN)
+ continue;
+ } else
+ tag_files->tcpgid = tc_pgid;
+ kill(0, signum);
+ continue;
+ }
+
+ /* Once in the foreground, activate the pager. */
+
+ if (pager_pid) {
+ (void)tcsetpgrp(STDIN_FILENO, pager_pid);
+ kill(pager_pid, SIGCONT);
+ } else
+ pager_pid = spawn_pager(tag_files);
+
+ /* Wait for the pager to stop or exit. */
+
+ while ((pid = waitpid(pager_pid, &status,
+ WUNTRACED)) == -1 && errno == EINTR)
+ continue;
+
+ if (pid == -1) {
warn("wait");
rc = MANDOCLEVEL_SYSERR;
break;
@@ -542,16 +574,7 @@ out:
if (!WIFSTOPPED(status))
break;
- (void)tcsetpgrp(STDIN_FILENO, getpgid(0));
- kill(0, WSTOPSIG(status));
-
- /*
- * I'm now stopped.
- * When getting SIGCONT, continue here:
- */
-
- (void)tcsetpgrp(STDIN_FILENO, pager_pid);
- kill(pager_pid, SIGCONT);
+ signum = WSTOPSIG(status);
}
tag_unlink();
}
@@ -1046,12 +1069,12 @@ spawn_pager(struct tag_files *tag_files)
break;
default:
(void)setpgid(pager_pid, 0);
- if (tcsetpgrp(STDIN_FILENO, pager_pid) == -1)
- err((int)MANDOCLEVEL_SYSERR, "tcsetpgrp");
+ (void)tcsetpgrp(STDIN_FILENO, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
+ tag_files->pager_pid = pager_pid;
return pager_pid;
}