=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.250 retrieving revision 1.259 diff -u -p -r1.250 -r1.259 --- mandoc/main.c 2015/10/19 19:51:22 1.250 +++ mandoc/main.c 2015/11/20 21:59:54 1.259 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.250 2015/10/19 19:51:22 schwarze Exp $ */ +/* $Id: main.c,v 1.259 2015/11/20 21:59:54 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 @@ -101,8 +104,6 @@ static int toptions(struct curparse *, char *); static void usage(enum argmode) __attribute__((noreturn)); static int woptions(struct curparse *, char *); -extern char *__progname; - static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; static char help_arg[] = "help"; static char *help_argv[] = {help_arg, NULL}; @@ -116,6 +117,7 @@ main(int argc, char *argv[]) struct curparse curp; struct mansearch search; struct tag_files *tag_files; + const char *progname; char *auxpaths; char *defos; unsigned char *uc; @@ -130,22 +132,33 @@ 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 +#if HAVE_PROGNAME + progname = getprogname(); +#else if (argc < 1) - __progname = mandoc_strdup("mandoc"); - else if ((__progname = strrchr(argv[0], '/')) == NULL) - __progname = argv[0]; + progname = mandoc_strdup("mandoc"); + else if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; else - ++__progname; + ++progname; + setprogname(progname); #endif #if HAVE_SQLITE3 - if (strcmp(__progname, BINM_MAKEWHATIS) == 0) + if (strncmp(progname, "mandocdb", 8) == 0 || + strcmp(progname, BINM_MAKEWHATIS) == 0) 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)); @@ -155,13 +168,13 @@ main(int argc, char *argv[]) memset(&search, 0, sizeof(struct mansearch)); search.outkey = "Nd"; - if (strcmp(__progname, BINM_MAN) == 0) + if (strcmp(progname, BINM_MAN) == 0) search.argmode = ARG_NAME; - else if (strcmp(__progname, BINM_APROPOS) == 0) + else if (strcmp(progname, BINM_APROPOS) == 0) search.argmode = ARG_EXPR; - else if (strcmp(__progname, BINM_WHATIS) == 0) + else if (strcmp(progname, BINM_WHATIS) == 0) search.argmode = ARG_WORD; - else if (strncmp(__progname, "help", 4) == 0) + else if (strncmp(progname, "help", 4) == 0) search.argmode = ARG_NAME; else search.argmode = ARG_FILE; @@ -285,6 +298,11 @@ main(int argc, char *argv[]) !isatty(STDOUT_FILENO)) use_pager = 0; +#if HAVE_PLEDGE + if (!use_pager && pledge("stdio rpath flock", NULL) == -1) + err((int)MANDOCLEVEL_SYSERR, "pledge"); +#endif + /* Parse arguments. */ if (argc > 0) { @@ -299,7 +317,7 @@ main(int argc, char *argv[]) */ if (search.argmode == ARG_NAME) { - if (*__progname == 'h') { + if (*progname == 'h') { if (argc == 0) { argv = help_argv; argc = 1; @@ -411,6 +429,12 @@ 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"); +#endif + if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths)) return (int)MANDOCLEVEL_BADARG; @@ -466,21 +490,23 @@ main(int argc, char *argv[]) mparse_reset(curp.mp); } - switch (curp.outtype) { - case OUTT_HTML: - html_free(curp.outdata); - break; - case OUTT_UTF8: - case OUTT_LOCALE: - case OUTT_ASCII: - ascii_free(curp.outdata); - break; - case OUTT_PDF: - case OUTT_PS: - pspdf_free(curp.outdata); - break; - default: - break; + if (curp.outdata != NULL) { + switch (curp.outtype) { + case OUTT_HTML: + html_free(curp.outdata); + break; + case OUTT_UTF8: + case OUTT_LOCALE: + case OUTT_ASCII: + ascii_free(curp.outdata); + break; + case OUTT_PDF: + case OUTT_PS: + pspdf_free(curp.outdata); + break; + default: + break; + } } mparse_free(curp.mp); mchars_free(); @@ -504,7 +530,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(); } @@ -589,7 +660,7 @@ fs_lookup(const struct manpaths *paths, size_t ipath, found: #if HAVE_SQLITE3 - warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s\n", + warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s", name, sec, paths->paths[ipath]); #endif *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); @@ -696,6 +767,7 @@ parse(struct curparse *curp, int fd, const char *file) if (man == NULL) return; if (man->macroset == MACROSET_MDOC) { + mdoc_validate(man); switch (curp->outtype) { case OUTT_HTML: html_mdoc(curp->outdata, man); @@ -718,6 +790,7 @@ parse(struct curparse *curp, int fd, const char *file) } } if (man->macroset == MACROSET_MAN) { + man_validate(man); switch (curp->outtype) { case OUTT_HTML: html_man(curp->outdata, man); @@ -749,12 +822,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); @@ -763,45 +836,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; @@ -927,7 +996,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl, { const char *mparse_msg; - fprintf(stderr, "%s: %s:", __progname, file); + fprintf(stderr, "%s: %s:", getprogname(), file); if (line) fprintf(stderr, "%d:%d:", line, col + 1); @@ -995,8 +1064,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; }