diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2015-11-20 21:58:33 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2015-11-20 21:58:33 +0000 |
commit | 39cb6b842f6368ad6c5ff10eb2200322becbcc65 (patch) | |
tree | cd95dc4d6e5ea530a86abc239ea8bdf522de3939 /usr.bin | |
parent | 19a19bedbc8cec5fad85329175916ed22ad0facd (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.c | 61 | ||||
-rw-r--r-- | usr.bin/mandoc/tag.c | 29 | ||||
-rw-r--r-- | usr.bin/mandoc/tag.h | 4 |
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; }; |