(root)/
glibc-2.38/
iconv/
gconv_parseconfdir.h
       1  /* Handle configuration data.
       2     Copyright (C) 2021-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <dirent.h>
      20  #include <libc-symbols.h>
      21  #include <locale.h>
      22  #include <sys/types.h>
      23  
      24  #if IS_IN (libc)
      25  # include <libio/libioP.h>
      26  # define __getdelim(line, len, c, fp) __getdelim (line, len, c, fp)
      27  
      28  # undef isspace
      29  # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
      30  # define asprintf __asprintf
      31  # define opendir __opendir
      32  # define readdir64 __readdir64
      33  # define closedir __closedir
      34  # define mempcpy __mempcpy
      35  # define struct_stat64 struct __stat64_t64
      36  # define lstat64 __lstat64_time64
      37  # define feof_unlocked __feof_unlocked
      38  #else
      39  # define struct_stat64 struct stat64
      40  #endif
      41  
      42  /* Name of the file containing the module information in the directories
      43     along the path.  */
      44  static const char gconv_conf_filename[] = "gconv-modules";
      45  
      46  static void add_alias (char *);
      47  static void add_module (char *, const char *, size_t, int);
      48  
      49  /* Read the next configuration file.  */
      50  static bool
      51  read_conf_file (const char *filename, const char *directory, size_t dir_len)
      52  {
      53    /* Note the file is opened with cancellation in the I/O functions
      54       disabled.  */
      55    FILE *fp = fopen (filename, "rce");
      56    char *line = NULL;
      57    size_t line_len = 0;
      58    static int modcounter;
      59  
      60    /* Don't complain if a file is not present or readable, simply silently
      61       ignore it.  */
      62    if (fp == NULL)
      63      return false;
      64  
      65    /* No threads reading from this stream.  */
      66    __fsetlocking (fp, FSETLOCKING_BYCALLER);
      67  
      68    /* Process the known entries of the file.  Comments start with `#' and
      69       end with the end of the line.  Empty lines are ignored.  */
      70    while (!feof_unlocked (fp))
      71      {
      72        char *rp, *endp, *word;
      73        ssize_t n = __getdelim (&line, &line_len, '\n', fp);
      74        if (n < 0)
      75  	/* An error occurred.  */
      76  	break;
      77  
      78        rp = line;
      79        /* Terminate the line (excluding comments or newline) by an NUL byte
      80  	 to simplify the following code.  */
      81        endp = strchr (rp, '#');
      82        if (endp != NULL)
      83  	*endp = '\0';
      84        else
      85  	if (rp[n - 1] == '\n')
      86  	  rp[n - 1] = '\0';
      87  
      88        while (isspace (*rp))
      89  	++rp;
      90  
      91        /* If this is an empty line go on with the next one.  */
      92        if (rp == endp)
      93  	continue;
      94  
      95        word = rp;
      96        while (*rp != '\0' && !isspace (*rp))
      97  	++rp;
      98  
      99        if (rp - word == sizeof ("alias") - 1
     100  	  && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
     101  	add_alias (rp);
     102        else if (rp - word == sizeof ("module") - 1
     103  	       && memcmp (word, "module", sizeof ("module") - 1) == 0)
     104  	add_module (rp, directory, dir_len, modcounter++);
     105        /* else */
     106  	/* Otherwise ignore the line.  */
     107      }
     108  
     109    free (line);
     110  
     111    fclose (fp);
     112    return true;
     113  }
     114  
     115  /* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
     116     parse configuration in it.  */
     117  
     118  static __always_inline bool
     119  gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
     120  {
     121    /* No slash needs to be inserted between dir and gconv_conf_filename; dir
     122       already ends in a slash.  The additional 2 is to accommodate the ".d"
     123       when looking for configuration files in gconv-modules.d.  */
     124    size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
     125    char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
     126    char *cp = buf;
     127    bool found = false;
     128  
     129    if (buf == NULL)
     130      return false;
     131  
     132    if (prefix != NULL)
     133      cp = stpcpy (cp, prefix);
     134  
     135    cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
     136  		sizeof (gconv_conf_filename));
     137  
     138    /* Read the gconv-modules configuration file first.  */
     139    found = read_conf_file (buf, dir, dir_len);
     140  
     141    /* Next, see if there is a gconv-modules.d directory containing
     142       configuration files and if it is non-empty.  */
     143    cp--;
     144    cp[0] = '.';
     145    cp[1] = 'd';
     146    cp[2] = '\0';
     147  
     148    DIR *confdir = opendir (buf);
     149    if (confdir != NULL)
     150      {
     151        struct dirent64 *ent;
     152        while ((ent = readdir64 (confdir)) != NULL)
     153  	{
     154  	  if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
     155  	    continue;
     156  
     157  	  size_t len = strlen (ent->d_name);
     158  	  const char *suffix = ".conf";
     159  
     160  	  if (len > strlen (suffix)
     161  	      && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
     162  	    {
     163  	      char *conf;
     164  	      struct_stat64 st;
     165  	      if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
     166  		continue;
     167  
     168  	      if (ent->d_type != DT_UNKNOWN
     169  		  || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
     170  		found |= read_conf_file (conf, dir, dir_len);
     171  
     172  	      free (conf);
     173  	    }
     174  	}
     175        closedir (confdir);
     176      }
     177    free (buf);
     178    return found;
     179  }