diff options
author | Giovanni Campagna <scampa.giovanni@gmail.com> | 2013-01-05 01:29:53 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-01-07 15:31:17 +0100 |
commit | 17d33cecaa762f7e43200307328af5e9135e2091 (patch) | |
tree | 05156ae987c70d7630a31c6844b5994e963614b0 | |
parent | 9261bb7c5058fd543e42020f72f5762349f92c65 (diff) | |
download | systemd-17d33cecaa762f7e43200307328af5e9135e2091.tar.gz systemd-17d33cecaa762f7e43200307328af5e9135e2091.tar.bz2 systemd-17d33cecaa762f7e43200307328af5e9135e2091.zip |
localectl: support systems without locale-archive
Not all systems ships with locales inside /usr/lib/locale-archive, some
prefer to have locale data as individual subdirectories of /usr/lib/locale.
(A notable example of this is OpenEmbeddded, and OSes deriving from it
like gnome-ostree).
Given that glibc supports both ways, localectl should too.
-rw-r--r-- | src/locale/localectl.c | 101 |
1 files changed, 85 insertions, 16 deletions
diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 5d35f9cdae..b3acb3ec45 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -266,7 +266,7 @@ finish: return r; } -static int list_locales(DBusConnection *bus, char **args, unsigned n) { +static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ struct locarhead { @@ -304,21 +304,15 @@ static int list_locales(DBusConnection *bus, char **args, unsigned n) { const struct namehashent *e; const void *p = MAP_FAILED; _cleanup_close_ int fd = -1; - _cleanup_strv_free_ char **l = NULL; - char **j; - Set *locales; size_t sz = 0; struct stat st; unsigned i; int r; - locales = set_new(string_hash_func, string_compare_func); - if (!locales) - return log_oom(); - fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) { - log_error("Failed to open locale archive: %m"); + if (errno != ENOENT) + log_error("Failed to open locale archive: %m"); r = -errno; goto finish; } @@ -380,15 +374,93 @@ static int list_locales(DBusConnection *bus, char **args, unsigned n) { } } + r = 0; + + finish: + if (p != MAP_FAILED) + munmap((void*) p, sz); + + return r; +} + +static int add_locales_from_libdir (Set *locales) { + DIR *dir; + struct dirent *entry; + int r; + + dir = opendir("/usr/lib/locale"); + if (!dir) { + log_error("Failed to open locale directory: %m"); + r = -errno; + goto finish; + } + + errno = 0; + while ((entry = readdir(dir))) { + char *z; + + if (entry->d_type != DT_DIR) + continue; + + if (ignore_file(entry->d_name)) + continue; + + z = strdup(entry->d_name); + if (!z) { + r = log_oom(); + goto finish; + } + + r = set_put(locales, z); + if (r < 0) { + free(z); + + if (r != -EEXIST) { + log_error("Failed to add locale: %s", strerror(-r)); + goto finish; + } + } + + errno = 0; + } + + if (errno != 0) { + log_error("Failed to read locale directory: %m"); + r = -errno; + goto finish; + } + + r = 0; + + finish: + closedir(dir); + return r; +} + +static int list_locales(DBusConnection *bus, char **args, unsigned n) { + Set *locales; + _cleanup_strv_free_ char **l = NULL; + char **j; + int r; + + locales = set_new(string_hash_func, string_compare_func); + if (!locales) + return log_oom(); + + r = add_locales_from_archive(locales); + if (r < 0 && r != -ENOENT) + goto finish; + + r = add_locales_from_libdir(locales); + if (r < 0) + goto finish; + l = set_get_strv(locales); if (!l) { r = log_oom(); goto finish; } - set_free(locales); - locales = NULL; - strv_sort(l); pager_open_if_enabled(); @@ -399,10 +471,7 @@ static int list_locales(DBusConnection *bus, char **args, unsigned n) { r = 0; finish: - if (p != MAP_FAILED) - munmap((void*) p, sz); - - set_free_free(locales); + set_free(locales); return r; } |