=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/mandoc/main.c,v retrieving revision 1.207 retrieving revision 1.208 diff -u -r1.207 -r1.208 --- src/usr.bin/mandoc/main.c 2018/04/13 19:55:13 1.207 +++ src/usr.bin/mandoc/main.c 2018/04/19 16:25:11 1.208 @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.207 2018/04/13 19:55:13 schwarze Exp $ */ +/* $OpenBSD: main.c,v 1.208 2018/04/19 16:25:11 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze @@ -126,7 +126,7 @@ size_t i, sz; int prio, best_prio; enum outmode outmode; - int fd; + int fd, startdir; int show_usage; int options; int use_pager; @@ -358,15 +358,34 @@ argc, argv, &res, &sz)) usage(search.argmode); - if (sz == 0) { - if (search.argmode == ARG_NAME) - fs_search(&search, &conf.manpath, - argc, argv, &res, &sz); - else - warnx("nothing appropriate"); + if (sz == 0 && search.argmode == ARG_NAME) + fs_search(&search, &conf.manpath, + argc, argv, &res, &sz); + + if (search.argmode == ARG_NAME) { + for (c = 0; c < argc; c++) { + if (strchr(argv[c], '/') == NULL) + continue; + if (access(argv[c], R_OK) == -1) { + warn("%s", argv[c]); + continue; + } + res = mandoc_reallocarray(res, + sz + 1, sizeof(*res)); + res[sz].file = mandoc_strdup(argv[c]); + res[sz].names = NULL; + res[sz].output = NULL; + res[sz].ipath = SIZE_MAX; + res[sz].bits = 0; + res[sz].sec = 10; + res[sz].form = FORM_SRC; + sz++; + } } if (sz == 0) { + if (search.argmode != ARG_NAME) + warnx("nothing appropriate"); rc = MANDOCLEVEL_BADARG; goto out; } @@ -448,7 +467,29 @@ parse(&curp, STDIN_FILENO, ""); } + /* + * Remember the original working directory, if possible. + * This will be needed if some names on the command line + * are page names and some are relative file names. + * Do not error out if the current directory is not + * readable: Maybe it won't be needed after all. + */ + startdir = open(".", O_RDONLY | O_DIRECTORY); + while (argc > 0) { + + /* + * Changing directories is not needed in ARG_FILE mode. + * Do it on a best-effort basis. Even in case of + * failure, some functionality may still work. + */ + if (resp != NULL) { + if (resp->ipath != SIZE_MAX) + (void)chdir(conf.manpath.paths[resp->ipath]); + else if (startdir != -1) + (void)fchdir(startdir); + } + fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv); if (fd != -1) { if (use_pager) { @@ -458,11 +499,9 @@ if (resp == NULL) parse(&curp, fd, *argv); - else if (resp->form == FORM_SRC) { - /* For .so only; ignore failure. */ - (void)chdir(conf.manpath.paths[resp->ipath]); + else if (resp->form == FORM_SRC) parse(&curp, fd, resp->file); - } else + else passthrough(resp->file, fd, conf.output.synopsisonly); @@ -495,6 +534,10 @@ if (--argc) mparse_reset(curp.mp); } + if (startdir != -1) { + (void)fchdir(startdir); + close(startdir); + } if (curp.outdata != NULL) { switch (curp.outtype) { @@ -715,7 +758,8 @@ cfg->firstmatch) return 1; } - if (res != NULL && *ressz == lastsz) + if (res != NULL && *ressz == lastsz && + strchr(*argv, '/') == NULL) warnx("No entry for %s in the manual.", *argv); lastsz = *ressz; argv++;