summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2015-11-20 21:58:33 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2015-11-20 21:58:33 +0000
commit39cb6b842f6368ad6c5ff10eb2200322becbcc65 (patch)
treecd95dc4d6e5ea530a86abc239ea8bdf522de3939 /usr.bin
parent19a19bedbc8cec5fad85329175916ed22ad0facd (diff)
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 'usr.bin')
-rw-r--r--usr.bin/mandoc/main.c61
-rw-r--r--usr.bin/mandoc/tag.c29
-rw-r--r--usr.bin/mandoc/tag.h4
3 files changed, 68 insertions, 26 deletions
diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c
index b9d4b3fafa6..37572a1c2ae 100644
--- a/usr.bin/mandoc/main.c
+++ b/usr.bin/mandoc/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.165 2015/11/14 23:56:41 schwarze Exp $ */
+/* $OpenBSD: main.c,v 1.166 2015/11/20 21:58:32 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -121,9 +121,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;
progname = getprogname();
if (strncmp(progname, "mandocdb", 8) == 0 ||
@@ -487,11 +487,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;
@@ -499,16 +531,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();
}
@@ -1001,10 +1024,10 @@ 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 (pledge("stdio rpath tmppath tty proc", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
+ tag_files->pager_pid = pager_pid;
return pager_pid;
}
diff --git a/usr.bin/mandoc/tag.c b/usr.bin/mandoc/tag.c
index 46c5406b384..0c20f154c81 100644
--- a/usr.bin/mandoc/tag.c
+++ b/usr.bin/mandoc/tag.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tag.c,v 1.10 2015/10/13 15:50:15 schwarze Exp $ */
+/* $OpenBSD: tag.c,v 1.11 2015/11/20 21:58:32 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -48,10 +48,12 @@ static struct tag_files tag_files;
struct tag_files *
tag_init(void)
{
+ struct sigaction sa;
int ofd;
ofd = -1;
tag_files.tfd = -1;
+ tag_files.tcpgid = -1;
/* Save the original standard output for use by the pager. */
@@ -64,9 +66,12 @@ tag_init(void)
sizeof(tag_files.ofn));
(void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
sizeof(tag_files.tfn));
- signal(SIGHUP, tag_signal);
- signal(SIGINT, tag_signal);
- signal(SIGTERM, tag_signal);
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = tag_signal;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
if ((ofd = mkstemp(tag_files.ofn)) == -1)
goto fail;
if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
@@ -154,7 +159,15 @@ tag_write(void)
void
tag_unlink(void)
{
-
+ pid_t tc_pgid;
+
+ if (tag_files.tcpgid != -1) {
+ tc_pgid = tcgetpgrp(STDIN_FILENO);
+ if (tc_pgid == tag_files.pager_pid ||
+ tc_pgid == getpgid(0) ||
+ getpgid(tc_pgid) == -1)
+ (void)tcsetpgrp(STDIN_FILENO, tag_files.tcpgid);
+ }
if (*tag_files.ofn != '\0')
unlink(tag_files.ofn);
if (*tag_files.tfn != '\0')
@@ -164,9 +177,13 @@ tag_unlink(void)
static void
tag_signal(int signum)
{
+ struct sigaction sa;
tag_unlink();
- signal(signum, SIG_DFL);
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sigaction(signum, &sa, NULL);
kill(getpid(), signum);
/* NOTREACHED */
_exit(1);
diff --git a/usr.bin/mandoc/tag.h b/usr.bin/mandoc/tag.h
index 46d6032b172..c646b64097d 100644
--- a/usr.bin/mandoc/tag.h
+++ b/usr.bin/mandoc/tag.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tag.h,v 1.6 2015/11/07 13:57:55 schwarze Exp $ */
+/* $OpenBSD: tag.h,v 1.7 2015/11/20 21:58:32 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -20,6 +20,8 @@ struct tag_files {
char tfn[20];
int ofd;
int tfd;
+ pid_t tcpgid;
+ pid_t pager_pid;
};