=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/mandoc/mandocdb.c,v retrieving revision 1.212 retrieving revision 1.213 diff -c -r1.212 -r1.213 *** src/usr.bin/mandoc/mandocdb.c 2019/05/03 18:16:57 1.212 --- src/usr.bin/mandoc/mandocdb.c 2020/01/25 22:59:14 1.213 *************** *** 1,7 **** ! /* $OpenBSD: mandocdb.c,v 1.212 2019/05/03 18:16:57 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons ! * Copyright (c) 2011-2019 Ingo Schwarze * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any --- 1,7 ---- ! /* $OpenBSD: mandocdb.c,v 1.213 2020/01/25 22:59:14 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons ! * Copyright (c) 2011-2020 Ingo Schwarze * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any *************** *** 164,169 **** --- 164,170 ---- static int exitcode; /* to be returned by main */ static enum op op; /* operational mode */ static char basedir[PATH_MAX]; /* current base directory */ + static size_t basedir_len; /* strlen(basedir) */ 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 */ *************** *** 318,324 **** * clobber each other. */ #define CHECKOP(_op, _ch) do \ ! if (OP_DEFAULT != (_op)) { \ warnx("-%c: Conflicting option", (_ch)); \ goto usage; \ } while (/*CONSTCOND*/0) --- 319,325 ---- * clobber each other. */ #define CHECKOP(_op, _ch) do \ ! if ((_op) != OP_DEFAULT) { \ warnx("-%c: Conflicting option", (_ch)); \ goto usage; \ } while (/*CONSTCOND*/0) *************** *** 327,333 **** path_arg = NULL; op = OP_DEFAULT; ! while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v"))) switch (ch) { case 'a': use_all = 1; --- 328,334 ---- path_arg = NULL; op = OP_DEFAULT; ! while ((ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")) != -1) switch (ch) { case 'a': use_all = 1; *************** *** 355,361 **** mparse_options |= MPARSE_QUICK; break; case 'T': ! if (strcmp(optarg, "utf8")) { warnx("-T%s: Unsupported output format", optarg); goto usage; --- 356,362 ---- mparse_options |= MPARSE_QUICK; break; case 'T': ! if (strcmp(optarg, "utf8") != 0) { warnx("-T%s: Unsupported output format", optarg); goto usage; *************** *** 390,396 **** } } ! if (OP_CONFFILE == op && argc > 0) { warnx("-C: Too many arguments"); goto usage; } --- 391,397 ---- } } ! if (op == OP_CONFFILE && argc > 0) { warnx("-C: Too many arguments"); goto usage; } *************** *** 401,413 **** mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); ! if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) { /* * Most of these deal with a specific directory. * Jump into that directory first. */ ! if (OP_TEST != op && 0 == set_basedir(path_arg, 1)) goto out; dba = nodb ? dba_new(128) : dba_read(MANDOC_DB); --- 402,414 ---- mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); ! if (op == OP_UPDATE || op == OP_DELETE || op == OP_TEST) { /* * Most of these deal with a specific directory. * Jump into that directory first. */ ! if (op != OP_TEST && set_basedir(path_arg, 1) == 0) goto out; dba = nodb ? dba_new(128) : dba_read(MANDOC_DB); *************** *** 428,438 **** " from scratch", strerror(errno)); exitcode = (int)MANDOCLEVEL_OK; op = OP_DEFAULT; ! if (0 == treescan()) goto out; dba = dba_new(128); } ! if (OP_DELETE != op) mpages_merge(dba, mp); if (nodb == 0) dbwrite(dba); --- 429,439 ---- " from scratch", strerror(errno)); exitcode = (int)MANDOCLEVEL_OK; op = OP_DEFAULT; ! if (treescan() == 0) goto out; dba = dba_new(128); } ! if (op != OP_DELETE) mpages_merge(dba, mp); if (nodb == 0) dbwrite(dba); *************** *** 466,472 **** sz = strlen(conf.manpath.paths[j]); if (sz && conf.manpath.paths[j][sz - 1] == '/') conf.manpath.paths[j][--sz] = '\0'; ! if (0 == sz) continue; if (j) { --- 467,473 ---- sz = strlen(conf.manpath.paths[j]); if (sz && conf.manpath.paths[j][sz - 1] == '/') conf.manpath.paths[j][--sz] = '\0'; ! if (sz == 0) continue; if (j) { *************** *** 476,484 **** offsetof(struct mlink, file)); } ! if ( ! set_basedir(conf.manpath.paths[j], argc > 0)) continue; ! if (0 == treescan()) continue; dba = dba_new(128); mpages_merge(dba, mp); --- 477,485 ---- offsetof(struct mlink, file)); } ! if (set_basedir(conf.manpath.paths[j], argc > 0) == 0) continue; ! if (treescan() == 0) continue; dba = dba_new(128); mpages_merge(dba, mp); *************** *** 578,584 **** say(path, "&realpath"); continue; } ! if (strstr(buf, basedir) != buf) { if (warnings) say("", "%s: outside base directory", buf); continue; --- 579,585 ---- say(path, "&realpath"); continue; } ! if (strncmp(buf, basedir, basedir_len) != 0) { if (warnings) say("", "%s: outside base directory", buf); continue; *************** *** 752,758 **** assert(use_all); ! if (0 == strncmp(file, "./", 2)) file += 2; /* --- 753,759 ---- assert(use_all); ! if (strncmp(file, "./", 2) == 0) file += 2; /* *************** *** 762,772 **** * we want to use the orginal file name, while for * regular files, we want to use the real path. */ ! if (-1 == lstat(file, &st)) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&lstat"); return; ! } else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "Not a regular file"); return; --- 763,773 ---- * we want to use the orginal file name, while for * regular files, we want to use the real path. */ ! if (lstat(file, &st) == -1) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&lstat"); return; ! } else if ((st.st_mode & (S_IFREG | S_IFLNK)) == 0) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "Not a regular file"); return; *************** *** 776,791 **** * We have to resolve the file name to the real path * in any case for the base directory check. */ ! if (NULL == realpath(file, buf)) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&realpath"); return; } ! if (OP_TEST == op) start = buf; ! else if (strstr(buf, basedir) == buf) ! start = buf + strlen(basedir); else { exitcode = (int)MANDOCLEVEL_BADARG; say("", "%s: outside base directory", buf); --- 777,792 ---- * We have to resolve the file name to the real path * in any case for the base directory check. */ ! if (realpath(file, buf) == NULL) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&realpath"); return; } ! if (op == OP_TEST) start = buf; ! else if (strncmp(buf, basedir, basedir_len) == 0) ! start = buf + basedir_len; else { exitcode = (int)MANDOCLEVEL_BADARG; say("", "%s: outside base directory", buf); *************** *** 801,808 **** * Note the stat(2) can still fail if the link target * doesn't exist. */ ! if (S_IFLNK & st.st_mode) { ! if (-1 == stat(buf, &st)) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&stat"); return; --- 802,809 ---- * Note the stat(2) can still fail if the link target * doesn't exist. */ ! if (st.st_mode & S_IFLNK) { ! if (stat(buf, &st) == -1) { exitcode = (int)MANDOCLEVEL_BADARG; say(file, "&stat"); return; *************** *** 812,819 **** return; } start = buf; ! if (OP_TEST != op && strstr(buf, basedir) == buf) ! start += strlen(basedir); } mlink = mandoc_calloc(1, sizeof(struct mlink)); --- 813,820 ---- return; } start = buf; ! if (op != OP_TEST && strncmp(buf, basedir, basedir_len) == 0) ! start += basedir_len; } mlink = mandoc_calloc(1, sizeof(struct mlink)); *************** *** 845,862 **** * If we find one of these and what's underneath is a directory, * assume it's an architecture. */ ! if (NULL != (p = strchr(start, '/'))) { *p++ = '\0'; ! if (0 == strncmp(start, "man", 3)) { mlink->dform = FORM_SRC; mlink->dsec = start + 3; ! } else if (0 == strncmp(start, "cat", 3)) { mlink->dform = FORM_CAT; mlink->dsec = start + 3; } start = p; ! if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) { *p++ = '\0'; mlink->arch = start; start = p; --- 846,863 ---- * If we find one of these and what's underneath is a directory, * assume it's an architecture. */ ! if ((p = strchr(start, '/')) != NULL) { *p++ = '\0'; ! if (strncmp(start, "man", 3) == 0) { mlink->dform = FORM_SRC; mlink->dsec = start + 3; ! } else if (strncmp(start, "cat", 3) == 0) { mlink->dform = FORM_CAT; mlink->dsec = start + 3; } start = p; ! if (mlink->dsec != NULL && (p = strchr(start, '/')) != NULL) { *p++ = '\0'; mlink->arch = start; start = p; *************** *** 868,877 **** * Suffix of `.0' indicates a catpage, `.1-9' is a manpage. */ p = strrchr(start, '\0'); ! while (p-- > start && '/' != *p && '.' != *p) ! /* Loop. */ ; ! if ('.' == *p) { *p++ = '\0'; mlink->fsec = p; } --- 869,878 ---- * Suffix of `.0' indicates a catpage, `.1-9' is a manpage. */ p = strrchr(start, '\0'); ! while (p-- > start && *p != '/' && *p != '.') ! continue; ! if (*p == '.') { *p++ = '\0'; mlink->fsec = p; } *************** *** 881,887 **** * Use the filename portion of the path. */ mlink->name = start; ! if (NULL != (p = strrchr(start, '/'))) { mlink->name = p + 1; *p = '\0'; } --- 882,888 ---- * Use the filename portion of the path. */ mlink->name = start; ! if ((p = strrchr(start, '/')) != NULL) { mlink->name = p + 1; *p = '\0'; } *************** *** 2212,2218 **** static char startdir[PATH_MAX]; static int getcwd_status; /* 1 = ok, 2 = failure */ static int chdir_status; /* 1 = changed directory */ - char *cp; /* * Remember the original working directory, if possible. --- 2213,2218 ---- *************** *** 2221,2228 **** * Do not error out if the current directory is not * searchable: Maybe it won't be needed after all. */ ! if (0 == getcwd_status) { ! if (NULL == getcwd(startdir, sizeof(startdir))) { getcwd_status = 2; (void)strlcpy(startdir, strerror(errno), sizeof(startdir)); --- 2221,2228 ---- * Do not error out if the current directory is not * searchable: Maybe it won't be needed after all. */ ! if (getcwd_status == 0) { ! if (getcwd(startdir, sizeof(startdir)) == NULL) { getcwd_status = 2; (void)strlcpy(startdir, strerror(errno), sizeof(startdir)); *************** *** 2235,2253 **** * Do not use it any longer, not even for messages. */ *basedir = '\0'; /* * If and only if the directory was changed earlier and * the next directory to process is given as a relative path, * first go back, or bail out if that is impossible. */ ! if (chdir_status && '/' != *targetdir) { ! if (2 == getcwd_status) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "getcwd: %s", startdir); return 0; } ! if (-1 == chdir(startdir)) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&chdir %s", startdir); return 0; --- 2235,2254 ---- * Do not use it any longer, not even for messages. */ *basedir = '\0'; + basedir_len = 0; /* * If and only if the directory was changed earlier and * the next directory to process is given as a relative path, * first go back, or bail out if that is impossible. */ ! if (chdir_status && *targetdir != '/') { ! if (getcwd_status == 2) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "getcwd: %s", startdir); return 0; } ! if (chdir(startdir) == -1) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&chdir %s", startdir); return 0; *************** *** 2259,2287 **** * pathname and append a trailing slash, such that * we can reliably check whether files are inside. */ ! if (NULL == realpath(targetdir, basedir)) { if (report_baddir || errno != ENOENT) { exitcode = (int)MANDOCLEVEL_BADARG; say("", "&%s: realpath", targetdir); } return 0; ! } else if (-1 == chdir(basedir)) { if (report_baddir || errno != ENOENT) { exitcode = (int)MANDOCLEVEL_BADARG; say("", "&chdir"); } return 0; } chdir_status = 1; ! cp = strchr(basedir, '\0'); ! if ('/' != cp[-1]) { ! if (cp - basedir >= PATH_MAX - 1) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "Filename too long"); return 0; } ! *cp++ = '/'; ! *cp = '\0'; } return 1; } --- 2260,2292 ---- * pathname and append a trailing slash, such that * we can reliably check whether files are inside. */ ! if (realpath(targetdir, basedir) == NULL) { if (report_baddir || errno != ENOENT) { exitcode = (int)MANDOCLEVEL_BADARG; say("", "&%s: realpath", targetdir); } + *basedir = '\0'; return 0; ! } else if (chdir(basedir) == -1) { if (report_baddir || errno != ENOENT) { exitcode = (int)MANDOCLEVEL_BADARG; say("", "&chdir"); } + *basedir = '\0'; return 0; } chdir_status = 1; ! basedir_len = strlen(basedir); ! if (basedir[basedir_len - 1] != '/') { ! if (basedir_len >= PATH_MAX - 1) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "Filename too long"); + *basedir = '\0'; + basedir_len = 0; return 0; } ! basedir[basedir_len++] = '/'; ! basedir[basedir_len] = '\0'; } return 1; } *************** *** 2292,2306 **** va_list ap; int use_errno; ! if ('\0' != *basedir) fprintf(stderr, "%s", basedir); ! if ('\0' != *basedir && '\0' != *file) fputc('/', stderr); ! if ('\0' != *file) fprintf(stderr, "%s", file); use_errno = 1; ! if (NULL != format) { switch (*format) { case '&': format++; --- 2297,2311 ---- va_list ap; int use_errno; ! if (*basedir != '\0') fprintf(stderr, "%s", basedir); ! if (*basedir != '\0' && *file != '\0') fputc('/', stderr); ! if (*file != '\0') fprintf(stderr, "%s", file); use_errno = 1; ! if (format != NULL) { switch (*format) { case '&': format++; *************** *** 2313,2327 **** break; } } ! if (NULL != format) { ! if ('\0' != *basedir || '\0' != *file) fputs(": ", stderr); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } if (use_errno) { ! if ('\0' != *basedir || '\0' != *file || NULL != format) fputs(": ", stderr); perror(NULL); } else --- 2318,2332 ---- break; } } ! if (format != NULL) { ! if (*basedir != '\0' || *file != '\0') fputs(": ", stderr); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } if (use_errno) { ! if (*basedir != '\0' || *file != '\0' || format != NULL) fputs(": ", stderr); perror(NULL); } else