summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2015-07-19 06:05:16 +0000
committerIngo Schwarze <schwarze@openbsd.org>2015-07-19 06:05:16 +0000
commit2911006dcd808278e26b990dd26b268183fc27b4 (patch)
tree987ef2c8066de90b45e419ccceecab93993a392f
parent20a972b9c7a4dc0048c55dd8cb3a9bc426793851 (diff)
downloadmandoc-2911006dcd808278e26b990dd26b268183fc27b4.tar.gz
Do not fork and exec gunzip(1), just link with libz instead.
As discussed with deraadt@, that's cleaner and will help tame(2). Something like this was also suggested earlier by bapt at FreeBSD. Minus 50 lines of code, deleting one interface function (mparse_wait), no functional change intended.
-rw-r--r--INSTALL7
-rw-r--r--Makefile2
-rwxr-xr-xconfigure4
-rw-r--r--main.c4
-rw-r--r--mandoc.350
-rw-r--r--mandoc.h1
-rw-r--r--mandocdb.c4
-rw-r--r--read.c114
8 files changed, 46 insertions, 140 deletions
diff --git a/INSTALL b/INSTALL
index dc0f6b0e..78bc61d1 100644
--- a/INSTALL
+++ b/INSTALL
@@ -84,9 +84,10 @@ manual page source.
Understanding mandoc dependencies
---------------------------------
-The mandoc(1), man(1), and demandoc(1) utilities have no external
-dependencies, but makewhatis(8) and apropos(1) depend on the
-following software:
+The mandoc(1), man(1), and demandoc(1) utilities only depend
+on the zlib library for decompressing gzipped manual pages,
+but makewhatis(8) and apropos(1) depend on the following
+additional software:
1. The SQLite database system, see <http://sqlite.org/>.
The recommended version of SQLite is 3.8.4.3 or newer. The mandoc
diff --git a/Makefile b/Makefile
index 8f466d02..6e1d2529 100644
--- a/Makefile
+++ b/Makefile
@@ -403,7 +403,7 @@ man.cgi: $(CGI_OBJS) libmandoc.a
$(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
demandoc: $(DEMANDOC_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a -lz
soelim: $(SOELIM_OBJS) compat_reallocarray.o
$(CC) $(LDFLAGS) -o $@ $(SOELIM_OBJS) compat_reallocarray.o
diff --git a/configure b/configure
index 59a28f92..7a3bb306 100755
--- a/configure
+++ b/configure
@@ -239,9 +239,9 @@ fi
# --- DBLIB ---
if [ ${BUILD_DB} -eq 0 ]; then
- DBLIB=
+ DBLIB="-lz"
elif [ -z "${DBLIB}" ]; then
- DBLIB="${DETECTLIB}"
+ DBLIB="${DETECTLIB} -lz"
echo "DBLIB=\"${DBLIB}\"" 1>&2
echo "DBLIB=\"${DBLIB}\"" 1>&3
echo 1>&3
diff --git a/main.c b/main.c
index 1ec130e9..a6587683 100644
--- a/main.c
+++ b/main.c
@@ -458,10 +458,6 @@ main(int argc, char *argv[])
passthrough(resp->file, fd,
conf.output.synopsisonly);
- rctmp = mparse_wait(curp.mp);
- if (rc < rctmp)
- rc = rctmp;
-
if (argc > 1 && curp.outtype <= OUTT_UTF8)
ascii_sepline(curp.outdata);
}
diff --git a/mandoc.3 b/mandoc.3
index 630cb52e..cd4fe78b 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -37,7 +37,6 @@
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel
-.Nm mparse_wait ,
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
@@ -106,10 +105,6 @@
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
-.Ft "enum mandoclevel"
-.Fo mparse_wait
-.Fa "struct mparse *parse"
-.Fc
.In sys/types.h
.In mandoc.h
.In mdoc.h
@@ -392,20 +387,14 @@ Declared in
implemented in
.Pa read.c .
.It Fn mparse_open
-If the
+Open the file for reading.
+If that fails and
.Fa fname
-ends in
-.Pa .gz ,
-open with
-.Xr gunzip 1 ;
-otherwise, with
-.Xr open 2 .
-If
-.Xr open 2
-fails, append
-.Pa .gz
-and try with
-.Xr gunzip 1 .
+does not already end in
+.Ql .gz ,
+try again after appending
+.Ql .gz .
+Save the information whether the file is zipped or not.
Return a file descriptor open for reading in
.Fa fd ,
or -1 on failure.
@@ -423,9 +412,6 @@ or
.Fn mparse_open .
Pass the associated filename in
.Va fname .
-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.
@@ -460,28 +446,6 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
-.It Fn mparse_wait
-Bury a
-.Xr gunzip 1
-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
-.Dv MANDOCLEVEL_SYSERR
-on failure, that is, when
-.Xr wait 2
-fails, or when
-.Xr gunzip 1
-died from a signal or exited with non-zero status.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa read.c .
.El
.Ss Variables
.Bl -ohang
diff --git a/mandoc.h b/mandoc.h
index 7a0fae10..d68f3c16 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -438,6 +438,5 @@ void mparse_result(struct mparse *,
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
-enum mandoclevel mparse_wait(struct mparse *);
__END_DECLS
diff --git a/mandocdb.c b/mandocdb.c
index e89dc164..5855e405 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1246,10 +1246,6 @@ mpages_merge(struct mparse *mp)
mlink = mpage->mlinks;
nextpage:
- if (mparse_wait(mp) != MANDOCLEVEL_OK) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mlink->file, "&wait gunzip");
- }
ohash_delete(&strings);
ohash_delete(&names);
mpage = ohash_next(&mpages, &pslot);
diff --git a/read.c b/read.c
index 40fb15a4..11b24ac1 100644
--- a/read.c
+++ b/read.c
@@ -23,19 +23,18 @@
#include <sys/mman.h>
#include <sys/stat.h>
#endif
-#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <zlib.h>
#include "mandoc_aux.h"
#include "mandoc.h"
@@ -60,10 +59,10 @@ struct mparse {
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int options; /* parser options */
+ int gzip; /* current input file is gzipped */
int filenc; /* encoding of the current file */
int reparse_count; /* finite interp. stack */
int line; /* line number in the file */
- pid_t child; /* the gunzip(1) process */
};
static void choose_parser(struct mparse *);
@@ -327,7 +326,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
int of;
int lnn; /* line number in the real file */
int fd;
- pid_t save_child;
unsigned char c;
memset(&ln, 0, sizeof(ln));
@@ -539,7 +537,6 @@ rerun:
if (curp->secondary)
curp->secondary->sz -= pos + 1;
save_file = curp->file;
- save_child = curp->child;
if (mparse_open(curp, &fd, ln.buf + of) ==
MANDOCLEVEL_OK) {
mparse_readfd(curp, fd, ln.buf + of);
@@ -557,7 +554,6 @@ rerun:
of = 0;
mparse_buf_r(curp, ln, of, 0);
}
- curp->child = save_child;
pos = 0;
continue;
default:
@@ -611,6 +607,7 @@ static int
read_whole_file(struct mparse *curp, const char *file, int fd,
struct buf *fb, int *with_mmap)
{
+ gzFile gz;
size_t off;
ssize_t ssz;
@@ -628,7 +625,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
* concerned that this is going to tank any machines.
*/
- if (S_ISREG(st.st_mode)) {
+ if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
if (st.st_size > 0x7fffffff) {
mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
@@ -641,6 +638,14 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
#endif
+ if (curp->gzip) {
+ if ((gz = gzdopen(fd, "rb")) == NULL) {
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ } else
+ gz = NULL;
+
/*
* If this isn't a regular file (like, say, stdin), then we must
* go the old way and just read things in bit by bit.
@@ -659,7 +664,9 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
resize_buf(fb, 65536);
}
- ssz = read(fd, fb->buf + (int)off, fb->sz - off);
+ ssz = curp->gzip ?
+ gzread(gz, fb->buf + (int)off, fb->sz - off) :
+ read(fd, fb->buf + (int)off, fb->sz - off);
if (ssz == 0) {
fb->sz = off;
return(1);
@@ -773,99 +780,42 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
- mparse_wait(curp);
return(curp->file_status);
}
enum mandoclevel
mparse_open(struct mparse *curp, int *fd, const char *file)
{
- int pfd[2];
- int save_errno;
char *cp;
curp->file = file;
+ cp = strrchr(file, '.');
+ curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
- /* Unless zipped, try to just open the file. */
+ /* First try to use the filename as it is. */
- if ((cp = strrchr(file, '.')) == NULL ||
- strcmp(cp + 1, "gz")) {
- curp->child = 0;
- if ((*fd = open(file, O_RDONLY)) != -1)
- return(MANDOCLEVEL_OK);
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
- /* Open failed; try to append ".gz". */
+ /*
+ * If that doesn't work and the filename doesn't
+ * already end in .gz, try appending .gz.
+ */
+ if ( ! curp->gzip) {
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;
+ *fd = open(file, O_RDONLY);
free(cp);
- *fd = -1;
- curp->child = 0;
- mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
- return(MANDOCLEVEL_ERROR);
- }
-
- /* Run gunzip(1). */
-
- if (pipe(pfd) == -1) {
- perror("pipe");
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- switch (curp->child = fork()) {
- case -1:
- perror("fork");
- exit((int)MANDOCLEVEL_SYSERR);
- case 0:
- close(pfd[0]);
- if (dup2(pfd[1], STDOUT_FILENO) == -1) {
- perror("dup");
- exit((int)MANDOCLEVEL_SYSERR);
+ if (*fd != -1) {
+ curp->gzip = 1;
+ return(MANDOCLEVEL_OK);
}
- signal(SIGPIPE, SIG_DFL);
- execlp("gunzip", "gunzip", "-c", file, NULL);
- perror("exec");
- exit((int)MANDOCLEVEL_SYSERR);
- default:
- close(pfd[1]);
- *fd = pfd[0];
- return(MANDOCLEVEL_OK);
}
-}
-enum mandoclevel
-mparse_wait(struct mparse *curp)
-{
- int status;
-
- if (curp->child == 0)
- return(MANDOCLEVEL_OK);
+ /* Neither worked, give up. */
- if (waitpid(curp->child, &status, 0) == -1) {
- perror("wait");
- exit((int)MANDOCLEVEL_SYSERR);
- }
- curp->child = 0;
- if (WIFSIGNALED(status)) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
- "gunzip died from signal %d", WTERMSIG(status));
- return(MANDOCLEVEL_ERROR);
- }
- if (WEXITSTATUS(status)) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
- "gunzip failed with code %d", WEXITSTATUS(status));
- return(MANDOCLEVEL_ERROR);
- }
- return(MANDOCLEVEL_OK);
+ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
+ return(MANDOCLEVEL_ERROR);
}
struct mparse *