1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <stdlib.h>
5
6 #include "env-file.h"
7 #include "env-util.h"
8 #include "locale-setup.h"
9 #include "locale-util.h"
10 #include "proc-cmdline.h"
11 #include "string-util.h"
12 #include "strv.h"
13 #include "util.h"
14 #include "virt.h"
15
locale_setup(char *** environment)16 int locale_setup(char ***environment) {
17 _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {};
18 _cleanup_strv_free_ char **add = NULL;
19 int r;
20
21 r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX,
22 "locale.LANG", &variables[VARIABLE_LANG],
23 "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
24 "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
25 "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
26 "locale.LC_TIME", &variables[VARIABLE_LC_TIME],
27 "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
28 "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
29 "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
30 "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
31 "locale.LC_NAME", &variables[VARIABLE_LC_NAME],
32 "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
33 "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
34 "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
35 "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
36 if (r < 0 && r != -ENOENT)
37 log_warning_errno(r, "Failed to read /proc/cmdline: %m");
38
39 /* Hmm, nothing set on the kernel cmd line? Then let's try /etc/locale.conf */
40 if (r <= 0) {
41 r = parse_env_file(NULL, "/etc/locale.conf",
42 "LANG", &variables[VARIABLE_LANG],
43 "LANGUAGE", &variables[VARIABLE_LANGUAGE],
44 "LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
45 "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
46 "LC_TIME", &variables[VARIABLE_LC_TIME],
47 "LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
48 "LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
49 "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
50 "LC_PAPER", &variables[VARIABLE_LC_PAPER],
51 "LC_NAME", &variables[VARIABLE_LC_NAME],
52 "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
53 "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
54 "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
55 "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
56 if (r < 0 && r != -ENOENT)
57 log_warning_errno(r, "Failed to read /etc/locale.conf: %m");
58 }
59
60 for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) {
61 char *s;
62
63 if (!variables[i])
64 continue;
65
66 s = strjoin(locale_variable_to_string(i), "=", variables[i]);
67 if (!s)
68 return -ENOMEM;
69
70 if (strv_consume(&add, s) < 0)
71 return -ENOMEM;
72 }
73
74 if (strv_isempty(add)) {
75 /* If no locale is configured then default to compile-time default. */
76
77 add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE);
78 if (!add)
79 return -ENOMEM;
80 }
81
82 if (strv_isempty(*environment))
83 strv_free_and_replace(*environment, add);
84 else {
85 char **merged;
86
87 merged = strv_env_merge(*environment, add);
88 if (!merged)
89 return -ENOMEM;
90
91 strv_free_and_replace(*environment, merged);
92 }
93
94 return 0;
95 }
96