=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.257 retrieving revision 1.261 diff -u -p -r1.257 -r1.261 --- mandoc/main.c 2015/11/07 17:58:55 1.257 +++ mandoc/main.c 2016/01/08 02:13:39 1.261 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.257 2015/11/07 17:58:55 schwarze Exp $ */ +/* $Id: main.c,v 1.261 2016/01/08 02:13:39 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze @@ -27,6 +27,7 @@ #if HAVE_ERR #include #endif +#include #include #include #include @@ -131,7 +132,9 @@ main(int argc, char *argv[]) int show_usage; int options; int use_pager; + int status, signum; int c; + pid_t pager_pid, tc_pgid, man_pgid, pid; #if HAVE_PROGNAME progname = getprogname(); @@ -152,7 +155,7 @@ main(int argc, char *argv[]) #endif #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath proc exec flock", NULL) == -1) + if (pledge("stdio rpath tmppath tty proc exec flock", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif @@ -296,8 +299,9 @@ main(int argc, char *argv[]) use_pager = 0; #if HAVE_PLEDGE - if (!use_pager && pledge("stdio rpath flock", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (!use_pager) + if (pledge("stdio rpath flock", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif /* Parse arguments. */ @@ -427,9 +431,13 @@ main(int argc, char *argv[]) /* mandoc(1) */ #if HAVE_PLEDGE - if (pledge(use_pager ? "stdio rpath tmppath proc exec" : - "stdio rpath", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (use_pager) { + if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); + } else { + if (pledge("stdio rpath", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); + } #endif if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths)) @@ -527,7 +535,52 @@ out: if (tag_files != NULL) { fclose(stdout); tag_write(); - waitpid(spawn_pager(tag_files), NULL, 0); + man_pgid = getpgid(0); + tag_files->tcpgid = man_pgid == getpid() ? + getpgid(getppid()) : man_pgid; + pager_pid = 0; + signum = SIGSTOP; + for (;;) { + + /* 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; + } + if (!WIFSTOPPED(status)) + break; + + signum = WSTOPSIG(status); + } tag_unlink(); } @@ -671,9 +724,11 @@ parse(struct curparse *curp, int fd, const char *file) /* Begin by parsing the file itself. */ assert(file); - assert(fd >= -1); + assert(fd > 0); rctmp = mparse_readfd(curp->mp, fd, file); + if (fd != STDIN_FILENO) + close(fd); if (rc < rctmp) rc = rctmp; @@ -1016,12 +1071,17 @@ spawn_pager(struct tag_files *tag_files) case -1: err((int)MANDOCLEVEL_SYSERR, "fork"); case 0: + /* Set pgrp in both parent and child to avoid racing exec. */ + (void)setpgid(0, 0); break; default: + (void)setpgid(pager_pid, 0); + (void)tcsetpgrp(STDIN_FILENO, pager_pid); #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath", NULL) == -1) + if (pledge("stdio rpath tmppath tty proc", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif + tag_files->pager_pid = pager_pid; return pager_pid; }