8d419f
From f990ee961a75791adfdea2f5efb35017a51a310e Mon Sep 17 00:00:00 2001
8d419f
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
8d419f
Date: Tue, 8 Mar 2022 10:08:05 +0100
8d419f
Subject: [PATCH] basic/env-file: make load-env-file deduplicate entries with
8d419f
 the same key
8d419f
8d419f
We generally assume parsing like the shell would do it, so the last value
8d419f
should win when there are repeats.
8d419f
8d419f
(cherry picked from commit 25407ad2a785d10b1aadff0c99829ea0cf51082b)
8d419f
8d419f
Related: #2082131
8d419f
---
8d419f
 src/basic/env-file.c     | 31 ++++++++++++++++++++-----------
8d419f
 src/test/test-env-file.c |  5 +++++
8d419f
 src/test/test-os-util.c  |  3 +--
8d419f
 3 files changed, 26 insertions(+), 13 deletions(-)
8d419f
8d419f
diff --git a/src/basic/env-file.c b/src/basic/env-file.c
8d419f
index 599b73bc22..0353f3f2a0 100644
8d419f
--- a/src/basic/env-file.c
8d419f
+++ b/src/basic/env-file.c
8d419f
@@ -415,30 +415,39 @@ static int load_env_file_push_pairs(
8d419f
                 const char *key, char *value,
8d419f
                 void *userdata,
8d419f
                 int *n_pushed) {
8d419f
-        char ***m = userdata;
8d419f
+        char ***m = ASSERT_PTR(userdata);
8d419f
+        bool added = false;
8d419f
         int r;
8d419f
 
8d419f
         r = check_utf8ness_and_warn(filename, line, key, value);
8d419f
         if (r < 0)
8d419f
                 return r;
8d419f
 
8d419f
+        /* Check if the key is present */
8d419f
+        for (char **t = *m; t && *t; t += 2)
8d419f
+                if (streq(t[0], key)) {
8d419f
+                        if (value)
8d419f
+                                r = free_and_replace(t[1], value);
8d419f
+                        else
8d419f
+                                r = free_and_strdup(t+1, "");
8d419f
+                        goto finish;
8d419f
+                }
8d419f
+
8d419f
         r = strv_extend(m, key);
8d419f
         if (r < 0)
8d419f
                 return -ENOMEM;
8d419f
 
8d419f
-        if (!value) {
8d419f
-                r = strv_extend(m, "");
8d419f
-                if (r < 0)
8d419f
-                        return -ENOMEM;
8d419f
-        } else {
8d419f
+        if (value)
8d419f
                 r = strv_push(m, value);
8d419f
-                if (r < 0)
8d419f
-                        return r;
8d419f
-        }
8d419f
+        else
8d419f
+                r = strv_extend(m, "");
8d419f
+        added = true;
8d419f
+ finish:
8d419f
+        if (r < 0)
8d419f
+                return r;
8d419f
 
8d419f
-        if (n_pushed)
8d419f
+        if (n_pushed && added)
8d419f
                 (*n_pushed)++;
8d419f
-
8d419f
         return 0;
8d419f
 }
8d419f
 
8d419f
diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c
8d419f
index 886a8e4bc8..461a0f0810 100644
8d419f
--- a/src/test/test-env-file.c
8d419f
+++ b/src/test/test-env-file.c
8d419f
@@ -9,7 +9,12 @@
8d419f
 #include "tests.h"
8d419f
 #include "tmpfile-util.h"
8d419f
 
8d419f
+/* In case of repeating keys, later entries win. */
8d419f
+
8d419f
 #define env_file_1                              \
8d419f
+        "a=a\n"                                 \
8d419f
+        "a=b\n"                                 \
8d419f
+        "a=b\n"                                 \
8d419f
         "a=a\n"                                 \
8d419f
         "b=b\\\n"                               \
8d419f
         "c\n"                                   \
8d419f
diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c
8d419f
index 5f82748783..d6336c53e9 100644
8d419f
--- a/src/test/test-os-util.c
8d419f
+++ b/src/test/test-os-util.c
8d419f
@@ -67,8 +67,7 @@ TEST(load_os_release_pairs) {
8d419f
 
8d419f
         _cleanup_strv_free_ char **pairs = NULL;
8d419f
         assert_se(load_os_release_pairs(NULL, &pairs) == 0);
8d419f
-        assert_se(strv_equal(pairs, STRV_MAKE("ID", "ignored", // FIXME
8d419f
-                                              "ID", "the-id",
8d419f
+        assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id",
8d419f
                                               "NAME", "the-name")));
8d419f
 
8d419f
         assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);