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

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