http://bugs.gentoo.org/90186 If we have entries in MANPATH that are really symlinks to other entries, then many man functions will yield duplicate entries. Without this patch, we see this behavior: $ echo $MANPATH /usr/share/man:/usr/man $ man --path /usr/share/man:/usr/man $ ls -ld /usr/share/man /usr/man lrwxrwxrwx 1 /usr/man -> /usr/share/man drwxr-xr-x 36 /usr/share/man $ man -k passwd passwd (1) - change user password passwd (1) - change user password With this patch, we get: $ echo $MANPATH /usr/share/man:/usr/man $ man --path /usr/share/man $ ls -ld /usr/share/man /usr/man lrwxrwxrwx 1 /usr/man -> /usr/share/man drwxr-xr-x 36 /usr/share/man $ man -k passwd passwd (1) - change user password --- man-1.6c/src/manpath.c +++ man-1.6c/src/manpath.c @@ -380,6 +380,44 @@ } } +void trim_symlinked_manpaths (void); +void +trim_symlinked_manpaths () { + /* + * Skip symlinks to other entries in path. + * Do this after we've built the entire list. + */ + struct stat *stat_cache; + size_t i, j, size; + + if (!mandirlist) + return; + + for (size = 0; mandirlist[size]; ++size) + /* count # of elements */; + if (size == 0) + return; + /* cache stat information for every element */ + stat_cache = (struct stat *) my_malloc (size * sizeof(*stat_cache)); + for (i = 0; i < size; ++i) + stat(mandirlist[i], &stat_cache[i]); + +#define EQU_STAT(s,d) ((s).st_dev == (d).st_dev && (s).st_ino == (d).st_ino) + for (i = 0; i < size; ++i) { + for (j = i+1; j < size; ++j) { + if (EQU_STAT(stat_cache[i], stat_cache[j])) { + /* these two entries are the same, so cut out the second one */ + memmove(mandirlist+j, mandirlist+j+1, (size-j)*sizeof(*mandirlist)); + memmove(stat_cache+j, stat_cache+j+1, (size-j)*sizeof(*stat_cache)); + mandirlist[--size] = NULL; + --j; + } + } + } + + free(stat_cache); +} + void init_manpath () { static int done = 0; @@ -391,6 +431,7 @@ (manp = getenv ("MANPATH")) == NULL) manp = ""; /* default path */ split (manp, to_mandirlist, 0); + trim_symlinked_manpaths (); done = 1; } }