diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-09-13 09:43:21 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-09-13 09:43:21 -0700 |
commit | 5280f9a0cd1f9ba200422ebba65d1e0133410995 (patch) | |
tree | bf85ce4e320a769d7e0903ff52ccfde13a422666 /catopen | |
download | man-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.gz man-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.bz2 man-5280f9a0cd1f9ba200422ebba65d1e0133410995.zip |
Initial.man-1.6g
Diffstat (limited to 'catopen')
-rw-r--r-- | catopen/README | 29 | ||||
-rw-r--r-- | catopen/catopen.c | 209 |
2 files changed, 238 insertions, 0 deletions
diff --git a/catopen/README b/catopen/README new file mode 100644 index 0000000..dbe8a45 --- /dev/null +++ b/catopen/README @@ -0,0 +1,29 @@ +In the good old days, with libc 4.*.*, +if NLSPATH was set to "/usr/lib/locale/%N/%L" +and LANG to "fr", then catopen("man",0) would open /usr/lib/locale/man/fr. + +These days, with libc 5.0.9, catopen will fail because it does a call +to setlocale, and if no locale has been setup, the C locale is assumed, +independent of the LANG setting. + +In order to preserve the possibility to say "LANG=de man fstab" +for systems where no locale has been set up, I enclose here +the original version of catopen. + +Concerning correctness: as far as I know POSIX does not specify +catopen(), and X/Open specifies catopen() without mentioning any +relation to locale - indeed, catopen() predates locale. +So, I think catopen() in libc 5.0.9 is broken. + +--- + +Time goes on, and I just looked at glibc-2.0.5. +Its catgets() contains (at least) two bugs, and will dump core. +One is fixed in RedHat's glibc-2.0.5c-10; I have submitted a fix +for the other. With a fixed catgets() things will work correctly. +However, glibc does a secure_getenv("NLSPATH"), which means that +the setting of NLSPATH is not taken into account for programs +that are sgid or suid. Thus, if you make man suid or sgid, and +want to use message catalogues, you have to install them in the +default place - on my system that is /usr/share/locale/%L/man +where %L is $LANG. diff --git a/catopen/catopen.c b/catopen/catopen.c new file mode 100644 index 0000000..2f756bc --- /dev/null +++ b/catopen/catopen.c @@ -0,0 +1,209 @@ +/* catopen.c - aeb, 960107 */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <nl_types.h> + +extern char *index (const char *, int); /* not always in <string.h> */ +extern char *my_malloc(int); /* in util.c */ + +#ifndef DEFAULT_NLSPATH +# if __GLIBC__ >= 2 +# define DEFAULT_NLSPATH "/usr/share/locale/%L/%N" +# else +# define DEFAULT_NLSPATH "/usr/lib/locale/%N/%L" +# endif +#endif + +static nl_catd my_catopenpath(char *name, char *path); + +static /* this source included in gripes.c */ +nl_catd +my_catopen(char *name, int oflag) { + nl_catd fd; + + fd = catopen(name, oflag); + + if (fd == (nl_catd) -1 && oflag) { + oflag = 0; + fd = catopen(name, oflag); + } + + if (fd == (nl_catd) -1) { + char *nlspath; + + /* The libc catopen fails - let us see if we can do better */ + /* The quotes below are from X/Open, XPG 1987, Vol. 3. */ + + /* + * "In catopen(), the oflag argument is reserved for future use + * and should be set to 0." + */ + + if (oflag) + return fd; /* only treat the known case */ + + /* + * "If `name' contains a `/', then `name' specifies a pathname" + */ + if (index(name, '/')) { +#ifdef __GLIBC__ + /* glibc uses a pointer type for nl_catd, not a fd */ + return fd; +#else + /* this works under libc5 */ + return open(name, O_RDONLY); +#endif + } + + /* + * "If NLSPATH does not exist in the environment, or if a + * message catalog cannot be opened in any of the paths specified + * by NLSPATH, then an implementation defined default path is used" + */ + + nlspath = getenv("NLSPATH"); + if (nlspath) + fd = my_catopenpath(name, nlspath); + if (fd == (nl_catd) -1) + fd = my_catopenpath(name, DEFAULT_NLSPATH); + } + return fd; +} + +/* + * XPG 1987, Vol. 3, Section 4.4 specifies the environment + * variable NLSPATH (example: + * NLSPATH=/nlslib/%L/%N.cat:/nlslib/%N/%L + * where %L stands for the value of the environment variable LANG, + * and %N stands for the `name' argument of catopen(). + * The environ(5) page specifies more precisely that + * LANG is of the form + * LANG=language[_territory[.codeset]] + * and adds %l, %t, %c for the three parts of LANG, without the + * _ or . and are NULL when these parts are missing. + * It also specifies %% for a single % sign. + * A leading colon, or a pair of adjacent colons, in NLSPATH + * specifies the current directory. (Meant is that "" stands for "%N".) + * + */ +static nl_catd +my_catopenpath(char *name, char *nlspath) { + int fd; + nl_catd cfd = (nl_catd) -1; + char *path0, *path, *s, *file, *lang, *lang_l, *lang_t, *lang_c; + int langsz, namesz, sz, lang_l_sz, lang_t_sz, lang_c_sz; + + namesz = strlen(name); + + lang = getenv("LANG"); + if (!lang) + lang = ""; + langsz = strlen(lang); + + lang_l = lang; + s = index(lang_l, '_'); + if (!s) { + lang_t = lang_c = ""; + lang_l_sz = langsz; + lang_t_sz = lang_c_sz = 0; + } else { + lang_l_sz = s - lang_l; + lang_t = s+1; + s = index(lang_t, '.'); + if (!s) { + lang_c = ""; + lang_t_sz = langsz - lang_l_sz - 1; + lang_c_sz = 0; + } else { + lang_t_sz = s - lang_t; + lang_c = s+1; + lang_c_sz = langsz - lang_l_sz - lang_t_sz - 2; + } + } + + /* figure out how much room we have to malloc() */ + sz = 0; + s = nlspath; + while(*s) { + if(*s == '%') { + s++; + switch(*s) { + case '%': + sz++; break; + case 'N': + sz += namesz; break; + case 'L': + sz += langsz; break; + case 'l': + sz += lang_l_sz; break; + case 't': + sz += lang_t_sz; break; + case 'c': + sz += lang_c_sz; break; + default: /* unknown escape - ignore */ + break; + } + } else if (*s == ':' && (s == nlspath || s[-1] == ':')) { + sz += (namesz + 1); + } else + sz++; + s++; + } + + /* expand the %L and %N escapes */ + path0 = my_malloc(sz + 1); + path = path0; + s = nlspath; + while(*s) { + if(*s == '%') { + s++; + switch(*s) { + case '%': + *path++ = '%'; break; + case 'N': + strncpy(path, name, namesz); path += namesz; break; + case 'L': + strncpy(path, lang, langsz); path += langsz; break; + case 'l': + strncpy(path, lang_l, lang_l_sz); path += lang_l_sz; break; + case 't': + strncpy(path, lang_t, lang_t_sz); path += lang_t_sz; break; + case 'c': + strncpy(path, lang_c, lang_c_sz); path += lang_c_sz; break; + default: /* unknown escape - ignore */ + break; + } + } else if (*s == ':' && (s == nlspath || s[-1] == ':')) { + strncpy(path, name, namesz); path += namesz; + *path++ = ':'; + } else + *path++ = *s; + s++; + } + *path = 0; + + path = path0; + while(path) { + file = path; + s = index(path, ':'); + if (s) { + *s = 0; + path = s+1; + } else + path = 0; + fd = open(file, O_RDONLY); + if (fd != -1) { + /* we found the right catalog - but we don't know the + type of nl_catd, so close it again and ask libc */ + close(fd); + cfd = catopen(file, 0); + break; + } + } + + free(path0); + return cfd; +} |