summaryrefslogtreecommitdiffstats
path: root/catopen
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-09-13 09:43:21 -0700
committerKaz Kylheku <kaz@kylheku.com>2014-09-13 09:43:21 -0700
commit5280f9a0cd1f9ba200422ebba65d1e0133410995 (patch)
treebf85ce4e320a769d7e0903ff52ccfde13a422666 /catopen
downloadman-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.gz
man-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.bz2
man-5280f9a0cd1f9ba200422ebba65d1e0133410995.zip
Initial.man-1.6g
Diffstat (limited to 'catopen')
-rw-r--r--catopen/README29
-rw-r--r--catopen/catopen.c209
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;
+}