From cf199a76d662055ce96b65d3442832db41fbc63c Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Wed, 26 Nov 2014 23:42:14 +0000 Subject: 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 . While here, make sure files are readable before forking, both for efficiency and for better error reporting. --- mandoc.3 | 25 +++++++++++++++++------- read.c | 66 ++++++++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 61 insertions(+), 30 deletions(-) diff --git a/mandoc.3 b/mandoc.3 index 08a0d168..f05fdac9 100644 --- a/mandoc.3 +++ b/mandoc.3 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.3,v 1.28 2014/11/26 21:40:17 schwarze Exp $ +.\" $Id: mandoc.3,v 1.29 2014/11/26 23:42:14 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2010 Ingo Schwarze @@ -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 cad96e2d..6ef75e51 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $Id: read.c,v 1.97 2014/11/26 21:40:17 schwarze Exp $ */ +/* $Id: read.c,v 1.98 2014/11/26 23:42:14 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2014 Ingo Schwarze @@ -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); -- cgit v1.2.3-56-ge451