6c0556
commit 43cea6d5652b6b9e61ac6ecc69419c909b504f47
6c0556
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
6c0556
Date:   Mon Sep 13 20:48:35 2021 +0530
6c0556
6c0556
    iconvconfig: Fix behaviour with --prefix [BZ #28199]
6c0556
    
6c0556
    The consolidation of configuration parsing broke behaviour with
6c0556
    --prefix, where the prefix bled into the modules cache.  Accept a
6c0556
    prefix which, when non-NULL, is prepended to the path when looking for
6c0556
    configuration files but only the original directory is added to the
6c0556
    modules cache.
6c0556
    
6c0556
    This has no effect on the codegen of gconv_conf since it passes NULL.
6c0556
    
6c0556
    Reported-by: Patrick McCarty <patrick.mccarty@intel.com>
6c0556
    Reported-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
6c0556
    Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
6c0556
6c0556
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
6c0556
index ce64faa928dc1c52..3f5a692f1510157c 100644
6c0556
--- a/iconv/gconv_conf.c
6c0556
+++ b/iconv/gconv_conf.c
6c0556
@@ -476,7 +476,7 @@ __gconv_read_conf (void)
6c0556
     __gconv_get_path ();
6c0556
 
6c0556
   for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
6c0556
-    gconv_parseconfdir (__gconv_path_elem[cnt].name,
6c0556
+    gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name,
6c0556
 			__gconv_path_elem[cnt].len);
6c0556
 #endif
6c0556
 
6c0556
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
6c0556
index e4c3c16d1f96ce0c..433aa18bab5083b0 100644
6c0556
--- a/iconv/gconv_parseconfdir.h
6c0556
+++ b/iconv/gconv_parseconfdir.h
6c0556
@@ -39,7 +39,6 @@
6c0556
 /* Name of the file containing the module information in the directories
6c0556
    along the path.  */
6c0556
 static const char gconv_conf_filename[] = "gconv-modules";
6c0556
-static const char gconv_conf_dirname[] = "gconv-modules.d";
6c0556
 
6c0556
 static void add_alias (char *);
6c0556
 static void add_module (char *, const char *, size_t, int);
6c0556
@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
6c0556
   return true;
6c0556
 }
6c0556
 
6c0556
+/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
6c0556
+   parse configuration in it.  */
6c0556
+
6c0556
 static __always_inline bool
6c0556
-gconv_parseconfdir (const char *dir, size_t dir_len)
6c0556
+gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
6c0556
 {
6c0556
-  /* No slash needs to be inserted between dir and gconv_conf_filename;
6c0556
-     dir already ends in a slash.  */
6c0556
-  char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
6c0556
+  /* No slash needs to be inserted between dir and gconv_conf_filename; dir
6c0556
+     already ends in a slash.  The additional 2 is to accommodate the ".d"
6c0556
+     when looking for configuration files in gconv-modules.d.  */
6c0556
+  size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
6c0556
+  char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
6c0556
+  char *cp = buf;
6c0556
   bool found = false;
6c0556
 
6c0556
   if (buf == NULL)
6c0556
     return false;
6c0556
 
6c0556
-  char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
6c0556
-		      sizeof (gconv_conf_filename));
6c0556
+  if (prefix != NULL)
6c0556
+    cp = stpcpy (cp, prefix);
6c0556
+
6c0556
+  cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
6c0556
+		sizeof (gconv_conf_filename));
6c0556
 
6c0556
   /* Read the gconv-modules configuration file first.  */
6c0556
   found = read_conf_file (buf, dir, dir_len);
6c0556
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
6c0556
index 777da870d2f8e99a..b1fd4100b5cbc9d2 100644
6c0556
--- a/iconv/iconvconfig.c
6c0556
+++ b/iconv/iconvconfig.c
6c0556
@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory,
6c0556
 static int
6c0556
 handle_dir (const char *dir)
6c0556
 {
6c0556
+  char *newp = NULL;
6c0556
   size_t dirlen = strlen (dir);
6c0556
   bool found = false;
6c0556
 
6c0556
-  char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
6c0556
-			     dir, dir[dirlen - 1] != '/' ? "/" : "");
6c0556
+  /* End directory path with a '/' if it doesn't already.  */
6c0556
+  if (dir[dirlen - 1] != '/')
6c0556
+    {
6c0556
+      newp = xmalloc (dirlen + 2);
6c0556
+      memcpy (newp, dir, dirlen);
6c0556
+      newp[dirlen++] = '/';
6c0556
+      newp[dirlen] = '\0';
6c0556
+      dir = newp;
6c0556
+    }
6c0556
 
6c0556
-  found = gconv_parseconfdir (fulldir, strlen (fulldir));
6c0556
+  found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen);
6c0556
 
6c0556
   if (!found)
6c0556
     {
6c0556
@@ -671,7 +679,7 @@ handle_dir (const char *dir)
6c0556
 	     "configuration files with names ending in .conf.");
6c0556
     }
6c0556
 
6c0556
-  free (fulldir);
6c0556
+  free (newp);
6c0556
 
6c0556
   return found ? 0 : 1;
6c0556
 }