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