=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.258 retrieving revision 1.266 diff -u -p -r1.258 -r1.266 --- mandoc/main.c 2015/11/14 23:57:47 1.258 +++ mandoc/main.c 2016/05/18 22:36:00 1.266 @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.258 2015/11/14 23:57:47 schwarze Exp $ */ +/* $Id: main.c,v 1.266 2016/05/18 22:36:00 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze + * Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "mandoc_aux.h" @@ -123,18 +124,17 @@ main(int argc, char *argv[]) unsigned char *uc; struct manpage *res, *resp; char *conf_file, *defpaths; - size_t isec, i, sz; + const char *sec; + size_t i, sz; int prio, best_prio; - char sec; - enum mandoclevel rctmp; enum outmode outmode; int fd; 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(); @@ -299,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. */ @@ -389,7 +390,7 @@ main(int argc, char *argv[]) if (outmode == OUTMODE_ONE) { argc = 1; - best_prio = 10; + best_prio = 20; } else if (outmode == OUTMODE_ALL) argc = (int)sz; @@ -405,11 +406,13 @@ main(int argc, char *argv[]) res[i].output); else if (outmode == OUTMODE_ONE) { /* Search for the best section. */ - isec = strcspn(res[i].file, "123456789"); - sec = res[i].file[isec]; - if ('\0' == sec) + sec = res[i].file; + sec += strcspn(sec, "123456789"); + if (sec[0] == '\0') continue; - prio = sec_prios[sec - '1']; + prio = sec_prios[sec[0] - '1']; + if (sec[1] != '/') + prio += 10; if (prio >= best_prio) continue; best_prio = prio; @@ -430,9 +433,13 @@ main(int argc, char *argv[]) /* mandoc(1) */ #if HAVE_PLEDGE - if (pledge(use_pager ? "stdio rpath tmppath tty 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)) @@ -454,11 +461,7 @@ main(int argc, char *argv[]) } while (argc > 0) { - rctmp = mparse_open(curp.mp, &fd, - resp != NULL ? resp->file : *argv); - if (rc < rctmp) - rc = rctmp; - + fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv); if (fd != -1) { if (use_pager) { tag_files = tag_init(); @@ -477,7 +480,8 @@ main(int argc, char *argv[]) if (argc > 1 && curp.outtype <= OUTT_UTF8) ascii_sepline(curp.outdata); - } + } else if (rc < MANDOCLEVEL_ERROR) + rc = MANDOCLEVEL_ERROR; if (MANDOCLEVEL_OK != rc && curp.wstop) break; @@ -530,11 +534,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 +578,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(); } @@ -637,8 +664,8 @@ fs_lookup(const struct manpaths *paths, size_t ipath, found: #if HAVE_SQLITE3 - warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s", - name, sec, paths->paths[ipath]); + warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s", + name, sec, BINM_MAKEWHATIS, paths->paths[ipath]); #endif *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); page = *res + (*ressz - 1); @@ -657,7 +684,7 @@ fs_search(const struct mansearch *cfg, const struct ma int argc, char **argv, struct manpage **res, size_t *ressz) { const char *const sections[] = - {"1", "8", "6", "2", "3", "3p", "5", "7", "4", "9"}; + {"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"}; const size_t nsec = sizeof(sections)/sizeof(sections[0]); size_t ipath, isec, lastsz; @@ -696,9 +723,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; @@ -992,6 +1021,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl, static pid_t spawn_pager(struct tag_files *tag_files) { + const struct timespec timeout = { 0, 100000000 }; /* 0.1s */ #define MAX_PAGER_ARGS 16 char *argv[MAX_PAGER_ARGS]; const char *pager; @@ -1041,17 +1071,15 @@ 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); - 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; } @@ -1061,6 +1089,12 @@ spawn_pager(struct tag_files *tag_files) err((int)MANDOCLEVEL_SYSERR, "pager stdout"); close(tag_files->ofd); close(tag_files->tfd); + + /* Do not start the pager before controlling the terminal. */ + + while (tcgetpgrp(STDIN_FILENO) != getpid()) + nanosleep(&timeout, NULL); + execvp(argv[0], argv); err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]); }