LCOV - code coverage report
Current view: top level - basic - locale-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 65 89 73.0 %
Date: 2015-07-29 18:47:03 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2014 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <sys/mman.h>
      23             : 
      24             : #include "set.h"
      25             : #include "util.h"
      26             : #include "utf8.h"
      27             : #include "strv.h"
      28             : 
      29             : #include "locale-util.h"
      30             : 
      31           1 : static int add_locales_from_archive(Set *locales) {
      32             :         /* Stolen from glibc... */
      33             : 
      34             :         struct locarhead {
      35             :                 uint32_t magic;
      36             :                 /* Serial number.  */
      37             :                 uint32_t serial;
      38             :                 /* Name hash table.  */
      39             :                 uint32_t namehash_offset;
      40             :                 uint32_t namehash_used;
      41             :                 uint32_t namehash_size;
      42             :                 /* String table.  */
      43             :                 uint32_t string_offset;
      44             :                 uint32_t string_used;
      45             :                 uint32_t string_size;
      46             :                 /* Table with locale records.  */
      47             :                 uint32_t locrectab_offset;
      48             :                 uint32_t locrectab_used;
      49             :                 uint32_t locrectab_size;
      50             :                 /* MD5 sum hash table.  */
      51             :                 uint32_t sumhash_offset;
      52             :                 uint32_t sumhash_used;
      53             :                 uint32_t sumhash_size;
      54             :         };
      55             : 
      56             :         struct namehashent {
      57             :                 /* Hash value of the name.  */
      58             :                 uint32_t hashval;
      59             :                 /* Offset of the name in the string table.  */
      60             :                 uint32_t name_offset;
      61             :                 /* Offset of the locale record.  */
      62             :                 uint32_t locrec_offset;
      63             :         };
      64             : 
      65             :         const struct locarhead *h;
      66             :         const struct namehashent *e;
      67           1 :         const void *p = MAP_FAILED;
      68           2 :         _cleanup_close_ int fd = -1;
      69           1 :         size_t sz = 0;
      70             :         struct stat st;
      71             :         unsigned i;
      72             :         int r;
      73             : 
      74           1 :         fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
      75           1 :         if (fd < 0)
      76           0 :                 return errno == ENOENT ? 0 : -errno;
      77             : 
      78           1 :         if (fstat(fd, &st) < 0)
      79           0 :                 return -errno;
      80             : 
      81           1 :         if (!S_ISREG(st.st_mode))
      82           0 :                 return -EBADMSG;
      83             : 
      84           1 :         if (st.st_size < (off_t) sizeof(struct locarhead))
      85           0 :                 return -EBADMSG;
      86             : 
      87           1 :         p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
      88           1 :         if (p == MAP_FAILED)
      89           0 :                 return -errno;
      90             : 
      91           1 :         h = (const struct locarhead *) p;
      92           2 :         if (h->magic != 0xde020109 ||
      93           2 :             h->namehash_offset + h->namehash_size > st.st_size ||
      94           2 :             h->string_offset + h->string_size > st.st_size ||
      95           2 :             h->locrectab_offset + h->locrectab_size > st.st_size ||
      96           1 :             h->sumhash_offset + h->sumhash_size > st.st_size) {
      97           0 :                 r = -EBADMSG;
      98           0 :                 goto finish;
      99             :         }
     100             : 
     101           1 :         e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
     102         908 :         for (i = 0; i < h->namehash_size; i++) {
     103             :                 char *z;
     104             : 
     105         907 :                 if (e[i].locrec_offset == 0)
     106         905 :                         continue;
     107             : 
     108           2 :                 if (!utf8_is_valid((char*) p + e[i].name_offset))
     109           0 :                         continue;
     110             : 
     111           2 :                 z = strdup((char*) p + e[i].name_offset);
     112           2 :                 if (!z) {
     113           0 :                         r = -ENOMEM;
     114           0 :                         goto finish;
     115             :                 }
     116             : 
     117           2 :                 r = set_consume(locales, z);
     118           2 :                 if (r < 0)
     119           0 :                         goto finish;
     120             :         }
     121             : 
     122           1 :         r = 0;
     123             : 
     124             :  finish:
     125           1 :         if (p != MAP_FAILED)
     126           1 :                 munmap((void*) p, sz);
     127             : 
     128           1 :         return r;
     129             : }
     130             : 
     131           1 : static int add_locales_from_libdir (Set *locales) {
     132           2 :         _cleanup_closedir_ DIR *dir = NULL;
     133             :         struct dirent *entry;
     134             :         int r;
     135             : 
     136           1 :         dir = opendir("/usr/lib/locale");
     137           1 :         if (!dir)
     138           0 :                 return errno == ENOENT ? 0 : -errno;
     139             : 
     140           4 :         FOREACH_DIRENT(entry, dir, return -errno) {
     141             :                 char *z;
     142             : 
     143           1 :                 if (entry->d_type != DT_DIR)
     144           1 :                         continue;
     145             : 
     146           0 :                 z = strdup(entry->d_name);
     147           0 :                 if (!z)
     148           0 :                         return -ENOMEM;
     149             : 
     150           0 :                 r = set_consume(locales, z);
     151           0 :                 if (r < 0 && r != -EEXIST)
     152           0 :                         return r;
     153           3 :         }
     154             : 
     155           1 :         return 0;
     156             : }
     157             : 
     158           1 : int get_locales(char ***ret) {
     159           2 :         _cleanup_set_free_ Set *locales = NULL;
     160           2 :         _cleanup_strv_free_ char **l = NULL;
     161             :         int r;
     162             : 
     163           1 :         locales = set_new(&string_hash_ops);
     164           1 :         if (!locales)
     165           0 :                 return -ENOMEM;
     166             : 
     167           1 :         r = add_locales_from_archive(locales);
     168           1 :         if (r < 0 && r != -ENOENT)
     169           0 :                 return r;
     170             : 
     171           1 :         r = add_locales_from_libdir(locales);
     172           1 :         if (r < 0)
     173           0 :                 return r;
     174             : 
     175           1 :         l = set_get_strv(locales);
     176           1 :         if (!l)
     177           0 :                 return -ENOMEM;
     178             : 
     179           1 :         strv_sort(l);
     180             : 
     181           1 :         *ret = l;
     182           1 :         l = NULL;
     183             : 
     184           1 :         return 0;
     185             : }
     186             : 
     187          11 : bool locale_is_valid(const char *name) {
     188             : 
     189          11 :         if (isempty(name))
     190           1 :                 return false;
     191             : 
     192          10 :         if (strlen(name) >= 128)
     193           0 :                 return false;
     194             : 
     195          10 :         if (!utf8_is_valid(name))
     196           0 :                 return false;
     197             : 
     198          10 :         if (!filename_is_valid(name))
     199           1 :                 return false;
     200             : 
     201           9 :         if (!string_is_safe(name))
     202           1 :                 return false;
     203             : 
     204           8 :         return true;
     205             : }
     206             : 
     207             : static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
     208             :         [VARIABLE_LANG] = "LANG",
     209             :         [VARIABLE_LANGUAGE] = "LANGUAGE",
     210             :         [VARIABLE_LC_CTYPE] = "LC_CTYPE",
     211             :         [VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
     212             :         [VARIABLE_LC_TIME] = "LC_TIME",
     213             :         [VARIABLE_LC_COLLATE] = "LC_COLLATE",
     214             :         [VARIABLE_LC_MONETARY] = "LC_MONETARY",
     215             :         [VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
     216             :         [VARIABLE_LC_PAPER] = "LC_PAPER",
     217             :         [VARIABLE_LC_NAME] = "LC_NAME",
     218             :         [VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
     219             :         [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
     220             :         [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
     221             :         [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
     222             : };
     223             : 
     224          32 : DEFINE_STRING_TABLE_LOOKUP(locale_variable, LocaleVariable);

Generated by: LCOV version 1.11