diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2015-01-15 04:26:39 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2015-01-15 04:26:39 +0000 |
commit | 581eba212eeec68331e4aa4a904d7c2d72bac114 (patch) | |
tree | d24a62288413bfb95754a300f45747756dc9943e | |
parent | 23a511d07a0f2e04178f507d768c9e5e7e86f858 (diff) | |
download | mandoc-581eba212eeec68331e4aa4a904d7c2d72bac114.tar.gz |
Fatal errors no longer exist.
If a file can be opened, mandoc will produce some output;
at worst, the output may be almost empty.
Simplifies error handling and frees a message type for future use.
-rw-r--r-- | cgi.c | 12 | ||||
-rw-r--r-- | demandoc.c | 16 | ||||
-rw-r--r-- | libmandoc.h | 4 | ||||
-rw-r--r-- | main.c | 9 | ||||
-rw-r--r-- | man.1 | 12 | ||||
-rw-r--r-- | man.c | 3 | ||||
-rw-r--r-- | mandoc.1 | 90 | ||||
-rw-r--r-- | mandoc.3 | 31 | ||||
-rw-r--r-- | mandoc.h | 5 | ||||
-rw-r--r-- | mandocdb.c | 13 | ||||
-rw-r--r-- | mdoc.c | 3 | ||||
-rw-r--r-- | read.c | 51 |
12 files changed, 91 insertions, 158 deletions
@@ -822,7 +822,6 @@ format(const struct req *req, const char *file) struct man *man; void *vp; char *opts; - enum mandoclevel rc; int fd; int usepath; @@ -832,18 +831,11 @@ format(const struct req *req, const char *file) } mchars = mchars_alloc(); - mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, + mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, mchars, req->q.manpath); - rc = mparse_readfd(mp, fd, file); + mparse_readfd(mp, fd, file); close(fd); - if (rc >= MANDOCLEVEL_FATAL) { - fprintf(stderr, "fatal mandoc error: %s/%s\n", - req->q.manpath, file); - pg_error_internal(); - return; - } - usepath = strcmp(req->q.manpath, req->p[0]); mandoc_asprintf(&opts, "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s", @@ -44,7 +44,7 @@ main(int argc, char *argv[]) { struct mparse *mp; struct mchars *mchars; - int ch, i, list; + int ch, fd, i, list; extern int optind; progname = strrchr(argv[0], '/'); @@ -78,7 +78,7 @@ main(int argc, char *argv[]) argv += optind; mchars = mchars_alloc(); - mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, mchars, NULL); + mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, mchars, NULL); assert(mp); if (0 == argc) @@ -86,7 +86,11 @@ main(int argc, char *argv[]) for (i = 0; i < argc; i++) { mparse_reset(mp); - pmandoc(mp, -1, argv[i], list); + if (mparse_open(mp, &fd, argv[i]) != MANDOCLEVEL_OK) { + perror(argv[i]); + continue; + } + pmandoc(mp, fd, argv[i], list); } mparse_free(mp); @@ -108,11 +112,7 @@ pmandoc(struct mparse *mp, int fd, const char *fn, int list) struct man *man; int line, col; - if (mparse_readfd(mp, fd, fn) >= MANDOCLEVEL_FATAL) { - fprintf(stderr, "%s: Parse failure\n", fn); - return; - } - + mparse_readfd(mp, fd, fn); mparse_result(mp, &mdoc, &man, NULL); line = 1; col = 0; diff --git a/libmandoc.h b/libmandoc.h index 0121b6da..f229466a 100644 --- a/libmandoc.h +++ b/libmandoc.h @@ -60,7 +60,7 @@ struct mdoc *mdoc_alloc(struct roff *, struct mparse *, const char *, int); void mdoc_reset(struct mdoc *); int mdoc_parseln(struct mdoc *, int, char *, int); -int mdoc_endparse(struct mdoc *); +void mdoc_endparse(struct mdoc *); void mdoc_addspan(struct mdoc *, const struct tbl_span *); void mdoc_addeqn(struct mdoc *, const struct eqn *); @@ -69,7 +69,7 @@ struct man *man_alloc(struct roff *, struct mparse *, const char *, int); void man_reset(struct man *); int man_parseln(struct man *, int, char *, int); -int man_endparse(struct man *); +void man_endparse(struct man *); void man_addspan(struct man *, const struct tbl_span *); void man_addeqn(struct man *, const struct eqn *); @@ -176,7 +176,7 @@ main(int argc, char *argv[]) memset(&curp, 0, sizeof(struct curparse)); curp.outtype = OUTT_LOCALE; - curp.wlevel = MANDOCLEVEL_FATAL; + curp.wlevel = MANDOCLEVEL_BADARG; options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; defos = NULL; @@ -647,11 +647,6 @@ parse(struct curparse *curp, int fd, const char *file, rc = mparse_readfd(curp->mp, fd, file); - /* Stop immediately if the parse has failed. */ - - if (MANDOCLEVEL_FATAL <= rc) - goto cleanup; - /* * With -Wstop and warnings or errors of at least the requested * level, do not produce output. @@ -913,7 +908,7 @@ woptions(struct curparse *curp, char *arg) curp->wlevel = MANDOCLEVEL_ERROR; break; case 4: - curp->wlevel = MANDOCLEVEL_FATAL; + curp->wlevel = MANDOCLEVEL_BADARG; break; default: fprintf(stderr, "%s: -W %s: Bad argument\n", @@ -3,7 +3,7 @@ .\" Copyright (c) 1989, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org> -.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010, 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -300,15 +300,15 @@ to be reported on the standard error output and to affect the exit status. The .Ar level can be -.Cm warning , -.Cm error , +.Cm warning or -.Cm fatal . -The default is -.Cm fatal ; +.Cm error ; .Cm all is an alias for .Cm warning . +By default, +.Nm +is silent. See the .Xr mandoc 1 manual for details. @@ -109,12 +109,11 @@ man_alloc(struct roff *roff, struct mparse *parse, return(p); } -int +void man_endparse(struct man *man) { man_macroend(man); - return(1); } int @@ -159,15 +159,15 @@ to be reported on the standard error output and to affect the exit status. The .Ar level can be -.Cm warning , -.Cm error , +.Cm warning or -.Cm fatal . -The default is -.Fl W Ns Cm fatal ; -.Fl W Ns Cm all +.Cm error ; +.Cm all is an alias for -.Fl W Ns Cm warning . +.Cm warning . +By default, +.Nm +is silent. See .Sx EXIT STATUS and @@ -532,13 +532,11 @@ At least one warning occurred, but no error, and .Fl W Ns Cm warning was specified. .It 3 -At least one parsing error occurred, but no fatal error, and +At least one parsing error occurred, and .Fl W Ns Cm error or .Fl W Ns Cm warning was specified. -.It 4 -A fatal parsing error occurred. .It 5 Invalid command line arguments were specified. No input files have been read. @@ -603,9 +601,6 @@ fields. .Pp Message levels have the following meanings: .Bl -tag -width "warning" -.It Cm fatal -The parser is unable to parse a given input file at all. -No formatted output is produced from that input file. .It Cm error An input file contains syntax that cannot be safely interpreted, either because it is invalid or because @@ -1277,6 +1272,14 @@ keeps the code more readable. .El .Ss "Errors related to roff, mdoc, and man code" .Bl -ohang +.It Sy "input too large" +.Pq mdoc , man +Currently, +.Nm +cannot handle input files larger than its arbitrary size limit +of 2^31 bytes (2 Gigabytes). +Since useful manuals are always small, this is not a problem in practice. +Parsing is aborted as soon as the condition is detected. .It Sy "input stack limit exceeded, infinite loop?" .Pq roff Explicit recursion limits are implemented for the following features, @@ -1465,6 +1468,29 @@ or .Ic \&gsize statement has a non-numeric or negative argument or no argument at all. The invalid request or statement is ignored. +.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq" +.Pq roff +For security reasons, +.Nm +allows +.Ic \&so +file inclusion requests only with relative paths +and only without ascending to any parent directory. +By requesting the inclusion of a sensitive file, a malicious document +might otherwise trick a privileged user into inadvertently displaying +the file on the screen, revealing the file content to bystanders. +.Nm +only shows the path as it appears behind +.Ic \&so . +.It Sy ".so request failed" +.Pq roff +Servicing a +.Ic \&so +request requires reading an external file, but the file could not be +opened. +.Nm +only shows the path as it appears behind +.Ic \&so . .It Sy "skipping all arguments" .Pq mdoc , man , eqn , roff An @@ -1504,44 +1530,6 @@ macro is invoked with more than one argument, or a request of the family is invoked with more than two arguments. The excess arguments are ignored. .El -.Ss FATAL errors -.Bl -ohang -.It Sy "input too large" -.Pq mdoc , man -Currently, -.Nm -cannot handle input files larger than its arbitrary size limit -of 2^31 bytes (2 Gigabytes). -Since useful manuals are always small, this is not a problem in practice. -Parsing is aborted as soon as the condition is detected. -.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq" -.Pq roff -For security reasons, -.Nm -allows -.Ic \&so -file inclusion requests only with relative paths -and only without ascending to any parent directory. -By requesting the inclusion of a sensitive file, a malicious document -might otherwise trick a privileged user into inadvertently displaying -the file on the screen, revealing the file content to bystanders. -The parser exits immediately. -.It Sy ".so request failed" -.Pq roff -Servicing a -.Ic \&so -request requires reading an external file. -While trying to do so, an -.Xr open 2 , -.Xr stat 2 , -or -.Xr read 2 -system call failed. -The parser exits immediately. -Before showing this message, -.Nm -always shows another message explaining why the system call failed. -.El .Sh COMPATIBILITY This section summarises .Nm @@ -1,7 +1,7 @@ .\" $Id$ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -39,11 +39,10 @@ .Nm mparse_strlevel .Nm mparse_wait , .Nd mandoc macro compiler library -.Sh LIBRARY -.Lb libmandoc .Sh SYNOPSIS .In sys/types.h .In mandoc.h +.Pp .Fd "#define ASCII_NBRSP" .Fd "#define ASCII_HYPH" .Fd "#define ASCII_BREAK" @@ -176,12 +175,15 @@ initiate a parsing sequence with and .Fn mparse_alloc ; .It -parse files with -.Fn mparse_open -and +open a file with +.Xr open 2 +or +.Fn mparse_open ; +.It +parse it with .Fn mparse_readfd ; .It -retrieve a parsed syntax tree, if the parse was successful, with +retrieve the syntax tree with .Fn mparse_result ; .It iterate over parse nodes with @@ -208,7 +210,7 @@ and .Ss Types .Bl -ohang .It Vt "enum mandocerr" -A fatal error, error, or warning message during parsing. +An error or warning message during parsing. .It Vt "enum mandoclevel" A classification of an .Vt "enum mandocerr" @@ -229,7 +231,7 @@ This may be used across parsed input if .Fn mparse_reset is called between parses. .It Vt "mandocmsg" -A prototype for a function to handle fatal error, error, and warning +A prototype for a function to handle error and warning messages emitted by the parser. .El .Ss Functions @@ -333,7 +335,7 @@ This is for example useful in to quickly build minimal databases. .It Ar wlevel Can be set to -.Dv MANDOCLEVEL_FATAL , +.Dv MANDOCLEVEL_BADARG , .Dv MANDOCLEVEL_ERROR , or .Dv MANDOCLEVEL_WARNING . @@ -441,14 +443,7 @@ implemented in .Pa read.c . .It Fn mparse_result Obtain the result of a parse. -Only successful parses -.Po -i.e., those where -.Fn mparse_readfd -returned less than MANDOCLEVEL_FATAL -.Pc -should invoke this function, in which case one of the three pointers will -be filled in. +One of the three pointers will be filled in. Declared in .In mandoc.h , implemented in @@ -148,6 +148,7 @@ enum mandocerr { /* related to document structure and macros */ MANDOCERR_FILE, /* cannot open file */ + MANDOCERR_TOOLARGE, /* input too large */ MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character: number */ MANDOCERR_MACRO, /* skipping unknown macro: macro */ @@ -172,10 +173,6 @@ enum mandocerr { MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */ MANDOCERR_DIVZERO, /* divide by zero */ - MANDOCERR_FATAL, /* ===== start of fatal errors ===== */ - - MANDOCERR_TOOLARGE, /* input too large */ - MANDOCERR_MAX }; @@ -442,7 +442,7 @@ mandocdb(int argc, char *argv[]) exitcode = (int)MANDOCLEVEL_OK; mchars = mchars_alloc(); - mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL, + mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, mchars, NULL); ohash_init(&mpages, 6, &mpages_info); ohash_init(&mlinks, 6, &mlinks_info); @@ -1102,7 +1102,6 @@ mpages_merge(struct mparse *mp) char *cp; int fd; unsigned int pslot; - enum mandoclevel lvl; str_info.alloc = hash_alloc; str_info.calloc = hash_calloc; @@ -1136,14 +1135,12 @@ mpages_merge(struct mparse *mp) } /* - * Try interpreting the file as mdoc(7) or man(7) - * source code, unless it is already known to be - * formatted. Fall back to formatted mode. + * Interpret the file as mdoc(7) or man(7) source + * code, unless it is known to be formatted. */ if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { - lvl = mparse_readfd(mp, fd, mlink->file); - if (lvl < MANDOCLEVEL_FATAL) - mparse_result(mp, &mdoc, &man, &sodest); + mparse_readfd(mp, fd, mlink->file); + mparse_result(mp, &mdoc, &man, &sodest); } if (sodest != NULL) { @@ -190,12 +190,11 @@ mdoc_alloc(struct roff *roff, struct mparse *parse, return(p); } -int +void mdoc_endparse(struct mdoc *mdoc) { mdoc_macroend(mdoc); - return(1); } void @@ -80,7 +80,7 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { MANDOCERR_WARNING, MANDOCERR_WARNING, MANDOCERR_ERROR, - MANDOCERR_FATAL, + MANDOCERR_MAX, MANDOCERR_MAX, MANDOCERR_MAX }; @@ -192,6 +192,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { /* related to document structure and macros */ NULL, + "input too large", "input stack limit exceeded, infinite loop?", "skipping bad character", "skipping unknown macro", @@ -215,10 +216,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "skipping all arguments", "skipping excess arguments", "divide by zero", - - "generic fatal error", - - "input too large", }; static const char * const mandoclevels[MANDOCLEVEL_MAX] = { @@ -545,14 +542,6 @@ rerun: } /* - * If we encounter errors in the recursive parse, make - * sure we don't continue parsing. - */ - - if (MANDOCLEVEL_FATAL <= curp->file_status) - break; - - /* * If input parsers have not been allocated, do so now. * We keep these instanced between parsers, but set them * locally per parse routine since we can use different @@ -623,10 +612,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, if (S_ISREG(st.st_mode)) { if (st.st_size >= (1U << 31)) { - curp->file_status = MANDOCLEVEL_FATAL; - if (curp->mmsg) - (*curp->mmsg)(MANDOCERR_TOOLARGE, - curp->file_status, file, 0, 0, NULL); + mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL); return(0); } *with_mmap = 1; @@ -649,11 +635,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd, for (;;) { if (off == fb->sz) { if (fb->sz == (1U << 31)) { - curp->file_status = MANDOCLEVEL_FATAL; - if (curp->mmsg) - (*curp->mmsg)(MANDOCERR_TOOLARGE, - curp->file_status, - file, 0, 0, NULL); + mandoc_msg(MANDOCERR_TOOLARGE, curp, + 0, 0, NULL); break; } resize_buf(fb, 65536); @@ -679,9 +662,6 @@ static void mparse_end(struct mparse *curp) { - if (MANDOCLEVEL_FATAL <= curp->file_status) - return; - if (curp->mdoc == NULL && curp->man == NULL && curp->sodest == NULL) { @@ -695,17 +675,10 @@ mparse_end(struct mparse *curp) curp->man = curp->pman; } } - - if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { - assert(MANDOCLEVEL_FATAL <= curp->file_status); - return; - } - - if (curp->man && ! man_endparse(curp->man)) { - assert(MANDOCLEVEL_FATAL <= curp->file_status); - return; - } - + if (curp->mdoc) + mdoc_endparse(curp->mdoc); + if (curp->man) + man_endparse(curp->man); roff_endparse(curp->roff); } @@ -742,7 +715,7 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) mparse_buf_r(curp, blk, offset, 1); - if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status) + if (--recursion_depth == 0) mparse_end(curp); curp->primary = svprimary; @@ -889,8 +862,6 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg, { struct mparse *curp; - assert(wlevel <= MANDOCLEVEL_FATAL); - curp = mandoc_calloc(1, sizeof(struct mparse)); curp->options = options; @@ -987,7 +958,7 @@ mandoc_msg(enum mandocerr er, struct mparse *m, { enum mandoclevel level; - level = MANDOCLEVEL_FATAL; + level = MANDOCLEVEL_ERROR; while (er < mandoclimits[level]) level--; |