version 1.249, 2017/05/05 15:17:32 |
version 1.258, 2018/02/23 18:25:57 |
|
|
#include "config.h" |
#include "config.h" |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/mman.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/wait.h> |
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
Line 139 static void parse_mdoc(struct mpage *, const struct r |
|
Line 139 static void parse_mdoc(struct mpage *, const struct r |
|
const struct roff_node *); |
const struct roff_node *); |
static int parse_mdoc_head(struct mpage *, const struct roff_meta *, |
static int parse_mdoc_head(struct mpage *, const struct roff_meta *, |
const struct roff_node *); |
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 *, |
static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, |
const struct roff_node *); |
const struct roff_node *); |
static void parse_mdoc_fname(struct mpage *, const struct roff_node *); |
static void parse_mdoc_fname(struct mpage *, const struct roff_node *); |
Line 207 static const struct mdoc_handler __mdocs[MDOC_MAX - MD |
|
Line 209 static const struct mdoc_handler __mdocs[MDOC_MAX - MD |
|
{ NULL, TYPE_Er, 0 }, /* Er */ |
{ NULL, TYPE_Er, 0 }, /* Er */ |
{ NULL, TYPE_Ev, 0 }, /* Ev */ |
{ NULL, TYPE_Ev, 0 }, /* Ev */ |
{ NULL, 0, 0 }, /* Ex */ |
{ NULL, 0, 0 }, /* Ex */ |
{ NULL, TYPE_Fa, 0 }, /* Fa */ |
{ parse_mdoc_Fa, 0, 0 }, /* Fa */ |
{ parse_mdoc_Fd, 0, 0 }, /* Fd */ |
{ parse_mdoc_Fd, 0, 0 }, /* Fd */ |
{ NULL, TYPE_Fl, 0 }, /* Fl */ |
{ NULL, TYPE_Fl, 0 }, /* Fl */ |
{ parse_mdoc_Fn, 0, 0 }, /* Fn */ |
{ 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_Ic, 0 }, /* Ic */ |
{ NULL, TYPE_In, 0 }, /* In */ |
{ NULL, TYPE_In, 0 }, /* In */ |
{ NULL, TYPE_Li, 0 }, /* Li */ |
{ NULL, TYPE_Li, 0 }, /* Li */ |
Line 319 mandocdb(int argc, char *argv[]) |
|
Line 321 mandocdb(int argc, char *argv[]) |
|
int ch, i; |
int ch, i; |
|
|
#if HAVE_PLEDGE |
#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"); |
warn("pledge"); |
return (int)MANDOCLEVEL_SYSERR; |
return (int)MANDOCLEVEL_SYSERR; |
} |
} |
Line 420 mandocdb(int argc, char *argv[]) |
|
Line 422 mandocdb(int argc, char *argv[]) |
|
|
|
exitcode = (int)MANDOCLEVEL_OK; |
exitcode = (int)MANDOCLEVEL_OK; |
mchars_alloc(); |
mchars_alloc(); |
mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, NULL); |
mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL, |
|
MANDOC_OS_OTHER, NULL); |
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); |
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); |
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); |
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); |
|
|
Line 439 mandocdb(int argc, char *argv[]) |
|
Line 442 mandocdb(int argc, char *argv[]) |
|
* The existing database is usable. Process |
* The existing database is usable. Process |
* all files specified on the command-line. |
* 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; |
use_all = 1; |
for (i = 0; i < argc; i++) |
for (i = 0; i < argc; i++) |
filescan(argv[i]); |
filescan(argv[i]); |
Line 1381 parse_cat(struct mpage *mpage, int fd) |
|
Line 1375 parse_cat(struct mpage *mpage, int fd) |
|
plen -= 2; |
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); |
fclose(stream); |
free(title); |
free(title); |
} |
} |
Line 1525 parse_man(struct mpage *mpage, const struct roff_meta |
|
Line 1524 parse_man(struct mpage *mpage, const struct roff_meta |
|
while (' ' == *start) |
while (' ' == *start) |
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); |
free(title); |
return; |
return; |
} |
} |
Line 1571 parse_mdoc(struct mpage *mpage, const struct roff_meta |
|
Line 1575 parse_mdoc(struct mpage *mpage, const struct roff_meta |
|
} |
} |
|
|
static int |
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, |
parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta, |
const struct roff_node *n) |
const struct roff_node *n) |
{ |
{ |
|
|
parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, |
parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, |
const struct roff_node *n) |
const struct roff_node *n) |
{ |
{ |
|
uint64_t mask; |
|
|
if (n->child == NULL) |
if (n->child == NULL) |
return 0; |
return 0; |
|
|
parse_mdoc_fname(mpage, n->child); |
parse_mdoc_fname(mpage, n->child); |
|
|
for (n = n->child->next; n != NULL; n = n->next) |
n = n->child->next; |
if (n->type == ROFFT_TEXT) |
if (n != NULL && n->type == ROFFT_TEXT) { |
putkey(mpage, n->string, TYPE_Fa); |
mask = TYPE_Fa; |
|
if (n->sec == SEC_SYNOPSIS) |
|
mask |= TYPE_Vt; |
|
putmdockey(mpage, n, mask, 0); |
|
} |
|
|
return 0; |
return 0; |
} |
} |
Line 2118 dbprune(struct dba *dba) |
|
Line 2141 dbprune(struct dba *dba) |
|
static void |
static void |
dbwrite(struct dba *dba) |
dbwrite(struct dba *dba) |
{ |
{ |
char tfn[32]; |
struct stat sb1, sb2; |
int status; |
char tfn[33], *cp1, *cp2; |
pid_t child; |
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 (dba_write(MANDOC_DB "~", dba) != -1) { |
if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { |
if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
Line 2131 dbwrite(struct dba *dba) |
|
Line 2172 dbwrite(struct dba *dba) |
|
return; |
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)); |
(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); |
if (mkdtemp(tfn) == NULL) { |
if (mkdtemp(tfn) == NULL) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say("", "&%s", tfn); |
say("", "&%s", tfn); |
return; |
return; |
} |
} |
|
cp1 = cp2 = MAP_FAILED; |
|
fd1 = fd2 = -1; |
(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); |
(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); |
if (dba_write(tfn, dba) == -1) { |
if (dba_write(tfn, dba) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tfn, "&dba_write"); |
say(tfn, "&dba_write"); |
goto out; |
goto err; |
} |
} |
|
if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) { |
switch (child = fork()) { |
say(MANDOC_DB, "&open"); |
case -1: |
goto err; |
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 (waitpid(child, &status, 0) == -1) { |
if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(tfn, "&open"); |
say("", "&wait cmp"); |
goto err; |
} 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 (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: |
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'; |
*strrchr(tfn, '/') = '\0'; |
switch (child = fork()) { |
rmdir(tfn); |
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); |
|
} |
|
} |
} |
|
|
static int |
static int |