]> git.cameronkatri.com Git - mandoc.git/blobdiff - manpath.c
Do not read past the end of the buffer if an "f" layout font modifier
[mandoc.git] / manpath.c
index 81c5b6a5f073454806e0c9e3782df82f6bdbeb97..e85175e945e8b25f25fc3226ecf9dae51ce61449 100644 (file)
--- a/manpath.c
+++ b/manpath.c
@@ -1,6 +1,6 @@
-/*     $Id: manpath.c,v 1.3 2011/11/24 10:44:56 kristaps Exp $ */
+/*     $Id: manpath.c,v 1.19 2014/11/27 00:30:40 schwarze Exp $ */
 /*
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "mandoc.h"
+#include "mandoc_aux.h"
 #include "manpath.h"
 
 #define MAN_CONF_FILE  "/etc/man.conf"
 #define MAN_CONF_KEY   "_whatdb"
 
-static void     manpath_add(struct manpaths *, const char *);
+static void     manpath_add(struct manpaths *, const char *, int);
+static void     manpath_parseline(struct manpaths *, char *, int);
 
 void
-manpath_parse(struct manpaths *dirs, char *defp, char *auxp) 
+manpath_parse(struct manpaths *dirs, const char *file,
+               char *defp, char *auxp)
 {
+#if HAVE_MANPATH
+       char             cmd[(PATH_MAX * 3) + 20];
+       FILE            *stream;
+       char            *buf;
+       size_t           sz, bsz;
+
+       strlcpy(cmd, "manpath", sizeof(cmd));
+       if (file) {
+               strlcat(cmd, " -C ", sizeof(cmd));
+               strlcat(cmd, file, sizeof(cmd));
+       }
+       if (auxp) {
+               strlcat(cmd, " -m ", sizeof(cmd));
+               strlcat(cmd, auxp, sizeof(cmd));
+       }
+       if (defp) {
+               strlcat(cmd, " -M ", sizeof(cmd));
+               strlcat(cmd, defp, sizeof(cmd));
+       }
+
+       /* Open manpath(1).  Ignore errors. */
+
+       stream = popen(cmd, "r");
+       if (NULL == stream)
+               return;
+
+       buf = NULL;
+       bsz = 0;
+
+       /* Read in as much output as we can. */
+
+       do {
+               buf = mandoc_realloc(buf, bsz + 1024);
+               sz = fread(buf + bsz, 1, 1024, stream);
+               bsz += sz;
+       } while (sz > 0);
+
+       if ( ! ferror(stream) && feof(stream) &&
+                       bsz && '\n' == buf[bsz - 1]) {
+               buf[bsz - 1] = '\0';
+               manpath_parseline(dirs, buf, 1);
+       }
+
+       free(buf);
+       pclose(stream);
+#else
+       char            *insert;
+
+       /* Always prepend -m. */
+       manpath_parseline(dirs, auxp, 1);
+
+       /* If -M is given, it overrides everything else. */
+       if (NULL != defp) {
+               manpath_parseline(dirs, defp, 1);
+               return;
+       }
+
+       /* MANPATH and man.conf(5) cooperate. */
+       defp = getenv("MANPATH");
+       if (NULL == file)
+               file = MAN_CONF_FILE;
+
+       /* No MANPATH; use man.conf(5) only. */
+       if (NULL == defp || '\0' == defp[0]) {
+               manpath_manconf(dirs, file);
+               return;
+       }
+
+       /* Prepend man.conf(5) to MANPATH. */
+       if (':' == defp[0]) {
+               manpath_manconf(dirs, file);
+               manpath_parseline(dirs, defp, 0);
+               return;
+       }
 
-       if (NULL != getenv("MANPATH"))
-               defp = getenv("MANPATH");
+       /* Append man.conf(5) to MANPATH. */
+       if (':' == defp[strlen(defp) - 1]) {
+               manpath_parseline(dirs, defp, 0);
+               manpath_manconf(dirs, file);
+               return;
+       }
 
-       if (NULL == defp)
-               manpath_parseconf(dirs);
-       else
-               manpath_parseline(dirs, defp);
+       /* Insert man.conf(5) into MANPATH. */
+       insert = strstr(defp, "::");
+       if (NULL != insert) {
+               *insert++ = '\0';
+               manpath_parseline(dirs, defp, 0);
+               manpath_manconf(dirs, file);
+               manpath_parseline(dirs, insert + 1, 0);
+               return;
+       }
 
-       manpath_parseline(dirs, auxp);
+       /* MANPATH overrides man.conf(5) completely. */
+       manpath_parseline(dirs, defp, 0);
+#endif
 }
 
 /*
  * Parse a FULL pathname from a colon-separated list of arrays.
  */
-void
-manpath_parseline(struct manpaths *dirs, char *path
+static void
+manpath_parseline(struct manpaths *dirs, char *path, int complain)
 {
        char    *dir;
 
@@ -61,7 +149,7 @@ manpath_parseline(struct manpaths *dirs, char *path)
                return;
 
        for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
-               manpath_add(dirs, dir);
+               manpath_add(dirs, dir, complain);
 }
 
 /*
@@ -69,68 +157,43 @@ manpath_parseline(struct manpaths *dirs, char *path)
  * Grow the array one-by-one for simplicity's sake.
  */
 static void
-manpath_add(struct manpaths *dirs, const char *dir
+manpath_add(struct manpaths *dirs, const char *dir, int complain)
 {
        char             buf[PATH_MAX];
+       struct stat      sb;
        char            *cp;
-       int              i;
+       size_t           i;
 
-       if (NULL == (cp = realpath(dir, buf)))
+       if (NULL == (cp = realpath(dir, buf))) {
+               if (complain) {
+                       fputs("manpath: ", stderr);
+                       perror(dir);
+               }
                return;
+       }
 
        for (i = 0; i < dirs->sz; i++)
                if (0 == strcmp(dirs->paths[i], dir))
                        return;
 
-       dirs->paths = mandoc_realloc
-               (dirs->paths, 
-                ((size_t)dirs->sz + 1) * sizeof(char *));
-
-       dirs->paths[dirs->sz++] = mandoc_strdup(cp);
-}
-
-void
-manpath_parseconf(struct manpaths *dirs)
-{
-#ifdef USE_MANPATH
-       FILE            *stream;
-       char            *buf;
-       size_t           sz, bsz;
-
-       /* Open manpath(1).  Ignore errors. */
-
-       stream = popen("manpath", "r");
-       if (NULL == stream)
+       if (stat(cp, &sb) == -1) {
+               if (complain) {
+                       fputs("manpath: ", stderr);
+                       perror(dir);
+               }
                return;
-
-       buf = NULL;
-       bsz = 0;
-
-       /* Read in as much output as we can. */
-
-       do {
-               buf = mandoc_realloc(buf, bsz + 1024);
-               sz = fread(buf + (int)bsz, 1, 1024, stream);
-               bsz += sz;
-       } while (sz > 0);
-
-       if ( ! ferror(stream) && feof(stream) &&
-                       bsz && '\n' == buf[bsz - 1]) {
-               buf[bsz - 1] = '\0';
-               manpath_parseline(dirs, buf);
        }
 
-       free(buf);
-       pclose(stream);
-#else
-       manpath_manconf(MAN_CONF_FILE, dirs);
-#endif
+       dirs->paths = mandoc_reallocarray(dirs->paths,
+           dirs->sz + 1, sizeof(char *));
+
+       dirs->paths[dirs->sz++] = mandoc_strdup(cp);
 }
 
 void
 manpath_free(struct manpaths *p)
 {
-       int              i;
+       size_t           i;
 
        for (i = 0; i < p->sz; i++)
                free(p->paths[i]);
@@ -139,11 +202,11 @@ manpath_free(struct manpaths *p)
 }
 
 void
-manpath_manconf(const char *file, struct manpaths *dirs)
+manpath_manconf(struct manpaths *dirs, const char *file)
 {
        FILE            *stream;
        char            *p, *q;
-       size_t           len, keysz;
+       size_t           len, keysz;
 
        keysz = strlen(MAN_CONF_KEY);
        assert(keysz > 0);
@@ -160,14 +223,14 @@ manpath_manconf(const char *file, struct manpaths *dirs)
                if (strncmp(MAN_CONF_KEY, p, keysz))
                        continue;
                p += keysz;
-               while (isspace(*p))
+               while (isspace((unsigned char)*p))
                        p++;
                if ('\0' == *p)
                        continue;
                if (NULL == (q = strrchr(p, '/')))
                        continue;
                *q = '\0';
-               manpath_add(dirs, p);
+               manpath_add(dirs, p, 0);
        }
 
        fclose(stream);