Hi, I have a question about us catopen(3) implementation: currently we bypass locale settings (that could be setted from setlocale(3)) to directly go reading user locale settings from environment.
So a program that try to set specific locale (using setlocale(LC_ALL, "C") for example), will not use the "C" locale for LC_MESSAGES (when using catopen). The current code is: --- from lib/libc/nls/catopen.c --- // in _catopen(const char *name, int oflag) lang = NULL; if (oflag & NL_CAT_LOCALE) { lang = getenv("LC_ALL"); if (lang == NULL) lang = getenv("LC_MESSAGES"); } if (lang == NULL) lang = getenv("LANG"); if (lang == NULL) lang = NLS_DEFAULT_LANG; if (strcmp(lang, "POSIX") == 0) lang = NLS_DEFAULT_LANG; --- The POSIX specification is not very clear, as it speak about "setting of LC_MESSAGES" and "LANG environment variable". > This default may be affected by the setting of LC_MESSAGES if the > value of oflag is NL_CAT_LOCALE, or the LANG environment variable if > oflag is 0. Others implementations checked use LC_MESSAGES from locale setting (instead of value from environment), and fallback to getenv: - NetBSD http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/nls/catopen.c?rev=1.33&content-type=text/x-cvsweb-markup if (oflag == NL_CAT_LOCALE) { lang = loc->part_name[LC_MESSAGES]; } - FreeBSD https://svnweb.freebsd.org/base/head/lib/libc/nls/msgcat.c?revision=278530&view=markup if (type == NL_CAT_LOCALE) lang = setlocale(LC_MESSAGES, NULL); else lang = getenv("LANG"); - DragonFlyBSD (same code as FreeBSD) http://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/lib/libc/nls/msgcat.c (same code as FreeBSD) - Linux http://sourceware.org/git/?p=glibc.git;a=blob;f=catgets/catgets.c;h=cf93d56c5407ed737cdb8975b77a8b1e5aa26903;hb=HEAD if (flag == NL_CAT_LOCALE) /* Use the current locale setting for LC_MESSAGES. */ env_var = setlocale (LC_MESSAGES, NULL); else /* Use the LANG environment variable. */ env_var = getenv ("LANG"); The following patch change the behaviour of catopen(3). It will have impact on program that use catopen(3) (or related functions like strerror(3)) and don't initialise locale settings using setlocale(LC_ALL, ""), as the default value for locale (without initialisation) is "C". One example in base is kill program: - don't use setlocale - use err(3) function (which use strerror, which use catopen) Generic example: $ cat catopen-test.c #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/errno.h> #include <locale.h> int main() { //setlocale(LC_ALL, ""); printf("EPERM = %s\n", strerror(EPERM)); return (EXIT_SUCCESS); } Old behaviour: $ env -i LC_ALL=fr_FR.UTF-8 ./catopen-test EPERM = Opération non autorisée New behaviour: $ env -i LC_ALL=fr_FR.UTF-8 ./catopen-test EPERM = Operation not permitted Same program with setlocale initialisation: $ env -i LC_ALL=fr_FR.UTF-8 ./catopen-test EPERM = Opération non autorisée If this change is desirable, I will propose patchs for programs in base in order to call setlocale(LC_ALL, "") at program initilisation. Comments, ideas ? -- Sébastien Marie Index: nls/catopen.c =================================================================== RCS file: /cvs/src/lib/libc/nls/catopen.c,v retrieving revision 1.16 diff -u -p -r1.16 catopen.c --- nls/catopen.c 16 Jan 2015 16:48:51 -0000 1.16 +++ nls/catopen.c 12 Jun 2015 06:37:22 -0000 @@ -39,6 +39,7 @@ #include <unistd.h> #include <fcntl.h> #include <nl_types.h> +#include <locale.h> #define NLS_DEFAULT_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%l.%c/%N.cat:/usr/share/nls/%l/%N.cat" #define NLS_DEFAULT_LANG "C" @@ -68,9 +69,7 @@ _catopen(const char *name, int oflag) lang = NULL; if (oflag & NL_CAT_LOCALE) { - lang = getenv("LC_ALL"); - if (lang == NULL) - lang = getenv("LC_MESSAGES"); + lang = setlocale(LC_MESSAGES, NULL); } if (lang == NULL) lang = getenv("LANG");