=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.254 retrieving revision 1.260 diff -u -p -r1.254 -r1.260 --- mandoc/main.c 2015/11/06 16:30:33 1.254 +++ mandoc/main.c 2015/12/15 17:38:45 1.260 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.254 2015/11/06 16:30:33 schwarze Exp $ */ +/* $Id: main.c,v 1.260 2015/12/15 17:38:45 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze @@ -24,7 +24,10 @@ #include #include +#if HAVE_ERR #include +#endif +#include #include #include #include @@ -129,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(); @@ -149,6 +154,11 @@ main(int argc, char *argv[]) return mandocdb(argc, argv); #endif +#if HAVE_PLEDGE + if (pledge("stdio rpath tmppath tty proc exec flock", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); +#endif + /* Search options. */ memset(&conf, 0, sizeof(conf)); @@ -288,6 +298,12 @@ main(int argc, char *argv[]) !isatty(STDOUT_FILENO)) use_pager = 0; +#if HAVE_PLEDGE + if (!use_pager) + if (pledge("stdio rpath flock", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); +#endif + /* Parse arguments. */ if (argc > 0) { @@ -414,6 +430,16 @@ main(int argc, char *argv[]) /* mandoc(1) */ +#if HAVE_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)) return (int)MANDOCLEVEL_BADARG; @@ -509,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(); } @@ -756,12 +827,12 @@ passthrough(const char *file, int fd, int synopsis_onl FILE *stream; const char *syscall; - char *line; - size_t len, off; - ssize_t nw; + char *line, *cp; + size_t linesz; int print; - fflush(stdout); + line = NULL; + linesz = 0; if ((stream = fdopen(fd, "r")) == NULL) { close(fd); @@ -770,45 +841,41 @@ passthrough(const char *file, int fd, int synopsis_onl } print = 0; - while ((line = fgetln(stream, &len)) != NULL) { + while (getline(&line, &linesz, stream) != -1) { + cp = line; if (synopsis_only) { if (print) { - if ( ! isspace((unsigned char)*line)) + if ( ! isspace((unsigned char)*cp)) goto done; - while (len && - isspace((unsigned char)*line)) { - line++; - len--; - } + while (isspace((unsigned char)*cp)) + cp++; } else { - if ((len == sizeof(synb) && - ! strncmp(line, synb, len - 1)) || - (len == sizeof(synr) && - ! strncmp(line, synr, len - 1))) + if (strcmp(cp, synb) == 0 || + strcmp(cp, synr) == 0) print = 1; continue; } } - for (off = 0; off < len; off += nw) - if ((nw = write(STDOUT_FILENO, line + off, - len - off)) == -1 || nw == 0) { - fclose(stream); - syscall = "write"; - goto fail; - } + if (fputs(cp, stdout)) { + fclose(stream); + syscall = "fputs"; + goto fail; + } } if (ferror(stream)) { fclose(stream); - syscall = "fgetln"; + syscall = "getline"; goto fail; } done: + free(line); fclose(stream); return; fail: + free(line); warn("%s: SYSERR: %s", file, syscall); if (rc < MANDOCLEVEL_SYSERR) rc = MANDOCLEVEL_SYSERR; @@ -1002,8 +1069,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 tty proc", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); +#endif + tag_files->pager_pid = pager_pid; return pager_pid; }