• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14895667988

07 May 2025 08:57PM UTC coverage: 72.225% (-0.007%) from 72.232%
14895667988

push

github

yuwata
network: log_link_message_debug_errno() automatically append %m if necessary

Follow-up for d28746ef5.
Fixes CID#1609753.

0 of 1 new or added line in 1 file covered. (0.0%)

20297 existing lines in 338 files now uncovered.

297407 of 411780 relevant lines covered (72.22%)

695716.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.23
/src/shared/locale-setup.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <sys/stat.h>
5

6
#include "alloc-util.h"
7
#include "env-file.h"
8
#include "env-file-label.h"
9
#include "env-util.h"
10
#include "errno-util.h"
11
#include "fd-util.h"
12
#include "locale-setup.h"
13
#include "proc-cmdline.h"
14
#include "stat-util.h"
15
#include "strv.h"
16

17
void locale_context_clear(LocaleContext *c) {
2,544✔
18
        assert(c);
2,544✔
19

20
        c->st = (struct stat) {};
2,544✔
21

22
        for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++)
38,160✔
23
                c->locale[i] = mfree(c->locale[i]);
35,616✔
24
}
2,544✔
25

26
static int locale_context_load_proc(LocaleContext *c, LocaleLoadFlag flag) {
1,118✔
27
        int r;
1,118✔
28

29
        assert(c);
1,118✔
30

31
        if (!FLAGS_SET(flag, LOCALE_LOAD_PROC_CMDLINE))
1,118✔
32
                return 0;
33

34
        locale_context_clear(c);
846✔
35

36
        r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX,
846✔
37
                                      "locale.LANG",              &c->locale[VARIABLE_LANG],
38
                                      "locale.LANGUAGE",          &c->locale[VARIABLE_LANGUAGE],
39
                                      "locale.LC_CTYPE",          &c->locale[VARIABLE_LC_CTYPE],
40
                                      "locale.LC_NUMERIC",        &c->locale[VARIABLE_LC_NUMERIC],
41
                                      "locale.LC_TIME",           &c->locale[VARIABLE_LC_TIME],
42
                                      "locale.LC_COLLATE",        &c->locale[VARIABLE_LC_COLLATE],
43
                                      "locale.LC_MONETARY",       &c->locale[VARIABLE_LC_MONETARY],
44
                                      "locale.LC_MESSAGES",       &c->locale[VARIABLE_LC_MESSAGES],
45
                                      "locale.LC_PAPER",          &c->locale[VARIABLE_LC_PAPER],
46
                                      "locale.LC_NAME",           &c->locale[VARIABLE_LC_NAME],
47
                                      "locale.LC_ADDRESS",        &c->locale[VARIABLE_LC_ADDRESS],
48
                                      "locale.LC_TELEPHONE",      &c->locale[VARIABLE_LC_TELEPHONE],
49
                                      "locale.LC_MEASUREMENT",    &c->locale[VARIABLE_LC_MEASUREMENT],
50
                                      "locale.LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
51
        if (r == -ENOENT)
846✔
52
                return 0;
53
        if (r < 0)
846✔
UNCOV
54
                return log_debug_errno(r, "Failed to read /proc/cmdline: %m");
×
55
        return r;
56
}
57

58
static int locale_context_load_conf(LocaleContext *c, LocaleLoadFlag flag) {
1,117✔
59
        _cleanup_close_ int fd = -EBADF;
1,117✔
60
        struct stat st;
1,117✔
61
        int r;
1,117✔
62

63
        assert(c);
1,117✔
64

65
        if (!FLAGS_SET(flag, LOCALE_LOAD_LOCALE_CONF))
1,117✔
66
                return 0;
67

68
        fd = RET_NERRNO(open("/etc/locale.conf", O_CLOEXEC | O_PATH));
862✔
69
        if (fd == -ENOENT)
2✔
70
                return 0;
71
        if (fd < 0)
860✔
UNCOV
72
                return log_debug_errno(errno, "Failed to open /etc/locale.conf: %m");
×
73

74
        if (fstat(fd, &st) < 0)
860✔
UNCOV
75
                return log_debug_errno(errno, "Failed to stat /etc/locale.conf: %m");
×
76

77
        /* If the file is not changed, then we do not need to re-read the file. */
78
        if (stat_inode_unmodified(&c->st, &st))
860✔
79
                return 1; /* (already) loaded */
80

81
        c->st = st;
592✔
82
        locale_context_clear(c);
592✔
83

84
        r = parse_env_file_fd(fd, "/etc/locale.conf",
592✔
85
                              "LANG",              &c->locale[VARIABLE_LANG],
86
                              "LANGUAGE",          &c->locale[VARIABLE_LANGUAGE],
87
                              "LC_CTYPE",          &c->locale[VARIABLE_LC_CTYPE],
88
                              "LC_NUMERIC",        &c->locale[VARIABLE_LC_NUMERIC],
89
                              "LC_TIME",           &c->locale[VARIABLE_LC_TIME],
90
                              "LC_COLLATE",        &c->locale[VARIABLE_LC_COLLATE],
91
                              "LC_MONETARY",       &c->locale[VARIABLE_LC_MONETARY],
92
                              "LC_MESSAGES",       &c->locale[VARIABLE_LC_MESSAGES],
93
                              "LC_PAPER",          &c->locale[VARIABLE_LC_PAPER],
94
                              "LC_NAME",           &c->locale[VARIABLE_LC_NAME],
95
                              "LC_ADDRESS",        &c->locale[VARIABLE_LC_ADDRESS],
96
                              "LC_TELEPHONE",      &c->locale[VARIABLE_LC_TELEPHONE],
97
                              "LC_MEASUREMENT",    &c->locale[VARIABLE_LC_MEASUREMENT],
98
                              "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
99
        if (r < 0)
592✔
UNCOV
100
                return log_debug_errno(r, "Failed to read /etc/locale.conf: %m");
×
101

102
        return 1; /* loaded */
103
}
104

105
static int locale_context_load_env(LocaleContext *c, LocaleLoadFlag flag) {
257✔
106
        int r;
257✔
107

108
        assert(c);
257✔
109

110
        if (!FLAGS_SET(flag, LOCALE_LOAD_ENVIRONMENT))
257✔
111
                return 0;
112

113
        locale_context_clear(c);
2✔
114

115
        /* Fill in what we got passed from systemd. */
116
        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
30✔
117
                const char *name = ASSERT_PTR(locale_variable_to_string(p));
28✔
118

119
                r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name)));
30✔
120
                if (r < 0)
28✔
UNCOV
121
                        return log_oom_debug();
×
122
        }
123

124
        return 1; /* loaded */
125
}
126

127
int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) {
1,118✔
128
        int r;
1,118✔
129

130
        assert(c);
1,118✔
131

132
        r = locale_context_load_proc(c, flag);
1,118✔
133
        if (r > 0)
1,118✔
134
                goto finalize;
1✔
135

136
        r = locale_context_load_conf(c, flag);
1,117✔
137
        if (r != 0)
1,117✔
138
                goto finalize;
860✔
139

140
        r = locale_context_load_env(c, flag);
257✔
141

142
finalize:
1,117✔
143
        if (r <= 0) {
1,118✔
144
                /* Nothing loaded, or error. */
145
                locale_context_clear(c);
255✔
146
                return r;
255✔
147
        }
148

149
        if (FLAGS_SET(flag, LOCALE_LOAD_SIMPLIFY))
863✔
150
                locale_variables_simplify(c->locale);
272✔
151

152
        return 0;
153
}
154

155
int locale_context_build_env(const LocaleContext *c, char ***ret_set, char ***ret_unset) {
1,118✔
156
        _cleanup_strv_free_ char **set = NULL, **unset = NULL;
1,118✔
157
        int r;
1,118✔
158

159
        assert(c);
1,118✔
160

161
        if (!ret_set && !ret_unset)
1,118✔
162
                return 0;
163

164
        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
16,770✔
165
                const char *name = ASSERT_PTR(locale_variable_to_string(p));
15,652✔
166

167
                if (isempty(c->locale[p])) {
15,652✔
168
                        if (!ret_unset)
14,778✔
169
                                continue;
14,677✔
170
                        r = strv_extend(&unset, name);
101✔
171
                } else {
172
                        if (!ret_set)
874✔
UNCOV
173
                                continue;
×
174
                        r = strv_env_assign(&set, name, c->locale[p]);
874✔
175
                }
176
                if (r < 0)
975✔
177
                        return r;
178
        }
179

180
        if (ret_set)
1,118✔
181
                *ret_set = TAKE_PTR(set);
1,118✔
182
        if (ret_unset)
1,118✔
183
                *ret_unset = TAKE_PTR(unset);
8✔
184
        return 0;
185
}
186

187
int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) {
8✔
188
        _cleanup_strv_free_ char **set = NULL, **unset = NULL;
8✔
189
        int r;
8✔
190

191
        assert(c);
8✔
192

193
        /* Set values will be returned as strv in *ret on success. */
194

195
        r = locale_context_build_env(c, &set, ret_unset ? &unset : NULL);
8✔
196
        if (r < 0)
8✔
197
                return r;
198

199
        if (strv_isempty(set)) {
8✔
200
                if (unlink("/etc/locale.conf") < 0)
×
UNCOV
201
                        return errno == ENOENT ? 0 : -errno;
×
202

UNCOV
203
                c->st = (struct stat) {};
×
204

205
                if (ret_set)
×
206
                        *ret_set = NULL;
×
207
                if (ret_unset)
×
208
                        *ret_unset = NULL;
×
UNCOV
209
                return 0;
×
210
        }
211

212
        r = write_env_file_label(AT_FDCWD, "/etc/locale.conf", NULL, set);
8✔
213
        if (r < 0)
8✔
214
                return r;
215

216
        if (stat("/etc/locale.conf", &c->st) < 0)
8✔
UNCOV
217
                return -errno;
×
218

219
        if (ret_set)
8✔
220
                *ret_set = TAKE_PTR(set);
8✔
221
        if (ret_unset)
8✔
222
                *ret_unset = TAKE_PTR(unset);
8✔
223
        return 0;
224
}
225

226
int locale_context_merge(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
8✔
227
        assert(c);
8✔
228
        assert(l);
8✔
229

230
        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
120✔
231
                if (!isempty(c->locale[p]) && isempty(l[p])) {
134✔
232
                        l[p] = strdup(c->locale[p]);
2✔
233
                        if (!l[p])
2✔
234
                                return -ENOMEM;
235
                }
236

237
        return 0;
238
}
239

240
void locale_context_take(LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
8✔
241
        assert(c);
8✔
242
        assert(l);
8✔
243

244
        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
120✔
245
                free_and_replace(c->locale[p], l[p]);
112✔
246
}
8✔
247

248
bool locale_context_equal(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
8✔
249
        assert(c);
8✔
250
        assert(l);
8✔
251

252
        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
8✔
253
                if (!streq_ptr(c->locale[p], l[p]))
8✔
254
                        return false;
255

256
        return true;
257
}
258

259
int locale_setup(char ***environment) {
590✔
260
        _cleanup_(locale_context_clear) LocaleContext c = {};
590✔
UNCOV
261
        _cleanup_strv_free_ char **add = NULL;
×
262
        int r;
590✔
263

264
        assert(environment);
590✔
265

266
        r = locale_context_load(&c, LOCALE_LOAD_PROC_CMDLINE | LOCALE_LOAD_LOCALE_CONF);
590✔
267
        if (r < 0)
590✔
268
                return r;
269

270
        r = locale_context_build_env(&c, &add, NULL);
590✔
271
        if (r < 0)
590✔
272
                return r;
273

274
        if (strv_isempty(add)) {
590✔
275
                /* If no locale is configured then default to compile-time default. */
276

277
                add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE);
×
UNCOV
278
                if (!add)
×
279
                        return -ENOMEM;
280
        }
281

282
        if (strv_isempty(*environment))
590✔
UNCOV
283
                strv_free_and_replace(*environment, add);
×
284
        else {
285
                char **merged;
590✔
286

287
                merged = strv_env_merge(*environment, add);
590✔
288
                if (!merged)
590✔
289
                        return -ENOMEM;
590✔
290

291
                strv_free_and_replace(*environment, merged);
590✔
292
        }
293

294
        return 0;
295
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc