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