Arch Linux – Why Is Almost Every Program Complaining About Locale?

arch linuxglibclocale

I'm using Arch Linux, and I've followed the directions on the wiki about setting my locale.

Nearly every program that runs complains about the locale – even locale. It looks like this:

% locale
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=
LC_CTYPE=en_US.UTF-8
LC_NUMERIC=en-US
LC_TIME=en-US
LC_COLLATE="POSIX"
LC_MONETARY=en-US
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT=en-US
LC_IDENTIFICATION="POSIX"
LC_ALL=

or:

% perl
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LC_TIME = "en-US",
    LC_NUMERIC = "en-US",
    LC_MONETARY = "en-US",
    LC_MEASUREMENT = "en-US",
    LC_CTYPE = "en_US.UTF-8",
    LANG = (unset)
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C")

Something slightly confusing is that the /etc/locale.gen has several examples; all the UTF-8 lines have "something.UTF-8", and running locale-gen shows en_US.UTF-8... done while it's running, but locale -a, which is supposed to show you the available locales shows en_US.utf8. I've tried various combinations of both formats in /etc/locale-gen and LOCALE= in /etc/rc.conf, but nothing has fixed the problem.

Additional information:

% locale -a
C
POSIX
en_US
en_US.iso88591
en_US.utf8

Bruce Ediger's suggestion of setting LANG=C and LC_ALL=en_US.UTF-8 worked (in fact, setting LC_ALL fixed it, setting LANG didn't matter), but I'd like to know what's happening. According to SUS, LC_ALL will override all the other LC_* variables if it is set and not null. In my system, it is set, but it is null, so it should be ignored, and other values should be used instead. That's not what's happening, it seems that applications are calling setlocale with LC_ALL, getting a NULL back, and generating an error, even when other calls to setlocale return a good string.

Here is the top of an ltrace of locale (scroll right to see function return values)

% ltrace locale
(0, 0, 0, -1, 0x7f5c1ae44510)                                                                      = 0x7f5c1ae47140
__libc_start_main(0x401d70, 1, 0x7fff7c8cfbf8, 0x404610, 0x4046a0 <unfinished ...>
setlocale(0, "")                                                                                   = "en_US.UTF-8"
setlocale(5, "")                                                                                   = "en_US.UTF-8"
textdomain("libc")                                                                                 = "libc"
argp_parse(0x607280, 1, 0x7fff7c8cfbf8, 0, 0x7fff7c8cfad4)                                         = 0
setlocale(6, "")                                                                                   = NULL
dcgettext(0, 0x405aa8, 5, 0, 0)                                                                    = 0x405aa8
error(0, 2, 0x405aa8, 1, 0locale: Cannot set LC_ALL to default locale: No such file or directory)  

Best Answer

You're missing a file which would be used to default the locale in the absence of $LANG or $LC_ALL (or all of the more specific $LC_whatever) being set.

On older glibc, it's /usr/lib/locale/locale-archive. Because GNU/Linux is chaotic, you should use strace to determine which files are expected in the particular versions in use on your machine:

strace -e file locale
execve("/usr/bin/locale", ["locale"], [/* 36 vars */]) = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/lib/libc.so.6", O_RDONLY)        = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3

----------------------Comments added 1 day later:

ltrace -S should be okay, since it shows syscalls.

Otherwise, "ltrace" is not very helpful (i.e. it's counterproductive versus strace), because it only shows the uppermost calls. Those are obvious (setlocale(3)), whereas the real problem happens within libc.

It sounds like you have the raw locale data installed, since en_US.UTF-8 works.

If so, then something like this should fix your problem, setting a system-wide default:

localedef -f UTF-8 -i en_US en_US.UTF-8
Related Question