=================================================================== RCS file: /cvs/mandoc/read.c,v retrieving revision 1.81 retrieving revision 1.82 diff -u -p -r1.81 -r1.82 --- mandoc/read.c 2014/08/16 19:00:01 1.81 +++ mandoc/read.c 2014/09/03 23:21:47 1.82 @@ -1,4 +1,4 @@ -/* $Id: read.c,v 1.81 2014/08/16 19:00:01 schwarze Exp $ */ +/* $Id: read.c,v 1.82 2014/09/03 23:21:47 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2014 Ingo Schwarze @@ -20,9 +20,10 @@ #include #if HAVE_MMAP -#include #include +#include #endif +#include #include #include @@ -213,9 +214,16 @@ static const char * const mandocerrs[MANDOCERR_MAX] = ".so request failed", /* system errors */ + "cannot dup file descriptor", + "cannot exec", + "gunzip failed with code", + "cannot fork", NULL, - "cannot stat file", + "cannot open pipe", "cannot read file", + "gunzip died from signal", + "cannot stat file", + "wait failed", }; static const char * const mandoclevels[MANDOCLEVEL_MAX] = { @@ -774,6 +782,91 @@ mparse_readfd(struct mparse *curp, int fd, const char perror(file); out: return(curp->file_status); +} + +enum mandoclevel +mparse_open(struct mparse *curp, int *fd, const char *file, + pid_t *child_pid) +{ + int pfd[2]; + char *cp; + enum mandocerr err; + + pfd[1] = -1; + curp->file = file; + if ((cp = strrchr(file, '.')) == NULL || + strcmp(cp + 1, "gz")) { + *child_pid = 0; + if ((*fd = open(file, O_RDONLY)) == -1) { + err = MANDOCERR_SYSOPEN; + goto out; + } + return(MANDOCLEVEL_OK); + } + + if (pipe(pfd) == -1) { + err = MANDOCERR_SYSPIPE; + goto out; + } + + switch (*child_pid = fork()) { + case -1: + err = MANDOCERR_SYSFORK; + close(pfd[0]); + close(pfd[1]); + pfd[1] = -1; + break; + case 0: + close(pfd[0]); + if (dup2(pfd[1], STDOUT_FILENO) == -1) { + err = MANDOCERR_SYSDUP; + break; + } + execlp("gunzip", "gunzip", "-c", file, NULL); + err = MANDOCERR_SYSEXEC; + break; + default: + close(pfd[1]); + *fd = pfd[0]; + return(MANDOCLEVEL_OK); + } + +out: + *fd = -1; + *child_pid = 0; + curp->file_status = MANDOCLEVEL_SYSERR; + if (curp->mmsg) + (*curp->mmsg)(err, curp->file_status, file, + 0, 0, strerror(errno)); + if (pfd[1] != -1) + exit(1); + return(curp->file_status); +} + +enum mandoclevel +mparse_wait(struct mparse *curp, pid_t child_pid) +{ + int status; + + if (waitpid(child_pid, &status, 0) == -1) { + mandoc_msg(MANDOCERR_SYSWAIT, curp, 0, 0, + strerror(errno)); + curp->file_status = MANDOCLEVEL_SYSERR; + return(curp->file_status); + } + if (WIFSIGNALED(status)) { + mandoc_vmsg(MANDOCERR_SYSSIG, curp, 0, 0, + "%d", WTERMSIG(status)); + curp->file_status = MANDOCLEVEL_SYSERR; + return(curp->file_status); + } + if (WEXITSTATUS(status)) { + mandoc_vmsg(MANDOCERR_SYSEXIT, curp, 0, 0, + "%d", WEXITSTATUS(status)); + curp->file_status = MANDOCLEVEL_SYSERR; + return(curp->file_status); + } + return(MANDOCLEVEL_OK); } struct mparse *