-/* $Id: main.c,v 1.254 2015/11/06 16:30:33 schwarze Exp $ */
+/* $Id: main.c,v 1.265 2016/04/14 20:55:48 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
#include <assert.h>
#include <ctype.h>
+#if HAVE_ERR
#include <err.h>
+#endif
+#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "mandoc_aux.h"
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, signum;
int c;
+ pid_t pager_pid, tc_pgid, man_pgid, pid;
#if HAVE_PROGNAME
progname = getprogname();
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));
!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) {
if (outmode == OUTMODE_ONE) {
argc = 1;
- best_prio = 10;
+ best_prio = 20;
} else if (outmode == OUTMODE_ALL)
argc = (int)sz;
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;
/* 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;
}
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();
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;
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();
}
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;
/* 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;
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);
}
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;
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;
case 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;
}
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]);
}