=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.249 retrieving revision 1.261 diff -u -p -r1.249 -r1.261 --- mandoc/mandocdb.c 2017/05/05 15:17:32 1.249 +++ mandoc/mandocdb.c 2018/12/14 01:18:26 1.261 @@ -1,7 +1,7 @@ -/* $Id: mandocdb.c,v 1.249 2017/05/05 15:17:32 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.261 2018/12/14 01:18:26 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2011-2017 Ingo Schwarze + * Copyright (c) 2011-2018 Ingo Schwarze * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any @@ -19,8 +19,8 @@ #include "config.h" #include +#include #include -#include #include #include @@ -52,6 +52,7 @@ #include "roff.h" #include "mdoc.h" #include "man.h" +#include "mandoc_parse.h" #include "manconf.h" #include "mansearch.h" #include "dba_array.h" @@ -139,6 +140,8 @@ static void parse_mdoc(struct mpage *, const struct r const struct roff_node *); static int parse_mdoc_head(struct mpage *, const struct roff_meta *, const struct roff_node *); +static int parse_mdoc_Fa(struct mpage *, const struct roff_meta *, + const struct roff_node *); static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, const struct roff_node *); static void parse_mdoc_fname(struct mpage *, const struct roff_node *); @@ -183,7 +186,7 @@ static struct ohash names; /* table of all names */ static struct ohash strings; /* table of all strings */ static uint64_t name_mask; -static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = { { NULL, 0, NODE_NOPRT }, /* Dd */ { NULL, 0, NODE_NOPRT }, /* Dt */ { NULL, 0, NODE_NOPRT }, /* Os */ @@ -207,11 +210,11 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MD { NULL, TYPE_Er, 0 }, /* Er */ { NULL, TYPE_Ev, 0 }, /* Ev */ { NULL, 0, 0 }, /* Ex */ - { NULL, TYPE_Fa, 0 }, /* Fa */ + { parse_mdoc_Fa, 0, 0 }, /* Fa */ { parse_mdoc_Fd, 0, 0 }, /* Fd */ { NULL, TYPE_Fl, 0 }, /* Fl */ { parse_mdoc_Fn, 0, 0 }, /* Fn */ - { NULL, TYPE_Ft, 0 }, /* Ft */ + { NULL, TYPE_Ft | TYPE_Vt, 0 }, /* Ft */ { NULL, TYPE_Ic, 0 }, /* Ic */ { NULL, TYPE_In, 0 }, /* In */ { NULL, TYPE_Li, 0 }, /* Li */ @@ -305,7 +308,6 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MD { NULL, 0, 0 }, /* %U */ { NULL, 0, 0 }, /* Ta */ }; -static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd; int @@ -319,7 +321,7 @@ mandocdb(int argc, char *argv[]) int ch, i; #if HAVE_PLEDGE - if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) { + if (pledge("stdio rpath wpath cpath", NULL) == -1) { warn("pledge"); return (int)MANDOCLEVEL_SYSERR; } @@ -420,7 +422,7 @@ mandocdb(int argc, char *argv[]) exitcode = (int)MANDOCLEVEL_OK; mchars_alloc(); - mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, NULL); + mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL); mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); @@ -439,15 +441,6 @@ mandocdb(int argc, char *argv[]) * The existing database is usable. Process * all files specified on the command-line. */ -#if HAVE_PLEDGE - if (!nodb) { - if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1) { - warn("pledge"); - exitcode = (int)MANDOCLEVEL_SYSERR; - goto out; - } - } -#endif use_all = 1; for (i = 0; i < argc; i++) filescan(argv[i]); @@ -1381,7 +1374,12 @@ parse_cat(struct mpage *mpage, int fd) plen -= 2; } - mpage->desc = mandoc_strdup(p); + /* + * Cut off excessive one-line descriptions. + * Bad pages are not worth better heuristics. + */ + + mpage->desc = mandoc_strndup(p, 150); fclose(stream); free(title); } @@ -1525,7 +1523,12 @@ parse_man(struct mpage *mpage, const struct roff_meta while (' ' == *start) start++; - mpage->desc = mandoc_strdup(start); + /* + * Cut off excessive one-line descriptions. + * Bad pages are not worth better heuristics. + */ + + mpage->desc = mandoc_strndup(start, 150); free(title); return; } @@ -1542,25 +1545,28 @@ static void parse_mdoc(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { + const struct mdoc_handler *handler; for (n = n->child; n != NULL; n = n->next) { - if (n->tok == TOKEN_NONE || - n->tok < ROFF_MAX || - n->flags & mdocs[n->tok].taboo) + if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX) continue; assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); + handler = mdoc_handlers + (n->tok - MDOC_Dd); + if (n->flags & handler->taboo) + continue; + switch (n->type) { case ROFFT_ELEM: case ROFFT_BLOCK: case ROFFT_HEAD: case ROFFT_BODY: case ROFFT_TAIL: - if (mdocs[n->tok].fp != NULL && - (*mdocs[n->tok].fp)(mpage, meta, n) == 0) + if (handler->fp != NULL && + (*handler->fp)(mpage, meta, n) == 0) break; - if (mdocs[n->tok].mask) + if (handler->mask) putmdockey(mpage, n->child, - mdocs[n->tok].mask, mdocs[n->tok].taboo); + handler->mask, handler->taboo); break; default: continue; @@ -1571,6 +1577,20 @@ parse_mdoc(struct mpage *mpage, const struct roff_meta } static int +parse_mdoc_Fa(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + uint64_t mask; + + mask = TYPE_Fa; + if (n->sec == SEC_SYNOPSIS) + mask |= TYPE_Vt; + + putmdockey(mpage, n->child, mask, 0); + return 0; +} + +static int parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { @@ -1639,15 +1659,20 @@ static int parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { + uint64_t mask; if (n->child == NULL) return 0; parse_mdoc_fname(mpage, n->child); - for (n = n->child->next; n != NULL; n = n->next) - if (n->type == ROFFT_TEXT) - putkey(mpage, n->string, TYPE_Fa); + n = n->child->next; + if (n != NULL && n->type == ROFFT_TEXT) { + mask = TYPE_Fa; + if (n->sec == SEC_SYNOPSIS) + mask |= TYPE_Vt; + putmdockey(mpage, n, mask, 0); + } return 0; } @@ -2118,10 +2143,28 @@ dbprune(struct dba *dba) static void dbwrite(struct dba *dba) { - char tfn[32]; - int status; - pid_t child; + struct stat sb1, sb2; + char tfn[33], *cp1, *cp2; + off_t i; + int fd1, fd2; + /* + * Do not write empty databases, and delete existing ones + * when makewhatis -u causes them to become empty. + */ + + dba_array_start(dba->pages); + if (dba_array_next(dba->pages) == NULL) { + if (unlink(MANDOC_DB) == -1 && errno != ENOENT) + say(MANDOC_DB, "&unlink"); + return; + } + + /* + * Build the database in a temporary file, + * then atomically move it into place. + */ + if (dba_write(MANDOC_DB "~", dba) != -1) { if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { exitcode = (int)MANDOCLEVEL_SYSERR; @@ -2131,65 +2174,73 @@ dbwrite(struct dba *dba) return; } + /* + * We lack write permission and cannot replace the database + * file, but let's at least check whether the data changed. + */ + (void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); if (mkdtemp(tfn) == NULL) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&%s", tfn); return; } - + cp1 = cp2 = MAP_FAILED; + fd1 = fd2 = -1; (void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); if (dba_write(tfn, dba) == -1) { - exitcode = (int)MANDOCLEVEL_SYSERR; say(tfn, "&dba_write"); - goto out; + goto err; } - - switch (child = fork()) { - case -1: - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&fork cmp"); - return; - case 0: - execlp("cmp", "cmp", "-s", tfn, MANDOC_DB, (char *)NULL); - say("", "&exec cmp"); - exit(0); - default: - break; + if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) { + say(MANDOC_DB, "&open"); + goto err; } - if (waitpid(child, &status, 0) == -1) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&wait cmp"); - } else if (WIFSIGNALED(status)) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "cmp died from signal %d", WTERMSIG(status)); - } else if (WEXITSTATUS(status)) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say(MANDOC_DB, - "Data changed, but cannot replace database"); + if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) { + say(tfn, "&open"); + goto err; } + if (fstat(fd1, &sb1) == -1) { + say(MANDOC_DB, "&fstat"); + goto err; + } + if (fstat(fd2, &sb2) == -1) { + say(tfn, "&fstat"); + goto err; + } + if (sb1.st_size != sb2.st_size) + goto err; + if ((cp1 = mmap(NULL, sb1.st_size, PROT_READ, MAP_PRIVATE, + fd1, 0)) == MAP_FAILED) { + say(MANDOC_DB, "&mmap"); + goto err; + } + if ((cp2 = mmap(NULL, sb2.st_size, PROT_READ, MAP_PRIVATE, + fd2, 0)) == MAP_FAILED) { + say(tfn, "&mmap"); + goto err; + } + for (i = 0; i < sb1.st_size; i++) + if (cp1[i] != cp2[i]) + goto err; + goto out; +err: + exitcode = (int)MANDOCLEVEL_SYSERR; + say(MANDOC_DB, "Data changed, but cannot replace database"); + out: + if (cp1 != MAP_FAILED) + munmap(cp1, sb1.st_size); + if (cp2 != MAP_FAILED) + munmap(cp2, sb2.st_size); + if (fd1 != -1) + close(fd1); + if (fd2 != -1) + close(fd2); + unlink(tfn); *strrchr(tfn, '/') = '\0'; - switch (child = fork()) { - case -1: - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&fork rm"); - return; - case 0: - execlp("rm", "rm", "-rf", tfn, (char *)NULL); - say("", "&exec rm"); - exit((int)MANDOCLEVEL_SYSERR); - default: - break; - } - if (waitpid(child, &status, 0) == -1) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&wait rm"); - } else if (WIFSIGNALED(status) || WEXITSTATUS(status)) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "%s: Cannot remove temporary directory", tfn); - } + rmdir(tfn); } static int