summaryrefslogtreecommitdiff
path: root/src/locale/localectl.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-07-07 11:49:48 +0200
committerLennart Poettering <lennart@poettering.net>2014-07-07 15:25:55 +0200
commit7568345034f2890af745747783c5abfbf6eccf0f (patch)
tree711cb1a32730435553d00fe2b1fcc222d5bcc803 /src/locale/localectl.c
parenta940778fb1dd16479f455bab3ac6cbdbc5b06165 (diff)
shared: make timezone and locale enumeration and validation generic
This way we can reuse it other code thatn just localectl/localed + timedatectl/timedated.
Diffstat (limited to 'src/locale/localectl.c')
-rw-r--r--src/locale/localectl.c184
1 files changed, 6 insertions, 178 deletions
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 2632305dc..8acc21203 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -43,6 +43,7 @@
#include "path-util.h"
#include "utf8.h"
#include "def.h"
+#include "locale-util.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -177,192 +178,19 @@ static int set_locale(sd_bus *bus, char **args, unsigned n) {
return 0;
}
-static int add_locales_from_archive(Set *locales) {
- /* Stolen from glibc... */
-
- struct locarhead {
- uint32_t magic;
- /* Serial number. */
- uint32_t serial;
- /* Name hash table. */
- uint32_t namehash_offset;
- uint32_t namehash_used;
- uint32_t namehash_size;
- /* String table. */
- uint32_t string_offset;
- uint32_t string_used;
- uint32_t string_size;
- /* Table with locale records. */
- uint32_t locrectab_offset;
- uint32_t locrectab_used;
- uint32_t locrectab_size;
- /* MD5 sum hash table. */
- uint32_t sumhash_offset;
- uint32_t sumhash_used;
- uint32_t sumhash_size;
- };
-
- struct namehashent {
- /* Hash value of the name. */
- uint32_t hashval;
- /* Offset of the name in the string table. */
- uint32_t name_offset;
- /* Offset of the locale record. */
- uint32_t locrec_offset;
- };
-
- const struct locarhead *h;
- const struct namehashent *e;
- const void *p = MAP_FAILED;
- _cleanup_close_ int fd = -1;
- size_t sz = 0;
- struct stat st;
- unsigned i;
- int r;
-
- fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0) {
- if (errno != ENOENT)
- log_error("Failed to open locale archive: %m");
- r = -errno;
- goto finish;
- }
-
- if (fstat(fd, &st) < 0) {
- log_error("fstat() failed: %m");
- r = -errno;
- goto finish;
- }
-
- if (!S_ISREG(st.st_mode)) {
- log_error("Archive file is not regular");
- r = -EBADMSG;
- goto finish;
- }
-
- if (st.st_size < (off_t) sizeof(struct locarhead)) {
- log_error("Archive has invalid size");
- r = -EBADMSG;
- goto finish;
- }
-
- p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (p == MAP_FAILED) {
- log_error("Failed to map archive: %m");
- r = -errno;
- goto finish;
- }
-
- h = (const struct locarhead *) p;
- if (h->magic != 0xde020109 ||
- h->namehash_offset + h->namehash_size > st.st_size ||
- h->string_offset + h->string_size > st.st_size ||
- h->locrectab_offset + h->locrectab_size > st.st_size ||
- h->sumhash_offset + h->sumhash_size > st.st_size) {
- log_error("Invalid archive file.");
- r = -EBADMSG;
- goto finish;
- }
-
- e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
- for (i = 0; i < h->namehash_size; i++) {
- char *z;
-
- if (e[i].locrec_offset == 0)
- continue;
-
- if (!utf8_is_valid((char*) p + e[i].name_offset))
- continue;
-
- z = strdup((char*) p + e[i].name_offset);
- if (!z) {
- r = log_oom();
- goto finish;
- }
-
- r = set_consume(locales, z);
- if (r < 0) {
- log_error("Failed to add locale: %s", strerror(-r));
- goto finish;
- }
- }
-
- r = 0;
-
- finish:
- if (p != MAP_FAILED)
- munmap((void*) p, sz);
-
- return r;
-}
-
-static int add_locales_from_libdir (Set *locales) {
- _cleanup_closedir_ DIR *dir;
- struct dirent *entry;
- int r;
-
- dir = opendir("/usr/lib/locale");
- if (!dir) {
- log_error("Failed to open locale directory: %m");
- return -errno;
- }
-
- 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)
- return log_oom();
-
- r = set_consume(locales, z);
- if (r < 0 && r != -EEXIST) {
- log_error("Failed to add locale: %s", strerror(-r));
- return r;
- }
-
- errno = 0;
- }
-
- if (errno > 0) {
- log_error("Failed to read locale directory: %m");
- return -errno;
- }
-
- return 0;
-}
-
static int list_locales(sd_bus *bus, char **args, unsigned n) {
- _cleanup_set_free_ Set *locales;
_cleanup_strv_free_ char **l = NULL;
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)
- return r;
+ assert(args);
- r = add_locales_from_libdir(locales);
- if (r < 0)
+ r = get_locales(&l);
+ if (r < 0) {
+ log_error("Failed to read list of locales: %s", strerror(-r));
return r;
-
- l = set_get_strv(locales);
- if (!l)
- return log_oom();
-
- strv_sort(l);
+ }
pager_open_if_enabled();
-
strv_print(l);
return 0;