summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-11-26 23:42:14 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-11-26 23:42:14 +0000
commit2522d763b092433ecab5e1d79f2ff9cd8bba1466 (patch)
tree8d9442c8eba5468d48ecbd1f458d05a212e0bad4
parenta7d7f08f9bf1378002063e44fe9ce8a27a886eed (diff)
downloadmandoc-2522d763b092433ecab5e1d79f2ff9cd8bba1466.tar.gz
Let mparse_readfd() use mparse_open() and mparse_wait()
and let mparse_open() fall back to .gz files such that .so works even when the target is zipped, requested by and in part using ideas from <bapt at FreeBSD>. While here, make sure files are readable before forking, both for efficiency and for better error reporting.
-rw-r--r--mandoc.323
-rw-r--r--read.c64
2 files changed, 59 insertions, 28 deletions
diff --git a/mandoc.3 b/mandoc.3
index b35f4251..af48348a 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -396,6 +396,12 @@ open with
.Xr gunzip 1 ;
otherwise, with
.Xr open 2 .
+If
+.Xr open 2
+fails, append
+.Pa .gz
+and try with
+.Xr gunzip 1 .
Return a file descriptor open for reading in
.Fa fd ,
or -1 on failure.
@@ -410,14 +416,18 @@ implemented in
Parse a file or file descriptor.
If
.Va fd
-is -1,
+is -1, open
.Va fname
-is opened for reading.
+with
+.Fn mparse_open .
Otherwise,
.Va fname
is assumed to be the name associated with
.Va fd .
-This may be called multiple times with different parameters; however,
+Calls
+.Fn mparse_wait
+before returning.
+This function may be called multiple times with different parameters; however,
.Fn mparse_reset
should be invoked between parses.
Declared in
@@ -461,11 +471,12 @@ implemented in
.It Fn mparse_wait
Bury a
.Xr gunzip 1
-child process
-.Fa child_pid
-that was spawned with
+child process that was spawned with
.Fn mparse_open .
To be called after the parse sequence is complete.
+Not needed after
+.Fn mparse_readfd ,
+but does no harm in that case, either.
Returns
.Dv MANDOCLEVEL_OK
on success and
diff --git a/read.c b/read.c
index 0d89db02..9bea86ae 100644
--- a/read.c
+++ b/read.c
@@ -780,28 +780,25 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len,
return(curp->file_status);
}
+/*
+ * If a file descriptor is given, use it and assume it points
+ * to the named file. Otherwise, open the named file.
+ * Read the whole file into memory and call the parsers.
+ * Called recursively when an .so request is encountered.
+ */
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
int save_filenc;
+ pid_t save_child;
- if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSOPEN,
- curp->file_status,
- file, 0, 0, strerror(errno));
- return(curp->file_status);
- }
-
- /*
- * Run for each opened file; may be called more than once for
- * each full parse sequence if the opened file is nested (i.e.,
- * from `so'). Simply sucks in the whole file and moves into
- * the parse phase for the file.
- */
+ save_child = curp->child;
+ if (fd != -1)
+ curp->child = 0;
+ else if (mparse_open(curp, &fd, file) >= MANDOCLEVEL_SYSERR)
+ goto out;
if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
save_filenc = curp->filenc;
@@ -817,9 +814,12 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
free(blk.buf);
}
- if (STDIN_FILENO != fd && -1 == close(fd))
+ if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
+ mparse_wait(curp);
+out:
+ curp->child = save_child;
return(curp->file_status);
}
@@ -827,21 +827,40 @@ enum mandoclevel
mparse_open(struct mparse *curp, int *fd, const char *file)
{
int pfd[2];
+ int save_errno;
char *cp;
enum mandocerr err;
pfd[1] = -1;
curp->file = file;
+
+ /* Unless zipped, try to just open the file. */
+
if ((cp = strrchr(file, '.')) == NULL ||
strcmp(cp + 1, "gz")) {
curp->child = 0;
- if ((*fd = open(file, O_RDONLY)) == -1) {
- err = MANDOCERR_SYSOPEN;
- goto out;
- }
- return(MANDOCLEVEL_OK);
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
+
+ /* Open failed; try to append ".gz". */
+
+ mandoc_asprintf(&cp, "%s.gz", file);
+ file = cp;
+ } else
+ cp = NULL;
+
+ /* Before forking, make sure the file can be read. */
+
+ save_errno = errno;
+ if (access(file, R_OK) == -1) {
+ if (cp != NULL)
+ errno = save_errno;
+ err = MANDOCERR_SYSOPEN;
+ goto out;
}
+ /* Run gunzip(1). */
+
if (pipe(pfd) == -1) {
err = MANDOCERR_SYSPIPE;
goto out;
@@ -870,11 +889,12 @@ mparse_open(struct mparse *curp, int *fd, const char *file)
}
out:
+ free(cp);
*fd = -1;
curp->child = 0;
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
- (*curp->mmsg)(err, curp->file_status, file,
+ (*curp->mmsg)(err, curp->file_status, curp->file,
0, 0, strerror(errno));
if (pfd[1] != -1)
exit(1);