--- configure.ac | 18 ++++++- include/comp_src.h.in | 2 +- lib/security.c | 36 +++++++++++++ lib/util.c | 3 ++ libdb/mydbm.h | 4 +- mk_catdirs | 30 +++++++++++ src/Makefile.am | 12 ++--- src/check_mandirs.c | 48 ++++++++++++----- src/lexgrog.l | 121 ++++++++++++++++++++++++++++------------- src/man.c | 115 ++++++++++++++++++++++++++------------- src/man_db.conf.in | 145 +++++++++++++++++++++++++++++++++++++++++++++++--- src/mandb.c | 18 +++++-- src/manp.c | 2 +- src/straycats.c | 13 +++-- src/ult_src.c | 9 +++- src/ult_src.h | 7 +-- 16 files changed, 460 insertions(+), 123 deletions(-) create mode 100644 mk_catdirs diff --git configure.ac configure.ac index 2daf4a3..34ce06e 100644 --- configure.ac +++ configure.ac @@ -333,6 +333,14 @@ then fi MAN_CHECK_PROGS([eqn], [EQN], [use EQN to preprocess equations], [eqn geqn]) +MAN_CHECK_PROGS([geqn], [GEQN], [use GEQN to preprocess equations], [geqn]) +dnl +dnl if geqn is found and geqn is identical with eqn we use a GNU eqn +dnl which its self can use -Tlatin1 +dnl +if test -n "$geqn" -a -n "$eqn" ; then + test $geqn -ef $eqn && neqn="$eqn -T$nroff_device" +fi MAN_CHECK_PROGS([neqn], [NEQN], [use NEQN to preprocess equations for character devices], [neqn gneqn]) # If we fail to find an neqn, use eqn and try to force it to output for an # ascii device. As this is only relevant for equations (?), not using latin1 @@ -376,9 +384,15 @@ then compress_ext="gz" fi MAN_CHECK_PROGS([compress], [COMPRESS], [use COMPRESS as UNIX compression utility], [compress]) -if test -n "$compress" +if test -n "$compress" || test -n "$gzip" then - uncompress="$compress -dc" + if test -n "$gzip" + then + uncompress="$gzip -dc" + elif test -n "$compress" + then + uncompress="$compress -dc" + fi if test -z "$gzip" then compressor="$compress -c" diff --git include/comp_src.h.in include/comp_src.h.in index 4d6b0e7..7c865e8 100644 --- include/comp_src.h.in +++ include/comp_src.h.in @@ -53,7 +53,7 @@ struct compression comp_list[] = { #endif /* HAVE_GZIP */ /* If we have compress, incorporate the following */ -#ifdef HAVE_COMPRESS +#if defined(HAVE_COMPRESS) || defined(HAVE_GZIP) {UNCOMPRESS, "Z", NULL}, /* Else if we have gzip, incorporate the following */ #elif defined (HAVE_GZIP) diff --git lib/security.c lib/security.c index dd2e221..37d0ca7 100644 --- lib/security.c +++ lib/security.c @@ -60,7 +60,10 @@ uid_t ruid; /* initial real user id */ uid_t euid; /* initial effective user id */ +gid_t rgid; /* initial real group id */ +gid_t egid; /* initial effective group id */ uid_t uid; /* current euid */ +gid_t gid; /* current egid */ static struct passwd *man_owner; @@ -74,10 +77,17 @@ static inline void gripe_set_euid (void) error (FATAL, errno, _("can't set effective uid")); } +static inline void gripe_set_egid (void) +{ + error (FATAL, errno, _("can't set effective gid")); +} + void init_security (void) { ruid = getuid (); + rgid = getgid (); uid = euid = geteuid (); + gid = egid = getegid (); debug ("ruid=%d, euid=%d\n", (int) ruid, (int) euid); priv_drop_count = 0; drop_effective_privs (); @@ -147,6 +157,32 @@ void regain_effective_privs (void) uid = euid; } + + if (gid != rgid) { +# if defined(HAVE_SETRESGID) + if (setresgid (rgid, egid, -1) < 0) +# elif defined(HAVE_SETREGID) + if (setregid (rgid, egid) < 0) +# elif defined(HAVE_SETEGID) + if (setegid (rgid) < 0) +# endif + gripe_set_egid(); + + gid = rgid; + } + + if (gid != egid) { +# if defined(HAVE_SETRESGID) + if (setresgid (egid, rgid, -1)) +# elif defined(HAVE_SETREGID) + if (setregid (egid, rgid) < 0) +# elif defined(HAVE_SETEGID) + if (setegid (egid)) +# endif + gripe_set_egid(); + + gid = egid; + } #endif /* SECURE_MAN_UID */ } diff --git lib/util.c lib/util.c index 978a16e..3dcf336 100644 --- lib/util.c +++ lib/util.c @@ -48,6 +48,9 @@ #include "gettext.h" +#include +#define _(String) gettext (String) + #include "manconfig.h" #include "error.h" diff --git libdb/mydbm.h libdb/mydbm.h index f0c4784..3538ed4 100644 --- libdb/mydbm.h +++ libdb/mydbm.h @@ -42,7 +42,7 @@ # include # ifndef HAVE_GDBM_EXISTS -extern inline int gdbm_exists(GDBM_FILE db, datum key); +extern int gdbm_exists(GDBM_FILE db, datum key); # endif /* !HAVE_GDBM_EXISTS */ /* gdbm_nextkey() is not lexicographically sorted, so we need to keep the @@ -144,7 +144,7 @@ extern int btree_nextkeydata(DB *db, datum *key, datum *cont); # define MYDBM_SET_DPTR(d, value) ((d).data = (char *) (value)) # define MYDBM_DSIZE(d) ((d).size) # define MYDBM_CTRWOPEN(file) btree_flopen(file, O_TRUNC|O_CREAT|O_RDWR, DBMODE) -# define MYDBM_CRWOPEN(file) btree_flopen(file, O_CREAT|O_RDWR, DBMODE) +# define MYDBM_CRWOPEN(file) btree_flopen(file, O_CREAT|O_RDWR, DBMODE) # define MYDBM_RWOPEN(file) btree_flopen(file, O_RDWR, DBMODE) # define MYDBM_RDOPEN(file) btree_flopen(file, O_RDONLY, DBMODE) # define MYDBM_INSERT(db, key, cont) btree_insert(db, key, cont) diff --git mk_catdirs mk_catdirs new file mode 100644 index 0000000..47eaa25 --- /dev/null +++ mk_catdirs @@ -0,0 +1,30 @@ +#!/bin/sh + +OLDPWD="`pwd`" +CACHE="$1/var/cache/man" + + cats="cat{0,1,2,3,4,5,6,7,8,9,n}" +locale="{ca,cs,da,de,en,es,et,fi,fr,ga,hu,is,it,ja,ko,nl,no,pl,pt,ru,sk,sr,sv,uk}" + dirs="{local,opt}" + +umask 022 +test -d ${CACHE} && rm -rf ${CACHE} +mkdir -p ${CACHE} + +catman=false +grep -qE '#[[:blank:]]*define[[:blank:]]+MAN_CATS' include/manconfig.h && catman=true +cd ${CACHE} +if $catman ; then + eval echo ${cats} \ + ${locale}/${cats} \ + ${dirs}/${cats} \ + ${dirs}/${locale}/${cats} +else + eval echo ${locale} \ + ${dirs} \ + ${dirs}/${locale} +fi | xargs mkdir -p +sync +cd ${OLDPWD} + +test "$(id -u)" -ne 0 || chown man:man -R ${CACHE} diff --git src/Makefile.am src/Makefile.am index 51118a1..0003cbc 100644 --- src/Makefile.am +++ src/Makefile.am @@ -177,15 +177,9 @@ apropos$(EXEEXT): whatis$(EXEEXT) all-am: apropos$(EXEEXT) install-exec-hook: - -test -z "$(man_owner)" || \ - chown $(man_owner) \ - $(DESTDIR)$(bindir)/$(TRANS_MAN) \ - $(DESTDIR)$(bindir)/$(TRANS_MANDB) - chmod $(man_mode) \ - $(DESTDIR)$(bindir)/$(TRANS_MAN) \ - $(DESTDIR)$(bindir)/$(TRANS_MANDB) - cd $(DESTDIR)$(bindir) && rm -f $(TRANS_APROPOS)$(EXEEXT) && \ - $(LN_S) $(TRANS_WHATIS)$(EXEEXT) $(TRANS_APROPOS)$(EXEEXT) + $(INSTALL_PROGRAM) $(TRANS_MAN) $(DESTDIR)$(pkglibexecdir)/$(TRANS_MAN) + $(INSTALL_PROGRAM) $(TRANS_MANDB) $(DESTDIR)$(pkglibexecdir)/$(TRANS_MANDB) + $(LN_S) $(TRANS_WHATIS) $(DESTDIR)$(bindir)/$(TRANS_APROPOS) install-data-hook: @if test -f $(DESTDIR)$(config_file); then \ diff --git src/check_mandirs.c src/check_mandirs.c index f954dbf..f9d6314 100644 --- src/check_mandirs.c +++ src/check_mandirs.c @@ -354,10 +354,13 @@ static inline void add_dir_entries (const char *path, char *infile) #ifdef SECURE_MAN_UID extern uid_t ruid; /* initial real user id */ +extern uid_t euid; /* initial effective user id */ +extern gid_t rgid; /* initial real group id */ +extern gid_t egid; /* initial effective group id */ #endif /* SECURE_MAN_UID */ /* create the catman hierarchy if it doesn't exist */ -static void mkcatdirs (const char *mandir, const char *catdir) +void mkcatdirs (const char *mandir, const char *catdir) { char *manname, *catname; #ifdef SECURE_MAN_UID @@ -381,6 +384,8 @@ static void mkcatdirs (const char *mandir, const char *catdir) #ifdef SECURE_MAN_UID if (ruid == 0) chown (catdir, man_owner->pw_uid, 0); + if (rgid == 0) + chown (catdir, -1, man_owner->pw_gid); #endif /* SECURE_MAN_UID */ drop_effective_privs (); } @@ -391,9 +396,14 @@ static void mkcatdirs (const char *mandir, const char *catdir) int j; regain_effective_privs (); debug ("creating catdir hierarchy %s ", catdir); - for (j = 1; j <= 9; j++) { - catname[strlen (catname) - 1] = '0' + j; - manname[strlen (manname) - 1] = '0' + j; + for (j = 0; j <= 10; j++) { + unsigned int c; + if (j < 10) + c = '0' + j; + else + c = 'n'; + catname[strlen (catname) - 1] = c; + manname[strlen (manname) - 1] = c; if ((is_directory (manname) == 1) && (is_directory (catname) != 1)) { if (mkdir (catname, @@ -402,11 +412,12 @@ static void mkcatdirs (const char *mandir, const char *catdir) error (0, 0, _("warning: cannot create catdir %s"), catname); debug ("warning: cannot create catdir %s\n", catname); } else - debug (" cat%d", j); + debug (" cat%d", c); #ifdef SECURE_MAN_UID if (ruid == 0) - chown (catname, - man_owner->pw_uid, 0); + chown (catname, man_owner->pw_uid, 0); + if (rgid == 0) + chown (catname, -1, man_owner->pw_gid); #endif /* SECURE_MAN_UID */ } } @@ -505,15 +516,10 @@ static int testmandirs (const char *path, const char *catpath, time_t last, } if (!quiet) { - int tty = isatty (STDERR_FILENO); - - if (tty) - fprintf (stderr, "\r"); fprintf (stderr, _("Updating index cache for path " "`%s/%s'. Wait..."), path, mandir->d_name); - if (!tty) - fprintf (stderr, "\n"); + fprintf (stderr, "\n"); } add_dir_entries (path, mandir->d_name); MYDBM_CLOSE (dbf); @@ -681,7 +687,7 @@ int update_db (const char *manpath, const char *catpath) return new; } - debug ("failed to open %s O_RDONLY\n", database); + debug ("failed to open database %s O_RDONLY\n", database); return EOF; } @@ -863,6 +869,7 @@ static int purge_whatis (const char *path, int cat, const char *name, "would delete\n", name, info->ext); return 1; } + return 1; } /* Check that multi keys are correctly constructed. */ @@ -937,6 +944,11 @@ int purge_missing (const char *manpath, const char *catpath) gripe_rwopen_failed (); return 0; } + if (dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + return 0; + } /* Extract the database mtime. */ key = MYDBM_FIRSTKEY (dbf); @@ -978,6 +990,14 @@ int purge_missing (const char *manpath, const char *catpath) continue; } + /* Ignore db identifier keys. */ + if (*key.dptr == '.' && *(key.dptr+1) == 0) { + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE (key.dptr); + key = nextkey; + continue; + } + content = MYDBM_FETCH (dbf, key); if (!MYDBM_DPTR (content)) { nextkey = MYDBM_NEXTKEY (dbf, key); diff --git src/lexgrog.l src/lexgrog.l index 18c5a5b..9e5fc16 100644 --- src/lexgrog.l +++ src/lexgrog.l @@ -56,7 +56,7 @@ #include "manconv_client.h" -#define YY_READ_BUF_SIZE 1024 +#define YY_READ_BUF_SIZE YY_BUF_SIZE #define MAX_NAME 8192 #ifdef PROFILE @@ -207,15 +207,15 @@ static const struct macro perldocs[] = { { "R\"", "\"" } }; -static void add_str_to_whatis (const char *string, size_t length); -static void add_char_to_whatis (unsigned char c); -static void add_separator_to_whatis (void); -static void add_wordn_to_whatis (const char *string, size_t length); -static void add_word_to_whatis (const char *string); -static void add_glyph_to_whatis (const char *string, size_t length); -static void add_perldoc_to_whatis (const char *string, size_t length); -static void mdoc_text (const char *string); -static void newline_found (void); +static __inline__ void add_str_to_whatis (const char *string, size_t length); +static __inline__ void add_char_to_whatis (unsigned char c); +static __inline__ void add_separator_to_whatis (const char *, size_t); +static __inline__ void add_wordn_to_whatis (const char *string, size_t length); +static __inline__ void add_word_to_whatis (const char *string); +static __inline__ void add_glyph_to_whatis (const char *string, size_t length); +static __inline__ void add_perldoc_to_whatis (const char *string, size_t length); +static __inline__ void mdoc_text (const char *string); +static __inline__ void newline_found (void); static char newname[MAX_NAME]; static char *p_name; @@ -224,6 +224,7 @@ static char filters[MAX_FILTERS]; static int fill_mode; static int waiting_for_quote; +static int have_separator; static pipeline *decomp; @@ -241,7 +242,7 @@ static pipeline *decomp; %} %option ecs meta-ecs -%option 8bit batch caseful never-interactive +%option 8bit batch caseful never-interactive align %option nostdinit %option warn %option noyywrap nounput @@ -279,8 +280,9 @@ font_change \\f([[:upper:]1-4]|\({upper}{2}) size_change \\s[+-]?{digit} style_change ({font_change}{size_change}?|{size_change}{font_change}?) typeface \.(B[IR]?|I[BR]?|R[BI]|S[BM]) +paragr \.[PITLH][Pp] sec_request \.[Ss][HhYySs] -comment ['.]\\{dbl_quote} +comment (['.]\\{dbl_quote}|\'\-+|\\&) /* Please add to this list if you know how. */ /* Note that, since flex only supports UTF-8 by accident, character classes @@ -315,7 +317,26 @@ vi_name TÊN zh_CN_name 名{blank}?(称|字){blank}?.* zh_TW_name (名{blank}?(稱|字)|命令名){blank}?.* name ({bg_name}|{cs_name}|{da_name}|{de_name}|{en_name}|{es_name}|{fi_name}|{fr_name}|{hu_name}|{id_name}|{it_name}|{ja_name}|{ko_name}|{latin_name}|{lt_name}|{nl_name}|{pl_name}|{ru_name}|{sk_name}|{sr_name}|{srlatin_name}|{sv_name}|{tr_name}|{vi_name}|{zh_CN_name}|{zh_TW_name}) -name_sec {dbl_quote}?{style_change}?{name}{style_change}?({blank}*{dbl_quote})? +name_sec {dbl_quote}?{style_change}?{name}{style_change}?({blank}*{dbl_quote})?\r? +start {sec_request}{blank_eol}+{name_sec} + +N N(\bN)? +n (N(\bN)?|n(\bn)?) +a (A(\bA)?|a(\ba)?) +o (O(\bO)?|o(\bo)?) +m (M(\bM)?|M(\bM)?) +e (E(\bE)?|e(\be)?) +B B(\bB) +b (B(\bB)?|b(\bb)?) +r (R(\bR)?|r(\br)?) +z (Z(\bZ)?|z(\bz)?) +i (I(\bI)?|i(\bi)?) +c (C(\bC)?|c(\bc)?) +h (H(\bH)?|h(\bh)?) +u (U(\bU)?|u(\bu)?) +g (G(\bG)?|g(\bg)?) + +cname (({N}({a}|{o}){m}({n}|{e})|{N}{o}{m}|{N}{o}{m}{b}{r}{e}|{B}{e}{z}{e}{i}{c}{h}{n}{u}{n}{g})|{bg_name}|{cs_name}|{hu_name}|{ko_name}|{ru_name}|{sr_name}|{tr_name}|{vi_name}|{ja_name}|{zh_CN_name}|{zh_TW_name}) /* eptgrv : eqn, pic, tbl, grap, refer, vgrind */ tbl_request \.TS @@ -329,8 +350,13 @@ vgrind_request \.vS %% /* begin NAME section processing */ -{sec_request}{blank_eol}+{name_sec}{blank}* BEGIN (MAN_PRENAME); -{empty}{2,}{name}{blank}*{indent} BEGIN (CAT_NAME); +{ + {start}{blank}*{bol}{blank}*{paragr} | /* strange format */ + {start}{blank}* { /* default */ + BEGIN (MAN_PRENAME); + } +} +{empty}{2,}{cname}{blank}*{indent} BEGIN (CAT_NAME); /* general text matching */ \.[^Ss\r\n].* | @@ -398,6 +424,7 @@ vgrind_request \.vS {bol}\.sp{blank}* | /* vertical spacing */ {bol}\.ig{blank}* | /* block comment */ {bol}\.de[1i]?{blank}* | /* macro definition */ +{bol}\.V[be]{blank}* | /* special in perl pages */ {bol}\.i[ef]{blank}* | /* conditional */ {empty}{bol}.+ | <> { /* terminate the string */ @@ -435,21 +462,24 @@ vgrind_request \.vS } /* No-op requests */ -{bol}\.{blank}*$ newline_found (); -{bol}\.\.$ newline_found (); +{bol}\.{blank}*/{eol} newline_found (); +{bol}\.\./{eol} newline_found (); /* Toggle fill mode */ -{bol}\.nf.* fill_mode = 0; -{bol}\.fi.* fill_mode = 1; +{bol}\.(nf|de).* fill_mode = 0; +{bol}\.(fi|\.).* fill_mode = 1; -{eol}{blank_eol}* /* strip continuations */ /* convert to DASH */ {next}{blank}*\\\((mi|hy|em){blank}* | +{bol}\.sp{bol}{blank}+\\-{blank}* | /* strange spacing in NAME section * +{blank}+[-\\]?-{bol} | /* dash at end of line */ +{next}{blank_eol}+(\\?-){2}{blank}+ | /* some man pages use -- as dash */ {next}{blank_eol}+[-\\]-{blank}* | {next}{blank_eol}*[-\\]-{blank}+ | {next}{blank}+-{1,2}{blank_eol}+ | -{bol}\.Nd{blank}* add_separator_to_whatis (); +{bol}\.Nd{blank}* add_separator_to_whatis (yytext, yyleng); /* escape sequences and special characters */ { @@ -465,6 +495,7 @@ vgrind_request \.vS {next}\\[|^&!%acdpruz{}\r\n] /* various useless control chars */ {next}\\[bhlLvx]{blank}*'[^']+' /* various inline functions */ + {next}\\\\\$[1-9] /* roff macro argument */ {next}\\\$[1-9] /* interpolate arg */ /* roff named glyphs */ @@ -627,11 +658,8 @@ vgrind_request \.vS for later processing */ { {bol}\.br{blank}* | - {bol}\.LP{blank}* | - {bol}\.PP{blank}* | + {bol}{paragr}{blank}* | {bol}\.P{blank}* | - {bol}\.IP{blank}.* | - {bol}\.HP{blank}.* | {bol}\.RS{blank}.* | {bol}\.RE{blank}.* add_char_to_whatis ((char) 0x11); } @@ -646,7 +674,7 @@ vgrind_request \.vS [[:alnum:]]* add_str_to_whatis (yytext, yyleng); /* normalise the period (,) separators */ -{blank}*,[ \t\r\n]* | +{blank}*,{blank_eol}* | {blank}*,{blank}* add_str_to_whatis (", ", 2); {bol}. { @@ -662,7 +690,7 @@ vgrind_request \.vS %% /* print warning and force scanner to terminate */ -static void too_big (void) +static __inline__ void too_big (void) { /* Even though MAX_NAME is a macro expanding to a constant, we * translate it using ngettext anyway because that will make it @@ -679,7 +707,7 @@ static void too_big (void) } /* append a string to newname if enough room */ -static void add_str_to_whatis (const char *string, size_t length) +static __inline__ void add_str_to_whatis (const char *string, size_t length) { if (p_name - newname + length >= MAX_NAME) too_big (); @@ -690,8 +718,10 @@ static void add_str_to_whatis (const char *string, size_t length) } /* append a char to newname if enough room */ -static void add_char_to_whatis (unsigned char c) +static __inline__ void add_char_to_whatis (unsigned char c) { + if (c == (char) 0x11 && *p_name == (char) 0x11) + return; if (p_name - newname + 1 >= MAX_NAME) too_big (); else if (waiting_for_quote && c == '"') @@ -703,8 +733,24 @@ static void add_char_to_whatis (unsigned char c) /* append the " - " separator to newname, trimming the first space if one's * already there */ -static void add_separator_to_whatis (void) +static __inline__ void add_separator_to_whatis (const char *, size_t) { + if (have_separator) { + unsigned int n; + unsigned char c; + + for (n = 0; (n < len) && (c = string[n]); n++) { + switch (c) { + case '-': + case ' ': + add_char_to_whatis (c); + default: + break; + } + } + return; + } + have_separator = 1; if (p_name != newname && *(p_name - 1) != ' ') add_char_to_whatis (' '); add_str_to_whatis ("- ", 2); @@ -712,7 +758,7 @@ static void add_separator_to_whatis (void) /* append a word to newname if enough room, ensuring only necessary surrounding space */ -static void add_wordn_to_whatis (const char *string, size_t length) +static __inline__ void add_wordn_to_whatis (const char *string, size_t length) { if (p_name != newname && *(p_name - 1) != ' ') add_char_to_whatis (' '); @@ -722,7 +768,7 @@ static void add_wordn_to_whatis (const char *string, size_t length) add_str_to_whatis (string, length); } -static void add_word_to_whatis (const char *string) +static __inline__ void add_word_to_whatis (const char *string) { add_wordn_to_whatis (string, strlen (string)); } @@ -732,7 +778,7 @@ struct compare_macro_key { size_t length; }; -static int compare_macro (const void *left, const void *right) +static __inline__ int compare_macro (const void *left, const void *right) { const struct compare_macro_key *key = left; const struct macro *value = right; @@ -750,7 +796,7 @@ static int compare_macro (const void *left, const void *right) return 0; } -static void add_macro_to_whatis (const struct macro *macros, size_t n_macros, +static __inline__ void add_macro_to_whatis (const struct macro *macros, size_t n_macros, const char *string, size_t length) { struct compare_macro_key key; @@ -764,23 +810,23 @@ static void add_macro_to_whatis (const struct macro *macros, size_t n_macros, add_str_to_whatis (macro->value, strlen (macro->value)); } -static void add_glyph_to_whatis (const char *string, size_t length) +static __inline__ void add_glyph_to_whatis (const char *string, size_t length) { add_macro_to_whatis (glyphs, ARRAY_SIZE (glyphs), string, length); } -static void add_perldoc_to_whatis (const char *string, size_t length) +static __inline__ void add_perldoc_to_whatis (const char *string, size_t length) { add_macro_to_whatis (perldocs, ARRAY_SIZE (perldocs), string, length); } -static void mdoc_text (const char *string) +static __inline__ void mdoc_text (const char *string) { add_word_to_whatis (string); BEGIN (MAN_NAME); } -static void newline_found (void) +static __inline__ void newline_found (void) { /* If we are mid p_name and the last added char was not a space, * best add one. @@ -856,6 +902,7 @@ int find_name_decompressed (pipeline *p, const char *filename, lexgrog *p_lg) fill_mode = 1; waiting_for_quote = 0; + have_separator = 0; if (p_lg->type) BEGIN (CAT_FILE); diff --git src/man.c src/man.c index 4715efb..edcd59c 100644 --- src/man.c +++ src/man.c @@ -68,6 +68,7 @@ static char *cwd; #include #include #include +#include #include "argp.h" #include "dirname.h" @@ -110,6 +111,8 @@ static char *cwd; #ifdef SECURE_MAN_UID extern uid_t ruid; extern uid_t euid; +extern gid_t rgid; +extern gid_t egid; #endif /* SECURE_MAN_UID */ /* the default preprocessor sequence */ @@ -140,6 +143,10 @@ char *lang; static int global_manpath = -1; /* global or user manual page hierarchy? */ static int skip; /* page exists but has been skipped */ +static struct termios tms; /* To save terminal settings in */ +static int tms_set = 0; /* Do we have saved terminal settings? */ + +static void set_term(void) { if (tms_set) tcsetattr(fileno(stdin), TCSANOW, &tms); } #if defined _AIX || defined __sgi char **global_argv; @@ -244,9 +251,9 @@ static int found_a_stray; /* found a straycat */ #ifdef MAN_CATS static char *tmp_cat_file; /* for open_cat_stream(), close_cat_stream() */ static int created_tmp_cat; /* dto. */ -#endif static int tmp_cat_fd; static int man_modtime; /* modtime of man page, for commit_tmp_cat() */ +#endif /* MAN_CATS */ # ifdef TROFF_IS_GROFF static int ditroff; @@ -611,25 +618,6 @@ static void gripe_no_name (const char *sect) exit (FAIL); } -static struct termios tms; -static int tms_set = 0; - -static void set_term (void) -{ - if (tms_set) - tcsetattr (STDIN_FILENO, TCSANOW, &tms); -} - -static void get_term (void) -{ - if (isatty (STDOUT_FILENO)) { - debug ("is a tty\n"); - tcgetattr (STDIN_FILENO, &tms); - if (!tms_set++) - atexit (set_term); - } -} - #if defined(TROFF_IS_GROFF) || defined(HEIRLOOM_NROFF) static int get_roff_line_length (void) { @@ -916,30 +904,43 @@ static int local_man_loop (const char *argv) display (NULL, "", NULL, "(stdin)", NULL); else { struct stat st; - - if (cwd[0]) { - debug ("chdir %s\n", cwd); - if (chdir (cwd)) { - error (0, errno, _("can't chdir to %s"), cwd); + char *pwd = cwd; + char *file = basename((char*)argv); + + if (strcmp(argv, file)) { + char *dlm; + pwd = strdupa(argv); + + if ((dlm = strrchr(pwd, '/'))) + *dlm = '\0'; + } + + if (pwd[0]) { + debug ("chdir %s\n", pwd); + if (chdir (pwd)) { + error (0, errno, _("can't chdir to %s"), pwd); regain_effective_privs (); return 0; } } /* Check that the file exists and isn't e.g. a directory */ - if (stat (argv, &st)) { + if (stat (file, &st)) { error (0, errno, "%s", argv); + regain_effective_privs (); return NOT_FOUND; } if (S_ISDIR (st.st_mode)) { error (0, EISDIR, "%s", argv); + regain_effective_privs (); return NOT_FOUND; } if (S_ISCHR (st.st_mode) || S_ISBLK (st.st_mode)) { /* EINVAL is about the best I can do. */ error (0, EINVAL, "%s", argv); + regain_effective_privs (); return NOT_FOUND; } @@ -1006,8 +1007,13 @@ executable_out: argv_abs = xstrdup (argv); } lang = lang_dir (argv_abs); + if (!lang || !*lang) { + if (lang) + free(lang); + lang = xstrdup(internal_locale); + } free (argv_abs); - if (!display (NULL, argv, NULL, argv_base, NULL)) { + if (!display (NULL, file, NULL, argv_base, NULL)) { if (local_mf) error (0, errno, "%s", argv); exit_status = NOT_FOUND; @@ -1036,7 +1042,16 @@ int main (int argc, char *argv[]) umask (022); init_locale (); - internal_locale = setlocale (LC_MESSAGES, NULL); + internal_locale = setlocale (LC_MESSAGES, ""); +#if defined(__GLIBC__) +# if (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) + if (!internal_locale) { + if ( !(internal_locale = getenv ("LC_ALL")) + && !(internal_locale = getenv ("LC_MESSAGES"))) + internal_locale = getenv ("LANG"); + } +# endif +#endif /* Use LANGUAGE only when LC_MESSAGES locale category is * neither "C" nor "POSIX". */ if (internal_locale && strcmp (internal_locale, "C") && @@ -1101,9 +1116,13 @@ int main (int argc, char *argv[]) if (external) do_extern (argc, argv); - get_term (); /* stores terminal settings */ #ifdef SECURE_MAN_UID debug ("real user = %d; effective user = %d\n", ruid, euid); + if (isatty(fileno(stdin)) && isatty(fileno(stdout))) { + tcgetattr(fileno(stdin), &tms); + if (!tms_set++) + atexit(set_term); + } #endif /* SECURE_MAN_UID */ /* close this locale and reinitialise if a new locale was @@ -1409,7 +1428,8 @@ static char *get_preprocessors_from_file (pipeline *decomp) if (!line) return NULL; - if (!strncmp (line, PP_COOKIE, 4)) { + if (!strncmp (line, PP_COOKIE, 4) || + (strlen(line) == 6 && !strncmp(line, ".\\\" ", 4))) { const char *newline = strchr (line, '\n'); if (newline) return xstrndup (line + 4, newline - (line + 4)); @@ -1921,6 +1941,18 @@ static void setenv_less (pipecmd *cmd, const char *title) free (less_opts); } +static void disable_x(void) +{ + char *bname = basename((char*)pager); + if (bname) { + if (!strcmp(bname, "less")) + unsetenv("DISPLAY"); +#if 0 + free(bname); +#endif + } +} + static void add_output_iconv (pipeline *p, const char *source, const char *target) { @@ -1976,6 +2008,8 @@ static pipeline *make_display_command (const char *encoding, const char *title) if (pager_cmd) { setenv_less (pager_cmd, title); + if (!htmlout) + disable_x(); pipeline_command (p, pager_cmd); } pipeline_ignore_signals (p, 1); @@ -1986,7 +2020,7 @@ static pipeline *make_display_command (const char *encoding, const char *title) return p; } - +#ifdef MAN_CATS /* return a (malloced) temporary name in cat_file's directory */ static char *tmp_cat_filename (const char *cat_file) { @@ -2088,6 +2122,7 @@ static int commit_tmp_cat (const char *cat_file, const char *tmp_cat, return status; } +#endif /* MAN_CATS */ /* TODO: This should all be refactored after work on the decompression * library is complete. @@ -2108,7 +2143,6 @@ static void maybe_discard_stderr (pipeline *p) } #ifdef MAN_CATS - /* Return pipeline to write formatted manual page to for saving as cat file. */ static pipeline *open_cat_stream (const char *cat_file, const char *encoding) { @@ -2343,6 +2377,7 @@ static void format_display (pipeline *decomp, regain_effective_privs (); } +#ifdef MAN_CATS /* "Display" a page in catman mode, which amounts to saving it. */ /* TODO: merge with format_display_and_save? */ static void display_catman (const char *cat_file, pipeline *decomp, @@ -2382,6 +2417,7 @@ static void display_catman (const char *cat_file, pipeline *decomp, pop_cleanup(); free (tmpcat); } +#endif /* MAN_CATS */ static void disable_hyphenation (void *data ATTRIBUTE_UNUSED) { @@ -2535,7 +2571,7 @@ static int display (const char *dir, const char *man_file, format_cmd = NULL; decomp_errno = errno; } - +#ifdef MAN_CATS /* Get modification time, for commit_tmp_cat(). */ if (man_file && *man_file) { struct stat stb; @@ -2544,7 +2580,7 @@ static int display (const char *dir, const char *man_file, else man_modtime = stb.st_mtime; } - +#endif /* MAN_CATS */ display_to_stdout = troff; #ifdef TROFF_IS_GROFF if (htmlout) @@ -2680,6 +2716,7 @@ static int display (const char *dir, const char *man_file, } if (printed) putchar ('\n'); +#ifdef MAN_CATS } else if (catman) { if (format) { if (!save_cat) @@ -2692,6 +2729,7 @@ static int display (const char *dir, const char *man_file, format_cmd, formatted_encoding); } +#endif /* MAN_CATS */ } else if (format) { /* no cat or out of date */ pipeline *disp_cmd; @@ -2753,8 +2791,10 @@ static int display (const char *dir, const char *man_file, free (formatted_encoding); - pipeline_free (format_cmd); - pipeline_free (decomp); + if (format_cmd) + pipeline_free (format_cmd); + if (decomp) + pipeline_free (decomp); if (!prompt) prompt = found; @@ -2762,7 +2802,6 @@ static int display (const char *dir, const char *man_file, return found; } - static char *find_cat_file (const char *path, const char *original, const char *man_file) { @@ -3515,7 +3554,7 @@ static int display_database_check (struct candidate *candp) #ifdef MAN_DB_UPDATES if (!exists && !skip) { debug ("dbdelete_wrapper (%s, %p)\n", - candp->req_name, candp->source); + candp->req_name, candp->source->addr); dbdelete_wrapper (candp->req_name, candp->source); } #endif /* MAN_DB_UPDATES */ diff --git src/man_db.conf.in src/man_db.conf.in index bc8bb7e..c94b543 100644 --- src/man_db.conf.in +++ src/man_db.conf.in @@ -20,6 +20,14 @@ MANDATORY_MANPATH /usr/man MANDATORY_MANPATH /usr/share/man MANDATORY_MANPATH /usr/local/share/man +MANDATORY_MANPATH /opt/man +MANDATORY_MANPATH /opt/dx/man +MANDATORY_MANPATH /opt/lsb/man +MANDATORY_MANPATH /opt/cross/share/man +MANDATORY_MANPATH /opt/mpich/man +MANDATORY_MANPATH /opt/lsb-tet3-lite/share/man +MANDATORY_MANPATH /opt/snavigator/man +MANDATORY_MANPATH /opt/novell/man #--------------------------------------------------------- # set up PATH to MANPATH mapping # ie. what man tree holds man pages for what binary directory. @@ -34,8 +42,10 @@ MANPATH_MAP /usr/local/bin /usr/local/man MANPATH_MAP /usr/local/bin /usr/local/share/man MANPATH_MAP /usr/local/sbin /usr/local/man MANPATH_MAP /usr/local/sbin /usr/local/share/man -MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man -MANPATH_MAP /usr/bin/X11 /usr/X11R6/man +MANPATH_MAP /usr/X11R6/bin /usr/share/man +MANPATH_MAP /usr/X11/bin /usr/share/man +MANPATH_MAP /usr/bin/X11 /usr/share/man +MANPATH_MAP /usr/bin/mh /usr/share/man MANPATH_MAP /usr/games /usr/share/man MANPATH_MAP /opt/bin /opt/man MANPATH_MAP /opt/sbin /opt/man @@ -63,12 +73,133 @@ MANPATH_MAP /opt/sbin /opt/man # # *MANPATH* -> *CATPATH* # -MANDB_MAP /usr/man /var/cache/man/fsstnd +MANDB_MAP /usr/share/man/ca /var/cache/man/ca +MANDB_MAP /usr/share/man/cs /var/cache/man/cs +MANDB_MAP /usr/share/man/cs_CZ /var/cache/man/cs +MANDB_MAP /usr/share/man/da /var/cache/man/da +MANDB_MAP /usr/share/man/de /var/cache/man/de +MANDB_MAP /usr/share/man/de_AT /var/cache/man/de +MANDB_MAP /usr/share/man/de_DE /var/cache/man/de +MANDB_MAP /usr/share/man/en /var/cache/man/en +MANDB_MAP /usr/share/man/es /var/cache/man/es +MANDB_MAP /usr/share/man/es_ES /var/cache/man/es +MANDB_MAP /usr/share/man/et /var/cache/man/et +MANDB_MAP /usr/share/man/fi /var/cache/man/fi +MANDB_MAP /usr/share/man/fr_FR /var/cache/man/fr +MANDB_MAP /usr/share/man/ga /var/cache/man/ga +MANDB_MAP /usr/share/man/is /var/cache/man/is +MANDB_MAP /usr/share/man/it /var/cache/man/it +MANDB_MAP /usr/share/man/ja /var/cache/man/ja +MANDB_MAP /usr/share/man/ja_JP /var/cache/man/ja +MANDB_MAP /usr/share/man/ja_JP.eucJP /var/cache/man/ja +MANDB_MAP /usr/share/man/ko /var/cache/man/ko +MANDB_MAP /usr/share/man/nl /var/cache/man/nl +MANDB_MAP /usr/share/man/no /var/cache/man/no +MANDB_MAP /usr/share/man/pl /var/cache/man/pl +MANDB_MAP /usr/share/man/pt /var/cache/man/pt +MANDB_MAP /usr/share/man/pt_BR /var/cache/man/pt +MANDB_MAP /usr/share/man/ru /var/cache/man/ru +MANDB_MAP /usr/share/man/sk /var/cache/man/sk +MANDB_MAP /usr/share/man/sr /var/cache/man/sr +MANDB_MAP /usr/share/man/sv /var/cache/man/sv +MANDB_MAP /usr/share/man/uk /var/cache/man/uk MANDB_MAP /usr/share/man /var/cache/man -MANDB_MAP /usr/local/man /var/cache/man/oldlocal -MANDB_MAP /usr/local/share/man /var/cache/man/local -MANDB_MAP /usr/X11R6/man /var/cache/man/X11R6 -MANDB_MAP /opt/man /var/cache/man/opt +# +MANDB_MAP /usr/local/man/ca /var/cache/man/local/ca +MANDB_MAP /usr/local/man/cs /var/cache/man/local/cs +MANDB_MAP /usr/local/man/cs_CZ /var/cache/man/local/cs +MANDB_MAP /usr/local/man/da /var/cache/man/local/da +MANDB_MAP /usr/local/man/de /var/cache/man/local/de +MANDB_MAP /usr/local/man/de_AT /var/cache/man/local/de +MANDB_MAP /usr/local/man/de_DE /var/cache/man/local/de +MANDB_MAP /usr/local/man/en /var/cache/man/local/en +MANDB_MAP /usr/local/man/es /var/cache/man/local/es +MANDB_MAP /usr/local/man/es_ES /var/cache/man/local/es +MANDB_MAP /usr/local/man/et /var/cache/man/local/et +MANDB_MAP /usr/local/man/fi /var/cache/man/local/fi +MANDB_MAP /usr/local/man/fr_FR /var/cache/man/local/fr +MANDB_MAP /usr/local/man/ga /var/cache/man/local/ga +MANDB_MAP /usr/local/man/is /var/cache/man/local/is +MANDB_MAP /usr/local/man/it /var/cache/man/local/it +MANDB_MAP /usr/local/man/ja /var/cache/man/local/ja +MANDB_MAP /usr/local/man/ja_JP /var/cache/man/local/ja +MANDB_MAP /usr/local/man/ja_JP.eucJP /var/cache/man/local/ja +MANDB_MAP /usr/local/man/ko /var/cache/man/local/ko +MANDB_MAP /usr/local/man/nl /var/cache/man/local/nl +MANDB_MAP /usr/local/man/no /var/cache/man/local/no +MANDB_MAP /usr/local/man/pl /var/cache/man/local/pl +MANDB_MAP /usr/local/man/pt /var/cache/man/local/pt +MANDB_MAP /usr/local/man/pt_BR /var/cache/man/local/pt +MANDB_MAP /usr/local/man/ru /var/cache/man/local/ru +MANDB_MAP /usr/local/man/sk /var/cache/man/local/sk +MANDB_MAP /usr/local/man/sr /var/cache/man/local/sr +MANDB_MAP /usr/local/man/sv /var/cache/man/local/sv +MANDB_MAP /usr/local/man/uk /var/cache/man/local/uk +MANDB_MAP /usr/local/man /var/cache/man/local +# +MANDB_MAP /usr/local/share/man/ca /var/cache/man/local/ca +MANDB_MAP /usr/local/share/man/cs /var/cache/man/local/cs +MANDB_MAP /usr/local/share/man/cs_CZ /var/cache/man/local/cs +MANDB_MAP /usr/local/share/man/da /var/cache/man/local/da +MANDB_MAP /usr/local/share/man/de /var/cache/man/local/de +MANDB_MAP /usr/local/share/man/de_AT /var/cache/man/local/de +MANDB_MAP /usr/local/share/man/de_DE /var/cache/man/local/de +MANDB_MAP /usr/local/share/man/en /var/cache/man/local/en +MANDB_MAP /usr/local/share/man/es /var/cache/man/local/es +MANDB_MAP /usr/local/share/man/es_ES /var/cache/man/local/es +MANDB_MAP /usr/local/share/man/et /var/cache/man/local/et +MANDB_MAP /usr/local/share/man/fi /var/cache/man/local/fi +MANDB_MAP /usr/local/share/man/fr_FR /var/cache/man/local/fr +MANDB_MAP /usr/local/share/man/ga /var/cache/man/local/ga +MANDB_MAP /usr/local/share/man/is /var/cache/man/local/is +MANDB_MAP /usr/local/share/man/it /var/cache/man/local/it +MANDB_MAP /usr/local/share/man/ja /var/cache/man/local/ja +MANDB_MAP /usr/local/share/man/ja_JP /var/cache/man/local/ja +MANDB_MAP /usr/local/share/man/ja_JP.eucJP /var/cache/man/local/ja +MANDB_MAP /usr/local/share/man/ko /var/cache/man/local/ko +MANDB_MAP /usr/local/share/man/nl /var/cache/man/local/nl +MANDB_MAP /usr/local/share/man/no /var/cache/man/local/no +MANDB_MAP /usr/local/share/man/pl /var/cache/man/local/pl +MANDB_MAP /usr/local/share/man/pt /var/cache/man/local/pt +MANDB_MAP /usr/local/share/man/pt_BR /var/cache/man/local/pt +MANDB_MAP /usr/local/share/man/ru /var/cache/man/local/ru +MANDB_MAP /usr/local/share/man/sk /var/cache/man/local/sk +MANDB_MAP /usr/local/share/man/sr /var/cache/man/local/sr +MANDB_MAP /usr/local/share/man/sv /var/cache/man/local/sv +MANDB_MAP /usr/local/share/man/uk /var/cache/man/local/uk +MANDB_MAP /usr/local/share/man /var/cache/man/local +# +MANDB_MAP /opt/share/man/ca /var/cache/man/opt/ca +MANDB_MAP /opt/share/man/cs /var/cache/man/opt/cs +MANDB_MAP /opt/share/man/cs_CZ /var/cache/man/opt/cs +MANDB_MAP /opt/share/man/da /var/cache/man/opt/da +MANDB_MAP /opt/share/man/de /var/cache/man/opt/de +MANDB_MAP /opt/share/man/de_AT /var/cache/man/opt/de +MANDB_MAP /opt/share/man/de_DE /var/cache/man/opt/de +MANDB_MAP /opt/share/man/en /var/cache/man/opt/en +MANDB_MAP /opt/share/man/es /var/cache/man/opt/es +MANDB_MAP /opt/share/man/es /var/cache/man/opt/es +MANDB_MAP /opt/share/man/et /var/cache/man/opt/et +MANDB_MAP /opt/share/man/fi /var/cache/man/opt/fi +MANDB_MAP /opt/share/man/fr_FR /var/cache/man/opt/fr +MANDB_MAP /opt/share/man/ga /var/cache/man/opt/ga +MANDB_MAP /opt/share/man/is /var/cache/man/opt/is +MANDB_MAP /opt/share/man/it /var/cache/man/opt/it +MANDB_MAP /opt/share/man/ja /var/cache/man/opt/ja +MANDB_MAP /opt/share/man/ja_JP /var/cache/man/opt/ja +MANDB_MAP /opt/share/man/ja_JP.eucJP /var/cache/man/opt/ja +MANDB_MAP /opt/share/man/ko /var/cache/man/opt/ko +MANDB_MAP /opt/share/man/nl /var/cache/man/opt/nl +MANDB_MAP /opt/share/man/no /var/cache/man/opt/no +MANDB_MAP /opt/share/man/pl /var/cache/man/opt/pl +MANDB_MAP /opt/share/man/pt /var/cache/man/opt/pt +MANDB_MAP /opt/share/man/pt_BR /var/cache/man/opt/pt +MANDB_MAP /opt/share/man/ru /var/cache/man/opt/ru +MANDB_MAP /opt/share/man/sk /var/cache/man/opt/sk +MANDB_MAP /opt/share/man/sr /var/cache/man/opt/sr +MANDB_MAP /opt/share/man/sv /var/cache/man/opt/sv +MANDB_MAP /opt/share/man/uk /var/cache/man/opt/uk +MANDB_MAP /opt/share/man /var/cache/man/opt # #--------------------------------------------------------- # Program definitions. These are commented out by default as the value diff --git src/mandb.c src/mandb.c index 5b8c57d..58cfeb6 100644 --- src/mandb.c +++ src/mandb.c @@ -193,6 +193,8 @@ static const char *xtmpfile; #ifdef SECURE_MAN_UID extern uid_t ruid; extern uid_t euid; +extern gid_t rgid; +extern gid_t egid; #endif /* SECURE_MAN_UID */ static char *manpathlist[MAXDIRS]; @@ -528,6 +530,8 @@ static int mandb (const char *catpath, const char *manpath) return amount; } +extern void mkcatdirs (const char *, const char *); + static int process_manpath (const char *manpath, int global_manpath, struct hashtable *tried_catdirs) { @@ -561,6 +565,8 @@ static int process_manpath (const char *manpath, int global_manpath, database = NULL; } + mkcatdirs (manpath, catpath); + push_cleanup (cleanup, NULL, 0); push_cleanup (cleanup_sigsafe, NULL, 1); if (single_filename) { @@ -591,7 +597,7 @@ static int process_manpath (const char *manpath, int global_manpath, if (!opt_test && amount) { finish_up (); #ifdef SECURE_MAN_UID - if (global_manpath && euid == 0) + if (global_manpath && (euid == 0 || ruid == 0)) do_chown (man_owner->pw_uid); #endif /* SECURE_MAN_UID */ } @@ -801,8 +807,14 @@ int main (int argc, char *argv[]) error (FAIL, 0, _("the setuid man user \"%s\" does not exist"), MAN_OWNER); - if (!user && euid != 0 && euid != man_owner->pw_uid) - user = 1; + if (!user) { + if (!ruid && euid != man_owner->pw_uid) { + seteuid(man_owner->pw_uid); + euid = geteuid(); + } + if (euid != man_owner->pw_uid) + user = 1; + } #endif /* SECURE_MAN_UID */ read_config_file (user); diff --git src/manp.c src/manp.c index e73e838..22c7ae0 100644 --- src/manp.c +++ src/manp.c @@ -925,7 +925,7 @@ static char *def_path (int flag) /* If we have complete config file failure... */ if (!manpath) - return xstrdup ("/usr/man"); + return xstrdup ("/usr/share/man"); return manpath; } diff --git src/straycats.c src/straycats.c index 349d57b..9a27ff8 100644 --- src/straycats.c +++ src/straycats.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef HAVE_DIRENT_H # include @@ -279,13 +280,17 @@ static int check_for_stray (void) if (lg.whatis) free (lg.whatis); - pipeline_free (decomp); + if (decomp) + pipeline_free (decomp); next_exists: - free_mandata_struct (exists); - free (mandir_base); + if (exists) + free_mandata_struct (exists); + if (mandir_base) + free (mandir_base); } next_section: - free (section); + if (section) + free (section); } closedir (cdir); return strays; diff --git src/ult_src.c src/ult_src.c index 283aee1..d2eb971 100644 --- src/ult_src.c +++ src/ult_src.c @@ -379,10 +379,15 @@ const char *ult_src (const char *name, const char *path, } pipeline_start (decomp); - /* make sure that we skip over any comments */ + /* + * make sure that we skip over any comments + * ... even if we handle TCL/TK manual pages + */ do { buffer = pipeline_readline (decomp); - } while (buffer && STRNEQ (buffer, ".\\\"", 3)); + } while (buffer && *buffer && + (STRNEQ (buffer, ".\\\"", 3) || + STRNEQ (buffer, "'\\\"", 3))); include = test_for_include (buffer); if (include) { diff --git src/ult_src.h src/ult_src.h index 6fad470..3cd3a37 100644 --- src/ult_src.h +++ src/ult_src.h @@ -22,9 +22,10 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define SO_LINK 0001 -#define SOFT_LINK 0002 -#define HARD_LINK 0004 +#define SO_LINK 0x0001 +#define SOFT_LINK 0x0002 +#define HARD_LINK 0x0004 +#define WHATISBUF 0x0008 /* Trace of the link chain from a given file. Any names listed here should * not have WHATIS_MAN entries created for them. -- 1.8.4.5