Blame SOURCES/0001-exec-Fix-setting-locale-for-util-calls.patch

1d3f6e
From d9571c2f1cf612ce0d479e428f7b1ae24944d140 Mon Sep 17 00:00:00 2001
1d3f6e
From: Vojtech Trefny <vtrefny@redhat.com>
1d3f6e
Date: Wed, 10 Jun 2020 17:03:28 +0200
1d3f6e
Subject: [PATCH] exec: Fix setting locale for util calls
1d3f6e
1d3f6e
This actually fixes two issue. The _utils_exec_and_report_progress
1d3f6e
function didn't set the LC_ALL=C environment variable to make sure
1d3f6e
we get output in English. And also we shouldn't use setenv in the
1d3f6e
GSpawnChildSetupFunc, it's actually example of what not to do in
1d3f6e
g_spawn_async documentation. This fix uses g_environ_setenv and
1d3f6e
passes the new environment to the g_spawn call.
1d3f6e
---
1d3f6e
 src/utils/exec.c    | 26 +++++++++++++++++---------
1d3f6e
 tests/utils_test.py |  7 +++++++
1d3f6e
 2 files changed, 24 insertions(+), 9 deletions(-)
1d3f6e
1d3f6e
diff --git a/src/utils/exec.c b/src/utils/exec.c
1d3f6e
index 9293930..37bd960 100644
1d3f6e
--- a/src/utils/exec.c
1d3f6e
+++ b/src/utils/exec.c
1d3f6e
@@ -140,11 +140,6 @@ static void log_done (guint64 task_id, gint exit_code) {
1d3f6e
     return;
1d3f6e
 }
1d3f6e
 
1d3f6e
-static void set_c_locale(gpointer user_data __attribute__((unused))) {
1d3f6e
-    if (setenv ("LC_ALL", "C", 1) != 0)
1d3f6e
-        g_warning ("Failed to set LC_ALL=C for a child process!");
1d3f6e
-}
1d3f6e
-
1d3f6e
 /**
1d3f6e
  * bd_utils_exec_and_report_error:
1d3f6e
  * @argv: (array zero-terminated=1): the argv array for the call
1d3f6e
@@ -194,6 +189,8 @@ gboolean bd_utils_exec_and_report_status_error (const gchar **argv, const BDExtr
1d3f6e
     const BDExtraArg **extra_p = NULL;
1d3f6e
     gint exit_status = 0;
1d3f6e
     guint i = 0;
1d3f6e
+    gchar **old_env = NULL;
1d3f6e
+    gchar **new_env = NULL;
1d3f6e
 
1d3f6e
     if (extra) {
1d3f6e
         args_len = g_strv_length ((gchar **) argv);
1d3f6e
@@ -219,16 +216,20 @@ gboolean bd_utils_exec_and_report_status_error (const gchar **argv, const BDExtr
1d3f6e
         args[i] = NULL;
1d3f6e
     }
1d3f6e
 
1d3f6e
+    old_env = g_get_environ ();
1d3f6e
+    new_env = g_environ_setenv (old_env, "LC_ALL", "C", TRUE);
1d3f6e
+
1d3f6e
     task_id = log_running (args ? args : argv);
1d3f6e
-    success = g_spawn_sync (NULL, args ? (gchar **) args : (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH,
1d3f6e
-                            (GSpawnChildSetupFunc) set_c_locale, NULL,
1d3f6e
-                            &stdout_data, &stderr_data, &exit_status, error);
1d3f6e
+    success = g_spawn_sync (NULL, args ? (gchar **) args : (gchar **) argv, new_env, G_SPAWN_SEARCH_PATH,
1d3f6e
+                            NULL, NULL, &stdout_data, &stderr_data, &exit_status, error);
1d3f6e
     if (!success) {
1d3f6e
         /* error is already populated from the call */
1d3f6e
+        g_strfreev (new_env);
1d3f6e
         g_free (stdout_data);
1d3f6e
         g_free (stderr_data);
1d3f6e
         return FALSE;
1d3f6e
     }
1d3f6e
+    g_strfreev (new_env);
1d3f6e
 
1d3f6e
     /* g_spawn_sync set the status in the same way waitpid() does, we need
1d3f6e
        to get the process exit code manually (this is similar to calling
1d3f6e
@@ -297,6 +298,8 @@ static gboolean _utils_exec_and_report_progress (const gchar **argv, const BDExt
1d3f6e
     gboolean err_done = FALSE;
1d3f6e
     GString *stdout_data = g_string_new (NULL);
1d3f6e
     GString *stderr_data = g_string_new (NULL);
1d3f6e
+    gchar **old_env = NULL;
1d3f6e
+    gchar **new_env = NULL;
1d3f6e
 
1d3f6e
     /* TODO: share this code between functions */
1d3f6e
     if (extra) {
1d3f6e
@@ -325,7 +328,10 @@ static gboolean _utils_exec_and_report_progress (const gchar **argv, const BDExt
1d3f6e
 
1d3f6e
     task_id = log_running (args ? args : argv);
1d3f6e
 
1d3f6e
-    ret = g_spawn_async_with_pipes (NULL, args ? (gchar**) args : (gchar**) argv, NULL,
1d3f6e
+    old_env = g_get_environ ();
1d3f6e
+    new_env = g_environ_setenv (old_env, "LC_ALL", "C", TRUE);
1d3f6e
+
1d3f6e
+    ret = g_spawn_async_with_pipes (NULL, args ? (gchar**) args : (gchar**) argv, new_env,
1d3f6e
                                     G_SPAWN_DEFAULT|G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
1d3f6e
                                     NULL, NULL, &pid, NULL, &out_fd, &err_fd, error);
1d3f6e
 
1d3f6e
@@ -333,9 +339,11 @@ static gboolean _utils_exec_and_report_progress (const gchar **argv, const BDExt
1d3f6e
         /* error is already populated */
1d3f6e
         g_string_free (stdout_data, TRUE);
1d3f6e
         g_string_free (stderr_data, TRUE);
1d3f6e
+        g_strfreev (new_env);
1d3f6e
         g_free (args);
1d3f6e
         return FALSE;
1d3f6e
     }
1d3f6e
+    g_strfreev (new_env);
1d3f6e
 
1d3f6e
     args_str = g_strjoinv (" ", args ? (gchar **) args : (gchar **) argv);
1d3f6e
     msg = g_strdup_printf ("Started '%s'", args_str);
1d3f6e
diff --git a/tests/utils_test.py b/tests/utils_test.py
1d3f6e
index 4bec3db..2bec5ed 100644
1d3f6e
--- a/tests/utils_test.py
1d3f6e
+++ b/tests/utils_test.py
1d3f6e
@@ -170,6 +170,13 @@ class UtilsExecLoggingTest(UtilsTestCase):
1d3f6e
             # exit code != 0
1d3f6e
             self.assertTrue(BlockDev.utils_check_util_version("libblockdev-fake-util-fail", "1.1", "version", "Version:\\s(.*)"))
1d3f6e
 
1d3f6e
+    @tag_test(TestTags.NOSTORAGE, TestTags.CORE)
1d3f6e
+    def test_exec_locale(self):
1d3f6e
+        """Verify that setting locale for exec functions works as expected"""
1d3f6e
+
1d3f6e
+        succ, out = BlockDev.utils_exec_and_capture_output(["locale"])
1d3f6e
+        self.assertTrue(succ)
1d3f6e
+        self.assertIn("LC_ALL=C", out)
1d3f6e
 
1d3f6e
 class UtilsDevUtilsTestCase(UtilsTestCase):
1d3f6e
     @tag_test(TestTags.NOSTORAGE, TestTags.CORE)
1d3f6e
-- 
1d3f6e
2.26.2
1d3f6e