=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.206 retrieving revision 1.220.2.3 diff -u -p -r1.206 -r1.220.2.3 --- mandoc/mandocdb.c 2015/11/06 16:30:33 1.206 +++ mandoc/mandocdb.c 2016/10/20 18:52:27 1.220.2.3 @@ -1,7 +1,8 @@ -/* $Id: mandocdb.c,v 1.206 2015/11/06 16:30:33 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.220.2.3 2016/10/20 18:52:27 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2011-2015 Ingo Schwarze + * Copyright (c) 2011-2016 Ingo Schwarze + * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,7 +24,9 @@ #include #include +#if HAVE_ERR #include +#endif #include #include #if HAVE_FTS @@ -31,8 +34,10 @@ #else #include "compat_fts.h" #endif -#include #include +#if HAVE_SANDBOX_INIT +#include +#endif #include #include #include @@ -99,6 +104,7 @@ struct mpage { char *arch; /* architecture from file content */ char *title; /* title from file content */ char *desc; /* description from file content */ + struct mpage *next; /* singly linked list */ struct mlink *mlinks; /* singly linked list */ int form; /* format from file content */ int name_head_done; @@ -135,6 +141,9 @@ struct mdoc_handler { uint64_t mask; /* set unless handler returns 0 */ }; + +int mandocdb(int, char *[]); + static void dbclose(int); static void dbadd(struct mpage *); static void dbadd_mlink(const struct mlink *mlink); @@ -142,6 +151,11 @@ static void dbadd_mlink_name(const struct mlink *mlin static int dbopen(int); static void dbprune(void); static void filescan(const char *); +#if HAVE_FTS_COMPARE_CONST +static int fts_compare(const FTSENT *const *, const FTSENT *const *); +#else +static int fts_compare(const FTSENT **, const FTSENT **); +#endif static void mlink_add(struct mlink *, const struct stat *); static void mlink_check(struct mpage *, struct mlink *); static void mlink_free(struct mlink *); @@ -154,8 +168,6 @@ static void parse_man(struct mpage *, const struct ro const struct roff_node *); static void parse_mdoc(struct mpage *, const struct roff_meta *, const struct roff_node *); -static int parse_mdoc_body(struct mpage *, const struct roff_meta *, - const struct roff_node *); static int parse_mdoc_head(struct mpage *, const struct roff_meta *, const struct roff_node *); static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, @@ -171,6 +183,8 @@ static int parse_mdoc_Nm(struct mpage *, const struct const struct roff_node *); static int parse_mdoc_Sh(struct mpage *, const struct roff_meta *, const struct roff_node *); +static int parse_mdoc_Va(struct mpage *, const struct roff_meta *, + const struct roff_node *); static int parse_mdoc_Xr(struct mpage *, const struct roff_meta *, const struct roff_node *); static void putkey(const struct mpage *, char *, uint64_t); @@ -178,7 +192,8 @@ static void putkeys(const struct mpage *, char *, siz static void putmdockey(const struct mpage *, const struct roff_node *, uint64_t); static int render_string(char **, size_t *); -static void say(const char *, const char *, ...); +static void say(const char *, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); static int set_basedir(const char *, int); static int treescan(void); static size_t utf8(unsigned int, char [7]); @@ -193,6 +208,7 @@ static int write_utf8; /* write UTF-8 output; else A static int exitcode; /* to be returned by main */ static enum op op; /* operational mode */ static char basedir[PATH_MAX]; /* current base directory */ +static struct mpage *mpage_head; /* list of distinct manual pages */ static struct ohash mpages; /* table of distinct manual pages */ static struct ohash mlinks; /* table of directory entries */ static struct ohash names; /* table of all names */ @@ -240,8 +256,8 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = { { NULL, TYPE_Pa }, /* Pa */ { NULL, 0 }, /* Rv */ { NULL, TYPE_St }, /* St */ - { NULL, TYPE_Va }, /* Va */ - { parse_mdoc_body, TYPE_Va }, /* Vt */ + { parse_mdoc_Va, TYPE_Va }, /* Va */ + { parse_mdoc_Va, TYPE_Vt }, /* Vt */ { parse_mdoc_Xr, 0 }, /* Xr */ { NULL, 0 }, /* %A */ { NULL, 0 }, /* %B */ @@ -337,6 +353,20 @@ mandocdb(int argc, char *argv[]) size_t j, sz; int ch, i; +#if HAVE_PLEDGE + if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) { + warn("pledge"); + return (int)MANDOCLEVEL_SYSERR; + } +#endif + +#if HAVE_SANDBOX_INIT + if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) { + warnx("sandbox_init"); + return (int)MANDOCLEVEL_SYSERR; + } +#endif + memset(&conf, 0, sizeof(conf)); memset(stmts, 0, STMT__MAX * sizeof(sqlite3_stmt *)); @@ -410,6 +440,15 @@ mandocdb(int argc, char *argv[]) argc -= optind; argv += optind; +#if HAVE_PLEDGE + if (nodb) { + if (pledge("stdio rpath", NULL) == -1) { + warn("pledge"); + return (int)MANDOCLEVEL_SYSERR; + } + } +#endif + if (OP_CONFFILE == op && argc > 0) { warnx("-C: Too many arguments"); goto usage; @@ -435,6 +474,15 @@ 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]); @@ -536,6 +584,20 @@ usage: } /* + * To get a singly linked list in alpha order while inserting entries + * at the beginning, process directory entries in reverse alpha order. + */ +static int +#if HAVE_FTS_COMPARE_CONST +fts_compare(const FTSENT *const *a, const FTSENT *const *b) +#else +fts_compare(const FTSENT **a, const FTSENT **b) +#endif +{ + return -strcmp((*a)->fts_name, (*b)->fts_name); +} + +/* * Scan a directory tree rooted at "basedir" for manpages. * We use fts(), scanning directory parts along the way for clues to our * section and architecture. @@ -547,7 +609,7 @@ usage: * or * [./]cat
[/]/.0 * - * TODO: accomodate for multi-language directories. + * TODO: accommodate for multi-language directories. */ static int treescan(void) @@ -564,8 +626,8 @@ treescan(void) argv[0] = "."; argv[1] = (char *)NULL; - f = fts_open((char * const *)argv, - FTS_PHYSICAL | FTS_NOCHDIR, NULL); + f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, + fts_compare); if (f == NULL) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&fts_open"); @@ -930,6 +992,8 @@ mlink_add(struct mlink *mlink, const struct stat *st) mpage = mandoc_calloc(1, sizeof(struct mpage)); mpage->inodev.st_ino = inodev.st_ino; mpage->inodev.st_dev = inodev.st_dev; + mpage->next = mpage_head; + mpage_head = mpage; ohash_insert(&mpages, slot, mpage); } else mlink->next = mpage->mlinks; @@ -953,20 +1017,18 @@ mpages_free(void) { struct mpage *mpage; struct mlink *mlink; - unsigned int slot; - mpage = ohash_first(&mpages, &slot); - while (NULL != mpage) { - while (NULL != (mlink = mpage->mlinks)) { + while ((mpage = mpage_head) != NULL) { + while ((mlink = mpage->mlinks) != NULL) { mpage->mlinks = mlink->next; mlink_free(mlink); } + mpage_head = mpage->next; free(mpage->sec); free(mpage->arch); free(mpage->title); free(mpage->desc); free(mpage); - mpage = ohash_next(&mpages, &slot); } } @@ -1087,18 +1149,14 @@ mpages_merge(struct mparse *mp) char *sodest; char *cp; int fd; - unsigned int pslot; if ( ! nodb) SQL_EXEC("BEGIN TRANSACTION"); - mpage = ohash_first(&mpages, &pslot); - while (mpage != NULL) { + for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) { mlinks_undupe(mpage); - if ((mlink = mpage->mlinks) == NULL) { - mpage = ohash_next(&mpages, &pslot); + if ((mlink = mpage->mlinks) == NULL) continue; - } name_mask = NAME_MASK; mandoc_ohash_init(&names, 4, offsetof(struct str, key)); @@ -1107,8 +1165,7 @@ mpages_merge(struct mparse *mp) man = NULL; sodest = NULL; - mparse_open(mp, &fd, mlink->file); - if (fd == -1) { + if ((fd = mparse_open(mp, mlink->file)) == -1) { say(mlink->file, "&open"); goto nextpage; } @@ -1119,6 +1176,7 @@ mpages_merge(struct mparse *mp) */ if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { mparse_readfd(mp, fd, mlink->file); + close(fd); mparse_result(mp, &man, &sodest); } @@ -1220,7 +1278,6 @@ mpages_merge(struct mparse *mp) nextpage: ohash_delete(&strings); ohash_delete(&names); - mpage = ohash_next(&mpages, &pslot); } if (0 == nodb) @@ -1267,7 +1324,9 @@ parse_cat(struct mpage *mpage, int fd) { FILE *stream; char *line, *p, *title; - size_t len, plen, titlesz; + size_t linesz, plen, titlesz; + ssize_t len; + int offs; stream = (-1 == fd) ? fopen(mpage->mlinks->file, "r") : @@ -1280,10 +1339,13 @@ parse_cat(struct mpage *mpage, int fd) return; } + line = NULL; + linesz = 0; + /* Skip to first blank line. */ - while (NULL != (line = fgetln(stream, &len))) - if ('\n' == *line) + while (getline(&line, &linesz, stream) != -1) + if (*line == '\n') break; /* @@ -1291,8 +1353,8 @@ parse_cat(struct mpage *mpage, int fd) * is the first section header. Skip to it. */ - while (NULL != (line = fgetln(stream, &len))) - if ('\n' != *line && ' ' != *line) + while (getline(&line, &linesz, stream) != -1) + if (*line != '\n' && *line != ' ') break; /* @@ -1305,20 +1367,20 @@ parse_cat(struct mpage *mpage, int fd) titlesz = 0; title = NULL; - while (NULL != (line = fgetln(stream, &len))) { - if (' ' != *line || '\n' != line[len - 1]) + while ((len = getline(&line, &linesz, stream)) != -1) { + if (*line != ' ') break; - while (len > 0 && isspace((unsigned char)*line)) { - line++; - len--; - } - if (1 == len) + offs = 0; + while (isspace((unsigned char)line[offs])) + offs++; + if (line[offs] == '\0') continue; - title = mandoc_realloc(title, titlesz + len); - memcpy(title + titlesz, line, len); - titlesz += len; + title = mandoc_realloc(title, titlesz + len - offs); + memcpy(title + titlesz, line + offs, len - offs); + titlesz += len - offs; title[titlesz - 1] = ' '; } + free(line); /* * If no page content can be found, or the input line @@ -1336,8 +1398,7 @@ parse_cat(struct mpage *mpage, int fd) return; } - title = mandoc_realloc(title, titlesz + 1); - title[titlesz] = '\0'; + title[titlesz - 1] = '\0'; /* * Skip to the first dash. @@ -1415,7 +1476,7 @@ parse_man(struct mpage *mpage, const struct roff_meta char byte; size_t sz; - if (NULL == n) + if (n == NULL) return; /* @@ -1427,13 +1488,12 @@ parse_man(struct mpage *mpage, const struct roff_meta if (n->type == ROFFT_BODY && n->tok == MAN_SH) { body = n; - assert(body->parent); - if (NULL != (head = body->parent->head) && - 1 == head->nchild && - NULL != (head = (head->child)) && + if ((head = body->parent->head) != NULL && + (head = head->child) != NULL && + head->next == NULL && head->type == ROFFT_TEXT && - 0 == strcmp(head->string, "NAME") && - NULL != body->child) { + strcmp(head->string, "NAME") == 0 && + body->child != NULL) { /* * Suck the entire NAME section into memory. @@ -1658,6 +1718,31 @@ parse_mdoc_Fo(struct mpage *mpage, const struct roff_m } static int +parse_mdoc_Va(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + char *cp; + + if (n->type != ROFFT_ELEM && n->type != ROFFT_BODY) + return 0; + + if (n->child != NULL && + n->child->next == NULL && + n->child->type == ROFFT_TEXT) + return 1; + + cp = NULL; + deroff(&cp, n); + if (cp != NULL) { + putkey(mpage, cp, TYPE_Vt | (n->tok == MDOC_Va || + n->type == ROFFT_BODY ? TYPE_Va : 0)); + free(cp); + } + + return 0; +} + +static int parse_mdoc_Xr(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { @@ -1703,7 +1788,7 @@ parse_mdoc_Nm(struct mpage *mpage, const struct roff_m if ( ! (mpage->name_head_done || n->child == NULL || n->child->string == NULL || strcasecmp(n->child->string, meta->title))) { - putkey(mpage, n->child->string, ROFFT_HEAD); + putkey(mpage, n->child->string, NAME_HEAD); mpage->name_head_done = 1; } return 0; @@ -1725,14 +1810,6 @@ parse_mdoc_head(struct mpage *mpage, const struct roff return n->type == ROFFT_HEAD; } -static int -parse_mdoc_body(struct mpage *mpage, const struct roff_meta *meta, - const struct roff_node *n) -{ - - return n->type == ROFFT_BODY; -} - /* * Add a string to the hash table for the current manual. * Each string has a bitmask telling which macros it belongs to. @@ -1759,7 +1836,7 @@ putkeys(const struct mpage *mpage, char *cp, size_t sz name_mask &= ~NAME_FIRST; if (debug > 1) say(mpage->mlinks->file, - "Adding name %*s, bits=%d", sz, cp, v); + "Adding name %*s, bits=0x%llx", (int)sz, cp, v); } else { htab = &strings; if (debug > 1) @@ -1767,7 +1844,7 @@ putkeys(const struct mpage *mpage, char *cp, size_t sz if ((uint64_t)1 << i & v) say(mpage->mlinks->file, "Adding key %s=%*s", - mansearch_keynames[i], sz, cp); + mansearch_keynames[i], (int)sz, cp); } end = cp + sz;