Merge pull request #23709 from yuwata/test-hostname-locale

test: import hostname and locale tests from debian/ubuntu test suite
This commit is contained in:
Yu Watanabe
2022-06-15 12:00:22 +09:00
committed by GitHub
29 changed files with 1103 additions and 435 deletions
+38 -15
View File
@@ -160,7 +160,7 @@ static int add_locales_from_archive(Set *locales) {
return r;
}
static int add_locales_from_libdir (Set *locales) {
static int add_locales_from_libdir(Set *locales) {
_cleanup_closedir_ DIR *dir = NULL;
int r;
@@ -187,7 +187,7 @@ static int add_locales_from_libdir (Set *locales) {
}
int get_locales(char ***ret) {
_cleanup_set_free_ Set *locales = NULL;
_cleanup_set_free_free_ Set *locales = NULL;
_cleanup_strv_free_ char **l = NULL;
int r;
@@ -203,10 +203,22 @@ int get_locales(char ***ret) {
if (r < 0)
return r;
char *locale;
SET_FOREACH(locale, locales) {
r = locale_is_installed(locale);
if (r < 0)
return r;
if (r == 0)
free(set_remove(locales, locale));
}
l = set_get_strv(locales);
if (!l)
return -ENOMEM;
/* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */
locales = set_free(locales);
r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES");
if (r == -ENXIO || r == 0) {
char **a, **b;
@@ -327,20 +339,31 @@ void locale_variables_free(char *l[_VARIABLE_LC_MAX]) {
l[i] = mfree(l[i]);
}
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]) {
assert(l);
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
if (p == VARIABLE_LANG)
continue;
if (isempty(l[p]) || streq_ptr(l[VARIABLE_LANG], l[p]))
l[p] = mfree(l[p]);
}
}
static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
[VARIABLE_LANG] = "LANG",
[VARIABLE_LANGUAGE] = "LANGUAGE",
[VARIABLE_LC_CTYPE] = "LC_CTYPE",
[VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
[VARIABLE_LC_TIME] = "LC_TIME",
[VARIABLE_LC_COLLATE] = "LC_COLLATE",
[VARIABLE_LC_MONETARY] = "LC_MONETARY",
[VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
[VARIABLE_LC_PAPER] = "LC_PAPER",
[VARIABLE_LC_NAME] = "LC_NAME",
[VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
[VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
[VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
[VARIABLE_LANG] = "LANG",
[VARIABLE_LANGUAGE] = "LANGUAGE",
[VARIABLE_LC_CTYPE] = "LC_CTYPE",
[VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
[VARIABLE_LC_TIME] = "LC_TIME",
[VARIABLE_LC_COLLATE] = "LC_COLLATE",
[VARIABLE_LC_MONETARY] = "LC_MONETARY",
[VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
[VARIABLE_LC_PAPER] = "LC_PAPER",
[VARIABLE_LC_NAME] = "LC_NAME",
[VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
[VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
[VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
[VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
};
+1
View File
@@ -53,3 +53,4 @@ void locale_variables_free(char* l[_VARIABLE_LC_MAX]);
static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) {
locale_variables_free(*l);
}
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]);
-95
View File
@@ -1,95 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdlib.h>
#include "env-file.h"
#include "env-util.h"
#include "locale-setup.h"
#include "locale-util.h"
#include "proc-cmdline.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
#include "virt.h"
int locale_setup(char ***environment) {
_cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {};
_cleanup_strv_free_ char **add = NULL;
int r;
r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX,
"locale.LANG", &variables[VARIABLE_LANG],
"locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
"locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
"locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
"locale.LC_TIME", &variables[VARIABLE_LC_TIME],
"locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
"locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
"locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
"locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
"locale.LC_NAME", &variables[VARIABLE_LC_NAME],
"locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
"locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
"locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
"locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read /proc/cmdline: %m");
/* Hmm, nothing set on the kernel cmd line? Then let's try /etc/locale.conf */
if (r <= 0) {
r = parse_env_file(NULL, "/etc/locale.conf",
"LANG", &variables[VARIABLE_LANG],
"LANGUAGE", &variables[VARIABLE_LANGUAGE],
"LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
"LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
"LC_TIME", &variables[VARIABLE_LC_TIME],
"LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
"LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
"LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
"LC_PAPER", &variables[VARIABLE_LC_PAPER],
"LC_NAME", &variables[VARIABLE_LC_NAME],
"LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
"LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
"LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
"LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read /etc/locale.conf: %m");
}
for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) {
char *s;
if (!variables[i])
continue;
s = strjoin(locale_variable_to_string(i), "=", variables[i]);
if (!s)
return -ENOMEM;
if (strv_consume(&add, s) < 0)
return -ENOMEM;
}
if (strv_isempty(add)) {
/* If no locale is configured then default to compile-time default. */
add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE);
if (!add)
return -ENOMEM;
}
if (strv_isempty(*environment))
strv_free_and_replace(*environment, add);
else {
char **merged;
merged = strv_env_merge(*environment, add);
if (!merged)
return -ENOMEM;
strv_free_and_replace(*environment, merged);
}
return 0;
}
-4
View File
@@ -1,4 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int locale_setup(char ***environment);
-2
View File
@@ -85,8 +85,6 @@ libcore_sources = files(
'load-dropin.h',
'load-fragment.c',
'load-fragment.h',
'locale-setup.c',
'locale-setup.h',
'manager-dump.c',
'manager-dump.h',
'manager-serialize.c',
+92 -62
View File
@@ -2,7 +2,6 @@
#include <getopt.h>
#include <stdbool.h>
#include <stdlib.h>
#include "sd-bus.h"
@@ -11,8 +10,9 @@
#include "bus-map-properties.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "kbd-util.h"
#include "locale-util.h"
#include "locale-setup.h"
#include "main-func.h"
#include "memory-util.h"
#include "pager.h"
@@ -51,69 +51,102 @@ static void status_info_clear(StatusInfo *info) {
}
}
static void print_overridden_variables(void) {
_cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {};
bool print_warning = true;
static int print_status_info(StatusInfo *i) {
_cleanup_strv_free_ char **kernel_locale = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
TableCell *cell;
int r;
if (arg_transport != BUS_TRANSPORT_LOCAL)
return;
r = proc_cmdline_get_key_many(
PROC_CMDLINE_STRIP_RD_PREFIX,
"locale.LANG", &variables[VARIABLE_LANG],
"locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
"locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
"locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
"locale.LC_TIME", &variables[VARIABLE_LC_TIME],
"locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
"locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
"locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
"locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
"locale.LC_NAME", &variables[VARIABLE_LC_NAME],
"locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
"locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
"locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
"locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
if (r < 0 && r != -ENOENT) {
log_warning_errno(r, "Failed to read /proc/cmdline: %m");
return;
}
for (LocaleVariable j = 0; j < _VARIABLE_LC_MAX; j++)
if (variables[j]) {
if (print_warning) {
log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n"
" Command Line: %s=%s", locale_variable_to_string(j), variables[j]);
print_warning = false;
} else
log_warning(" %s=%s", locale_variable_to_string(j), variables[j]);
}
}
static void print_status_info(StatusInfo *i) {
assert(i);
if (strv_isempty(i->locale))
puts(" System Locale: n/a");
else {
printf(" System Locale: %s\n", i->locale[0]);
STRV_FOREACH(j, i->locale + 1)
printf(" %s\n", *j);
if (arg_transport == BUS_TRANSPORT_LOCAL) {
_cleanup_(locale_context_clear) LocaleContext c = { .mtime = USEC_INFINITY };
r = locale_context_load(&c, LOCALE_LOAD_PROC_CMDLINE);
if (r < 0)
return log_error_errno(r, "Failed to read /proc/cmdline: %m");
r = locale_context_build_env(&c, &kernel_locale, NULL);
if (r < 0)
return log_error_errno(r, "Failed to build locale settings from kernel command line: %m");
}
printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
if (!isempty(i->vconsole_keymap_toggle))
printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
table = table_new("key", "value");
if (!table)
return log_oom();
printf(" X11 Layout: %s\n", strna(i->x11_layout));
if (!isempty(i->x11_model))
printf(" X11 Model: %s\n", i->x11_model);
if (!isempty(i->x11_variant))
printf(" X11 Variant: %s\n", i->x11_variant);
if (!isempty(i->x11_options))
printf(" X11 Options: %s\n", i->x11_options);
assert_se(cell = table_get_cell(table, 0, 0));
(void) table_set_ellipsize_percent(table, cell, 100);
(void) table_set_align_percent(table, cell, 100);
table_set_header(table, false);
r = table_set_empty_string(table, "n/a");
if (r < 0)
return log_oom();
if (!strv_isempty(kernel_locale)) {
log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.");
r = table_add_many(table,
TABLE_STRING, "Command Line:",
TABLE_SET_COLOR, ansi_highlight_yellow(),
TABLE_STRV, kernel_locale,
TABLE_SET_COLOR, ansi_highlight_yellow());
if (r < 0)
return table_log_add_error(r);
}
r = table_add_many(table,
TABLE_STRING, "System Locale:",
TABLE_STRV, i->locale,
TABLE_STRING, "VC Keymap:",
TABLE_STRING, i->vconsole_keymap);
if (r < 0)
return table_log_add_error(r);
if (!isempty(i->vconsole_keymap_toggle)) {
r = table_add_many(table,
TABLE_STRING, "VC Toggle Keymap:",
TABLE_STRING, i->vconsole_keymap_toggle);
if (r < 0)
return table_log_add_error(r);
}
r = table_add_many(table,
TABLE_STRING, "X11 Layout:",
TABLE_STRING, i->x11_layout);
if (r < 0)
return table_log_add_error(r);
if (!isempty(i->x11_model)) {
r = table_add_many(table,
TABLE_STRING, "X11 Model:",
TABLE_STRING, i->x11_model);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->x11_variant)) {
r = table_add_many(table,
TABLE_STRING, "X11 Variant:",
TABLE_STRING, i->x11_variant);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->x11_options)) {
r = table_add_many(table,
TABLE_STRING, "X11 Options:",
TABLE_STRING, i->x11_options);
if (r < 0)
return table_log_add_error(r);
}
r = table_print(table, NULL);
if (r < 0)
return table_log_print_error(r);
return 0;
}
static int show_status(int argc, char **argv, void *userdata) {
@@ -147,10 +180,7 @@ static int show_status(int argc, char **argv, void *userdata) {
if (r < 0)
return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
print_overridden_variables();
print_status_info(&info);
return r;
return print_status_info(&info);
}
static int set_locale(int argc, char **argv, void *userdata) {
@@ -15,8 +15,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "kbd-util.h"
#include "keymap-util.h"
#include "locale-util.h"
#include "localed-util.h"
#include "macro.h"
#include "mkdir-label.h"
#include "nulstr-util.h"
@@ -65,13 +64,8 @@ static void context_free_vconsole(Context *c) {
c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
}
static void context_free_locale(Context *c) {
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
c->locale[p] = mfree(c->locale[p]);
}
void context_clear(Context *c) {
context_free_locale(c);
locale_context_clear(&c->locale_context);
context_free_x11(c);
context_free_vconsole(c);
@@ -82,15 +76,8 @@ void context_clear(Context *c) {
bus_verify_polkit_async_registry_free(c->polkit_registry);
};
void locale_simplify(char *locale[_VARIABLE_LC_MAX]) {
for (LocaleVariable p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++)
if (isempty(locale[p]) || streq_ptr(locale[VARIABLE_LANG], locale[p]))
locale[p] = mfree(locale[p]);
}
int locale_read_data(Context *c, sd_bus_message *m) {
struct stat st;
int r;
assert(c);
/* Do not try to re-read the file within single bus operation. */
if (m) {
@@ -101,57 +88,7 @@ int locale_read_data(Context *c, sd_bus_message *m) {
c->locale_cache = sd_bus_message_ref(m);
}
r = stat("/etc/locale.conf", &st);
if (r < 0 && errno != ENOENT)
return -errno;
if (r >= 0) {
usec_t t;
/* If mtime is not changed, then we do not need to re-read the file. */
t = timespec_load(&st.st_mtim);
if (c->locale_mtime != USEC_INFINITY && t == c->locale_mtime)
return 0;
c->locale_mtime = t;
context_free_locale(c);
r = parse_env_file(NULL, "/etc/locale.conf",
"LANG", &c->locale[VARIABLE_LANG],
"LANGUAGE", &c->locale[VARIABLE_LANGUAGE],
"LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE],
"LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC],
"LC_TIME", &c->locale[VARIABLE_LC_TIME],
"LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE],
"LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY],
"LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES],
"LC_PAPER", &c->locale[VARIABLE_LC_PAPER],
"LC_NAME", &c->locale[VARIABLE_LC_NAME],
"LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS],
"LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE],
"LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT],
"LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
if (r < 0)
return r;
} else {
c->locale_mtime = USEC_INFINITY;
context_free_locale(c);
/* Fill in what we got passed from systemd. */
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
const char *name;
name = locale_variable_to_string(p);
assert(name);
r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name)));
if (r < 0)
return r;
}
}
locale_simplify(c->locale);
return 0;
return locale_context_load(&c->locale_context, LOCALE_LOAD_LOCALE_CONF | LOCALE_LOAD_ENVIRONMENT | LOCALE_LOAD_SIMPLIFY);
}
int vconsole_read_data(Context *c, sd_bus_message *m) {
@@ -280,40 +217,6 @@ int x11_read_data(Context *c, sd_bus_message *m) {
return 0;
}
int locale_write_data(Context *c, char ***settings) {
_cleanup_strv_free_ char **l = NULL;
struct stat st;
int r;
/* Set values will be returned as strv in *settings on success. */
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!isempty(c->locale[p])) {
r = strv_env_assign(&l, locale_variable_to_string(p), c->locale[p]);
if (r < 0)
return r;
}
if (strv_isempty(l)) {
if (unlink("/etc/locale.conf") < 0)
return errno == ENOENT ? 0 : -errno;
c->locale_mtime = USEC_INFINITY;
return 0;
}
r = write_env_file_label("/etc/locale.conf", l);
if (r < 0)
return r;
*settings = TAKE_PTR(l);
if (stat("/etc/locale.conf", &st) >= 0)
c->locale_mtime = timespec_load(&st.st_mtim);
return 0;
}
int vconsole_write_data(Context *c) {
_cleanup_strv_free_ char **l = NULL;
struct stat st;
@@ -4,13 +4,12 @@
#include "sd-bus.h"
#include "hashmap.h"
#include "locale-util.h"
#include "locale-setup.h"
#include "time-util.h"
typedef struct Context {
sd_bus_message *locale_cache;
usec_t locale_mtime;
char *locale[_VARIABLE_LC_MAX];
LocaleContext locale_context;
sd_bus_message *x11_cache;
usec_t x11_mtime;
@@ -40,8 +39,6 @@ int vconsole_convert_to_x11(Context *c);
int vconsole_write_data(Context *c);
int x11_convert_to_vconsole(Context *c);
int x11_write_data(Context *c);
void locale_simplify(char *locale[_VARIABLE_LC_MAX]);
int locale_write_data(Context *c, char ***settings);
bool locale_gen_check_available(void);
int locale_gen_enable_locale(const char *locale);
+17 -72
View File
@@ -20,8 +20,7 @@
#include "def.h"
#include "dlfcn-util.h"
#include "kbd-util.h"
#include "keymap-util.h"
#include "locale-util.h"
#include "localed-util.h"
#include "macro.h"
#include "main-func.h"
#include "missing_capability.h"
@@ -33,44 +32,13 @@
#include "strv.h"
#include "user-util.h"
static int locale_update_system_manager(Context *c, sd_bus *bus) {
_cleanup_free_ char **l_unset = NULL;
_cleanup_strv_free_ char **l_set = NULL;
static int locale_update_system_manager(sd_bus *bus, char **l_set, char **l_unset) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
size_t c_set = 0, c_unset = 0;
int r;
assert(bus);
l_unset = new0(char*, _VARIABLE_LC_MAX);
if (!l_unset)
return log_oom();
l_set = new0(char*, _VARIABLE_LC_MAX);
if (!l_set)
return log_oom();
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
const char *name;
name = locale_variable_to_string(p);
assert(name);
if (isempty(c->locale[p]))
l_unset[c_set++] = (char*) name;
else {
char *s;
s = strjoin(name, "=", c->locale[p]);
if (!s)
return log_oom();
l_set[c_unset++] = s;
}
}
assert(c_set + c_unset == _VARIABLE_LC_MAX);
r = sd_bus_message_new_method_call(bus, &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
@@ -188,21 +156,9 @@ static int property_get_locale(
if (!l)
return -ENOMEM;
for (LocaleVariable p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) {
char *t;
const char *name;
name = locale_variable_to_string(p);
assert(name);
if (isempty(c->locale[p]))
continue;
if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0)
return -ENOMEM;
l[q++] = t;
}
r = locale_context_build_env(&c->locale_context, &l, NULL);
if (r < 0)
return r;
return sd_bus_message_append_strv(reply, l);
}
@@ -342,9 +298,8 @@ static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX],
static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {};
_cleanup_strv_free_ char **settings = NULL, **l = NULL;
_cleanup_strv_free_ char **l = NULL, **l_set = NULL, **l_unset = NULL;
Context *c = userdata;
bool modified = false;
int interactive, r;
bool use_localegen;
@@ -402,22 +357,13 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
}
/* Merge with the current settings */
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!isempty(c->locale[p]) && isempty(new_locale[p])) {
new_locale[p] = strdup(c->locale[p]);
if (!new_locale[p])
return -ENOMEM;
}
r = locale_context_merge(&c->locale_context, new_locale);
if (r < 0)
return r;
locale_simplify(new_locale);
locale_variables_simplify(new_locale);
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!streq_ptr(c->locale[p], new_locale[p])) {
modified = true;
break;
}
if (!modified) {
if (locale_context_equal(&c->locale_context, new_locale)) {
log_debug("Locale settings were not modified.");
return sd_bus_reply_method_return(m, NULL);
}
@@ -443,22 +389,21 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
return r;
}
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
free_and_replace(c->locale[p], new_locale[p]);
locale_context_take(&c->locale_context, new_locale);
/* Write locale configuration */
r = locale_write_data(c, &settings);
r = locale_context_save(&c->locale_context, &l_set, &l_unset);
if (r < 0) {
log_error_errno(r, "Failed to set locale: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set locale: %m");
}
(void) locale_update_system_manager(c, sd_bus_message_get_bus(m));
(void) locale_update_system_manager(sd_bus_message_get_bus(m), l_set, l_unset);
if (settings) {
if (!strv_isempty(l_set)) {
_cleanup_free_ char *line = NULL;
line = strv_join(settings, ", ");
line = strv_join(l_set, ", ");
log_info("Changed locale to %s.", strnull(line));
} else
log_info("Changed locale to unset.");
@@ -827,7 +772,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {
.locale_mtime = USEC_INFINITY,
.locale_context.mtime = USEC_INFINITY,
.vc_mtime = USEC_INFINITY,
.x11_mtime = USEC_INFINITY,
};
+5 -5
View File
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
systemd_localed_sources = files(
'localed-util.c',
'localed-util.h',
'localed.c',
'keymap-util.c',
'keymap-util.h',
)
localectl_sources = files('localectl.c')
@@ -30,7 +30,7 @@ if conf.get('ENABLE_LOCALED') == 1
endif
tests += [
[files('test-keymap-util.c',
'keymap-util.c',
'keymap-util.h')],
[files('test-localed-util.c',
'localed-util.c',
'localed-util.h')],
]
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "keymap-util.h"
#include "localed-util.h"
#include "log.h"
#include "string-util.h"
#include "tests.h"
+256
View File
@@ -0,0 +1,256 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <sys/stat.h>
#include "env-file-label.h"
#include "env-file.h"
#include "env-util.h"
#include "locale-setup.h"
#include "proc-cmdline.h"
#include "strv.h"
void locale_context_clear(LocaleContext *c) {
assert(c);
c->mtime = USEC_INFINITY;
for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++)
c->locale[i] = mfree(c->locale[i]);
}
int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) {
int r;
assert(c);
if (FLAGS_SET(flag, LOCALE_LOAD_PROC_CMDLINE)) {
locale_context_clear(c);
r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX,
"locale.LANG", &c->locale[VARIABLE_LANG],
"locale.LANGUAGE", &c->locale[VARIABLE_LANGUAGE],
"locale.LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE],
"locale.LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC],
"locale.LC_TIME", &c->locale[VARIABLE_LC_TIME],
"locale.LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE],
"locale.LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY],
"locale.LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES],
"locale.LC_PAPER", &c->locale[VARIABLE_LC_PAPER],
"locale.LC_NAME", &c->locale[VARIABLE_LC_NAME],
"locale.LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS],
"locale.LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE],
"locale.LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT],
"locale.LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
if (r > 0)
goto finalize;
}
if (FLAGS_SET(flag, LOCALE_LOAD_LOCALE_CONF)) {
struct stat st;
usec_t t;
r = stat("/etc/locale.conf", &st);
if (r < 0 && errno != ENOENT)
return log_debug_errno(errno, "Failed to stat /etc/locale.conf: %m");
if (r >= 0) {
/* If mtime is not changed, then we do not need to re-read the file. */
t = timespec_load(&st.st_mtim);
if (c->mtime != USEC_INFINITY && t == c->mtime)
return 0;
locale_context_clear(c);
c->mtime = t;
r = parse_env_file(NULL, "/etc/locale.conf",
"LANG", &c->locale[VARIABLE_LANG],
"LANGUAGE", &c->locale[VARIABLE_LANGUAGE],
"LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE],
"LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC],
"LC_TIME", &c->locale[VARIABLE_LC_TIME],
"LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE],
"LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY],
"LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES],
"LC_PAPER", &c->locale[VARIABLE_LC_PAPER],
"LC_NAME", &c->locale[VARIABLE_LC_NAME],
"LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS],
"LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE],
"LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT],
"LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
if (r < 0)
return log_debug_errno(r, "Failed to read /etc/locale.conf: %m");
goto finalize;
}
}
if (FLAGS_SET(flag, LOCALE_LOAD_ENVIRONMENT)) {
locale_context_clear(c);
/* Fill in what we got passed from systemd. */
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
const char *name = ASSERT_PTR(locale_variable_to_string(p));
r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name)));
if (r < 0)
return log_oom_debug();
}
goto finalize;
}
/* Nothing loaded. */
locale_context_clear(c);
return 0;
finalize:
if (FLAGS_SET(flag, LOCALE_LOAD_SIMPLIFY))
locale_variables_simplify(c->locale);
return 0;
}
int locale_context_build_env(const LocaleContext *c, char ***ret_set, char ***ret_unset) {
_cleanup_strv_free_ char **set = NULL, **unset = NULL;
int r;
assert(c);
if (!ret_set && !ret_unset)
return 0;
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
const char *name = ASSERT_PTR(locale_variable_to_string(p));
if (isempty(c->locale[p])) {
if (!ret_unset)
continue;
r = strv_extend(&unset, name);
} else {
if (!ret_set)
continue;
r = strv_env_assign(&set, name, c->locale[p]);
}
if (r < 0)
return r;
}
if (ret_set)
*ret_set = TAKE_PTR(set);
if (ret_unset)
*ret_unset = TAKE_PTR(unset);
return 0;
}
int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) {
_cleanup_strv_free_ char **set = NULL, **unset = NULL;
struct stat st;
int r;
assert(c);
/* Set values will be returned as strv in *ret on success. */
r = locale_context_build_env(c, &set, ret_unset ? &unset : NULL);
if (r < 0)
return r;
if (strv_isempty(set)) {
if (unlink("/etc/locale.conf") < 0)
return errno == ENOENT ? 0 : -errno;
c->mtime = USEC_INFINITY;
if (ret_set)
*ret_set = NULL;
if (ret_unset)
*ret_unset = NULL;
return 0;
}
r = write_env_file_label("/etc/locale.conf", set);
if (r < 0)
return r;
if (stat("/etc/locale.conf", &st) >= 0)
c->mtime = timespec_load(&st.st_mtim);
if (ret_set)
*ret_set = TAKE_PTR(set);
if (ret_unset)
*ret_unset = TAKE_PTR(unset);
return 0;
}
int locale_context_merge(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
assert(c);
assert(l);
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!isempty(c->locale[p]) && isempty(l[p])) {
l[p] = strdup(c->locale[p]);
if (!l[p])
return -ENOMEM;
}
return 0;
}
void locale_context_take(LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
assert(c);
assert(l);
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
free_and_replace(c->locale[p], l[p]);
}
bool locale_context_equal(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) {
assert(c);
assert(l);
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!streq_ptr(c->locale[p], l[p]))
return false;
return true;
}
int locale_setup(char ***environment) {
_cleanup_(locale_context_clear) LocaleContext c = { .mtime = USEC_INFINITY };
_cleanup_strv_free_ char **add = NULL;
int r;
assert(environment);
r = locale_context_load(&c, LOCALE_LOAD_PROC_CMDLINE | LOCALE_LOAD_LOCALE_CONF);
if (r < 0)
return r;
r = locale_context_build_env(&c, &add, NULL);
if (r < 0)
return r;
if (strv_isempty(add)) {
/* If no locale is configured then default to compile-time default. */
add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE);
if (!add)
return -ENOMEM;
}
if (strv_isempty(*environment))
strv_free_and_replace(*environment, add);
else {
char **merged;
merged = strv_env_merge(*environment, add);
if (!merged)
return -ENOMEM;
strv_free_and_replace(*environment, merged);
}
return 0;
}
+28
View File
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "locale-util.h"
#include "time-util.h"
typedef struct LocaleContext {
usec_t mtime;
char *locale[_VARIABLE_LC_MAX];
} LocaleContext;
typedef enum LocaleLoadFlag {
LOCALE_LOAD_PROC_CMDLINE = 1 << 0,
LOCALE_LOAD_LOCALE_CONF = 1 << 1,
LOCALE_LOAD_ENVIRONMENT = 1 << 2,
LOCALE_LOAD_SIMPLIFY = 1 << 3,
} LocaleLoadFlag;
void locale_context_clear(LocaleContext *c);
int locale_context_load(LocaleContext *c, LocaleLoadFlag flag);
int locale_context_build_env(const LocaleContext *c, char ***ret_set, char ***ret_unset);
int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset);
int locale_context_merge(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]);
void locale_context_take(LocaleContext *c, char *l[_VARIABLE_LC_MAX]);
bool locale_context_equal(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]);
int locale_setup(char ***environment);
+2
View File
@@ -199,6 +199,8 @@ shared_sources = files(
'linux/ethtool.h',
'local-addresses.c',
'local-addresses.h',
'locale-setup.c',
'locale-setup.h',
'lockfile-util.c',
'lockfile-util.h',
'log-link.h',
+1
View File
@@ -0,0 +1 @@
../TEST-01-BASIC/Makefile
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e
TEST_DESCRIPTION="test hostnamed"
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
do_test "$@"
+1
View File
@@ -0,0 +1 @@
../TEST-01-BASIC/Makefile
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e
TEST_DESCRIPTION="test localed"
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
do_test "$@"
+99 -26
View File
@@ -702,7 +702,9 @@ setup_basic_environment() {
install_pam
install_dbus
install_fonts
install_locales
install_keymaps
install_x11_keymaps
install_terminfo
install_execs
install_fs_tools
@@ -1249,7 +1251,7 @@ install_missing_libraries() {
local lib path
# A number of dependencies is now optional via dlopen, so the install
# script will not pick them up, since it looks at linkage.
for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw; do
for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon; do
ddebug "Searching for $lib via pkg-config"
if pkg-config --exists "$lib"; then
path="$(pkg-config --variable=libdir "$lib")"
@@ -1265,6 +1267,10 @@ install_missing_libraries() {
# (eg: libcryptsetup), so just ignore them
inst_libs "${path}/${lib}.so" || true
inst_library "${path}/${lib}.so" || true
if [[ "$lib" == "libxkbcommon" ]]; then
install_x11_keymaps full
fi
else
ddebug "$lib.pc not found, skipping"
continue
@@ -1911,29 +1917,85 @@ install_pam() {
done
}
install_locales() {
# install only C.UTF-8 and English locales
dinfo "Install locales"
if command -v meson >/dev/null \
&& (meson configure "${BUILD_DIR:?}" | grep 'localegen-path */') \
|| get_bool "$LOOKS_LIKE_DEBIAN"; then
# locale-gen support
image_install -o locale-gen localedef
inst /etc/locale.gen || :
inst /usr/share/i18n/SUPPORTED || :
inst_recursive /usr/share/i18n/charmaps
inst_recursive /usr/share/i18n/locales
inst_recursive /usr/share/locale/en
inst_recursive /usr/share/locale/en_*
fi
inst_recursive /usr/lib/locale/C.utf8
inst_recursive /usr/lib/locale/C.UTF-8
inst_recursive /usr/lib/locale/en_*.utf8
inst_recursive /usr/lib/locale/en_*.UTF-8
}
# shellcheck disable=SC2120
install_keymaps() {
dinfo "Install keymaps"
# The first three paths may be deprecated.
# It seems now the last two paths are used by many distributions.
for i in \
/usr/lib/kbd/keymaps/include/* \
/usr/lib/kbd/keymaps/i386/include/* \
/usr/lib/kbd/keymaps/i386/qwerty/us.* \
/usr/lib/kbd/keymaps/legacy/include/* \
/usr/lib/kbd/keymaps/legacy/i386/qwerty/us.*; do
[[ -f "$i" ]] || continue
inst "$i"
done
local i p
local -a prefix=(
"/usr"
)
# When it takes any argument, then install more keymaps.
if [[ $# -gt 1 ]]; then
for i in \
/usr/lib/kbd/keymaps/i386/*/* \
/usr/lib/kbd/keymaps/legacy/i386/*/*; do
[[ -f "$i" ]] || continue
inst "$i"
dinfo "Install console keymaps"
if command -v meson >/dev/null \
&& [[ "$(meson configure "${BUILD_DIR:?}" | grep 'split-usr' | awk '{ print $2 }')" == "true" ]] \
|| [[ ! -L /lib ]]; then
prefix+=(
""
)
fi
if (( $# == 0 )); then
for p in "${prefix[@]}"; do
# The first three paths may be deprecated.
# It seems now the last three paths are used by many distributions.
for i in \
"$p"/lib/kbd/keymaps/include/* \
"$p"/lib/kbd/keymaps/i386/include/* \
"$p"/lib/kbd/keymaps/i386/qwerty/us.* \
"$p"/lib/kbd/keymaps/legacy/include/* \
"$p"/lib/kbd/keymaps/legacy/i386/qwerty/us.* \
"$p"/lib/kbd/keymaps/xkb/us*; do
[[ -f "$i" ]] || continue
inst "$i"
done
done
else
# When it takes any argument, then install more keymaps.
for p in "${prefix[@]}"; do
for i in \
"$p"/lib/kbd/keymaps/include/* \
"$p"/lib/kbd/keymaps/i386/*/* \
"$p"/lib/kbd/keymaps/legacy/i386/*/* \
"$p"/lib/kbd/keymaps/xkb/*; do
[[ -f "$i" ]] || continue
inst "$i"
done
done
fi
}
install_x11_keymaps() {
dinfo "Install x11 keymaps"
if (( $# == 0 )); then
# Install only keymap list.
inst /usr/share/X11/xkb/rules/base.lst
else
# When it takes any argument, then install all keymaps.
inst_recursive /usr/share/X11/xkb
fi
}
@@ -2259,8 +2321,7 @@ convert_abs_rel() {
__abssize=${#__absolute[@]}
__cursize=${#__current[@]}
while [[ "${__absolute[__level]}" == "${__current[__level]}" ]]
do
while [[ "${__absolute[__level]}" == "${__current[__level]}" ]]; do
(( __level++ ))
if (( __level > __abssize || __level > __cursize ))
then
@@ -2268,8 +2329,7 @@ convert_abs_rel() {
fi
done
for ((__i = __level; __i < __cursize-1; __i++))
do
for ((__i = __level; __i < __cursize-1; __i++)); do
if ((__i > __level))
then
__newpath=$__newpath"/"
@@ -2277,8 +2337,7 @@ convert_abs_rel() {
__newpath=$__newpath".."
done
for ((__i = __level; __i < __abssize; __i++))
do
for ((__i = __level; __i < __abssize; __i++)); do
if [[ -n $__newpath ]]
then
__newpath=$__newpath"/"
@@ -2609,6 +2668,20 @@ inst_any() {
return 1
}
inst_recursive() {
local p item
for p in "$@"; do
while read -r item; do
if [[ -d "$item" ]]; then
inst_dir "$item"
elif [[ -f "$item" ]]; then
inst_simple "$item"
fi
done < <(find "$p" 2>/dev/null)
done
}
# image_install [-o ] <file> [<file> ... ]
# Install <file> to the test image
# -o optionally install the <file> and don't fail, if it is not there
+31 -17
View File
@@ -3,42 +3,56 @@
# utility functions for shell tests
assert_true() {
assert_true() {(
local rc
set +e
set +ex
"$@"
rc=$?
set -e
if [[ "$rc" != "0" ]]; then
if [[ $rc -ne 0 ]]; then
echo "FAIL: command '$*' failed with exit code $rc" >&2
exit 1
fi
}
)}
assert_eq() {
if [[ "$1" != "$2" ]]; then
assert_eq() {(
set +ex
if [[ "${1?}" != "${2?}" ]]; then
echo "FAIL: expected: '$2' actual: '$1'" >&2
exit 1
fi
}
)}
assert_in() {
if ! echo "$2" | grep -q "$1"; then
assert_in() {(
set +ex
if ! [[ "${2?}" =~ ${1?} ]]; then
echo "FAIL: '$1' not found in:" >&2
echo "$2" >&2
exit 1
fi
}
)}
assert_not_in() {(
set +ex
if [[ "${2?}" =~ ${1?} ]]; then
echo "FAIL: '$1' found in:" >&2
echo "$2" >&2
exit 1
fi
)}
assert_rc() {(
local rc exp="${1?}"
set +ex
assert_rc() {
local exp=$1
local rc
shift
set +e
"$@"
rc=$?
set -e
assert_eq "$rc" "$exp"
}
)}
+3 -3
View File
@@ -18,18 +18,18 @@ function check_validity() {
function check() {
local i j
for ((i=0;i<2;i++)); do
for ((i = 0; i < 2; i++)); do
systemctl restart systemd-udevd.service
udevadm control --ping
udevadm settle
check_validity
for ((j=0;j<2;j++)); do
for ((j = 0; j < 2; j++)); do
udevadm trigger -w --action add --subsystem-match=block
check_validity
done
for ((j=0;j<2;j++)); do
for ((j = 0; j < 2; j++)); do
udevadm trigger -w --action change --subsystem-match=block
check_validity
done
+6 -12
View File
@@ -91,7 +91,7 @@ test_suspend_on_lid() {
fi
KILL_PID=
trap test_suspend_tear_down EXIT
trap test_suspend_tear_down RETURN
# create fake suspend
mkdir -p /run/systemd/system/systemd-suspend.service.d
@@ -149,7 +149,7 @@ EOF
evemu-device /run/lidswitch.evemu &
KILL_PID="$!"
for ((i=0;i<20;i++)); do
for ((i = 0; i < 20; i++)); do
if (( i != 0 )); then sleep .5; fi
INPUT_NAME=$(grep -l '^Fake Lid Switch' /sys/class/input/*/device/name || :)
@@ -184,9 +184,6 @@ EOF
echo "logind crashed" >&2
exit 1
fi
test_suspend_tear_down
trap - EXIT
}
test_shutdown() {
@@ -269,7 +266,7 @@ test_session() {
return
fi
trap test_session_tear_down EXIT
trap test_session_tear_down RETURN
# add user
useradd -s /bin/bash logind-test-user
@@ -287,7 +284,7 @@ EOF
# check session
ret=1
for ((i=0;i<30;i++)); do
for ((i = 0; i < 30; i++)); do
if (( i != 0)); then sleep 1; fi
if check_session; then
ret=0
@@ -315,7 +312,7 @@ EOF
# coldplug: logind started with existing device
systemctl stop systemd-logind.service
modprobe scsi_debug
for ((i=0;i<30;i++)); do
for ((i = 0; i < 30; i++)); do
if (( i != 0)); then sleep 1; fi
if dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null); then
break
@@ -342,7 +339,7 @@ EOF
# hotplug: new device appears while logind is running
rmmod scsi_debug
modprobe scsi_debug
for ((i=0;i<30;i++)); do
for ((i = 0; i < 30; i++)); do
if (( i != 0)); then sleep 1; fi
if dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null); then
break
@@ -361,9 +358,6 @@ EOF
getfacl -p "$dev" >&2
exit 1
fi
test_session_tear_down
trap - EXIT
}
: >/failed
+31 -13
View File
@@ -7,9 +7,24 @@ set -o pipefail
# shellcheck source=test/units/assert.sh
. "$(dirname "$0")"/assert.sh
restore_timezone() {
if [[ -f /tmp/timezone.bak ]]; then
mv /tmp/timezone.bak /etc/timezone
else
rm -f /etc/timezone
fi
}
test_timezone() {
local ORIG_TZ=
# Debian/Ubuntu specific file
if [[ -f /etc/timezone ]]; then
mv /etc/timezone /tmp/timezone.bak
fi
trap restore_timezone RETURN
if [[ -L /etc/localtime ]]; then
ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')
echo "original tz: $ORIG_TZ"
@@ -21,12 +36,18 @@ test_timezone() {
echo 'change timezone'
assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" ""
assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev"
assert_in "Time.*zone: Europe/Kiev (EEST, +" "$(timedatectl --no-pager)"
if [[ -f /etc/timezone ]]; then
assert_eq "$(cat /etc/timezone)" "Europe/Kiev"
fi
assert_in "Time zone: Europe/Kiev \(EEST, \+0[0-9]00\)" "$(timedatectl)"
if [[ -n "$ORIG_TZ" ]]; then
echo 'reset timezone to original'
assert_eq "$(timedatectl --no-pager set-timezone "$ORIG_TZ" 2>&1)" ""
assert_eq "$(timedatectl set-timezone "$ORIG_TZ" 2>&1)" ""
assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ"
if [[ -f /etc/timezone ]]; then
assert_eq "$(cat /etc/timezone)" "$ORIG_TZ"
fi
fi
}
@@ -51,7 +72,7 @@ test_adjtime() {
mv /etc/adjtime /etc/adjtime.bak
fi
trap restore_adjtime EXIT
trap restore_adjtime RETURN
echo 'no adjtime file'
rm -f /etc/adjtime
@@ -158,9 +179,6 @@ LOCAL"
assert_eq "$(cat /etc/adjtime)" "0.0 0 0
0
LOCAL"
restore_adjtime
trap - EXIT
}
assert_ntp() {
@@ -173,7 +191,7 @@ start_mon() {
}
wait_mon() {
for ((i=0;i<10;i++)); do
for ((i = 0; i < 10; i++)); do
if (( i != 0 )); then sleep 1; fi
if grep -q "$1" "$mon"; then break; fi
done
@@ -204,13 +222,13 @@ EOF
echo 'disable NTP'
timedatectl set-ntp false
for ((i=0;i<10;i++)); do
for ((i = 0; i < 10; i++)); do
if (( i != 0 )); then sleep 1; fi
if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then
if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then
break;
fi
done
assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=inactive"
assert_eq "$(systemctl show systemd-timesyncd --property ActiveState)" "ActiveState=inactive"
assert_ntp "false"
assert_rc 3 systemctl is-active --quiet systemd-timesyncd
@@ -219,13 +237,13 @@ EOF
timedatectl set-ntp true
wait_mon "NTP" "BOOLEAN true"
assert_ntp "true"
for ((i=0;i<10;i++)); do
for ((i = 0; i < 10; i++)); do
if (( i != 0 )); then sleep 1; fi
if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then
if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then
break;
fi
done
assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=active"
assert_eq "$(systemctl show systemd-timesyncd --property ActiveState)" "ActiveState=active"
assert_rc 0 systemctl is-active --quiet systemd-timesyncd
echo 're-disable NTP'
+1 -1
View File
@@ -27,7 +27,7 @@ inspect() {
}
wait_for_state() {
for ((i=0;i<10;i++)) ; do
for ((i = 0; i < 10; i++)) ; do
homectl inspect "$1" | grep -qF "State: $2" && break
sleep .5
done
+1 -1
View File
@@ -32,7 +32,7 @@ EOF
# Trigger the mount ratelimiting
cd "$(mktemp -d)"
mkdir foo
for ((i=0;i<50;++i)); do
for ((i = 0; i < 50; i++)); do
mount --bind foo foo
umount foo
done
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=TEST-71-HOSTNAME
[Service]
ExecStartPre=rm -f /failed /testok
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
StandardOutput=journal+console
StandardError=journal+console
Type=oneshot
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/assert.sh
. "$(dirname "$0")"/assert.sh
restore_hostname() {
if [[ -e /tmp/hostname.bak ]]; then
mv /tmp/hostname.bak /etc/hostname
else
rm -f /etc/hostname
fi
}
test_hostname() {
local orig=
if [[ -f /etc/hostname ]]; then
cp /etc/hostname /tmp/hostname.bak
orig=$(cat /etc/hostname)
fi
trap restore_hostname RETURN
# should activate daemon and work
if [[ -n "$orig" ]]; then
assert_in "Static hostname: $orig" "$(hostnamectl)"
fi
assert_in "Kernel: $(uname -s) $(uname -r)" "$(hostnamectl)"
# change hostname
assert_rc 0 hostnamectl set-hostname testhost
assert_eq "$(cat /etc/hostname)" "testhost"
assert_in "Static hostname: testhost" "$(hostnamectl)"
if [[ -n "$orig" ]]; then
# reset to original
assert_rc 0 hostnamectl set-hostname "$orig"
assert_eq "$(cat /etc/hostname)" "$orig"
assert_in "Static hostname: $orig" "$(hostnamectl)"
fi
}
: >/failed
test_hostname
touch /testok
rm /failed
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=TEST-73-LOCALE
[Service]
ExecStartPre=rm -f /failed /testok
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
StandardOutput=journal+console
StandardError=journal+console
Type=oneshot
+391
View File
@@ -0,0 +1,391 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/assert.sh
. "$(dirname "$0")"/assert.sh
enable_debug() {
mkdir -p /run/systemd/system/systemd-localed.service.d
cat >>/run/systemd/system/systemd-localed.service.d/override.conf <<EOF
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug
EOF
mkdir -p /run/systemd/system/systemd-vconsole-setup.service.d
cat >>/run/systemd/system/systemd-vconsole-setup.service.d/override.conf <<EOF
[Unit]
StartLimitIntervalSec=0
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug
EOF
systemctl daemon-reload
}
restore_locale() {
if [[ -d /usr/lib/locale/xx_XX.UTF-8 ]]; then
rmdir /usr/lib/locale/xx_XX.UTF-8
fi
if [[ -f /tmp/locale.conf.bak ]]; then
mv /tmp/locale.conf.bak /etc/locale.conf
else
rm -f /etc/locale.conf
fi
if [[ -f /tmp/default-locale.bak ]]; then
mv /tmp/default-locale.bak /etc/default/locale
else
rm -f /etc/default/locale
rmdir --ignore-fail-on-non-empty /etc/default
fi
if [[ -f /tmp/locale.gen.bak ]]; then
mv /tmp/locale.gen.bak /etc/locale.gen
else
rm -f /etc/locale.gen
fi
}
test_locale() {
local i output
if [[ -f /etc/locale.conf ]]; then
cp /etc/locale.conf /tmp/locale.conf.bak
fi
# Debian/Ubuntu specific file
if [[ -f /etc/default/locale ]]; then
cp /etc/default/locale /tmp/default-locale.bak
fi
if [[ -f /etc/locale.gen ]]; then
cp /etc/locale.gen /tmp/locale.gen.bak
fi
# remove locale.conf to make /etc/default/locale used by Debian/Ubuntu
rm -f /etc/locale.conf
# also remove /etc/default/locale
rm -f /etc/default/locale
# and create /etc/default to make /etc/default/locale created by localed
mkdir -p /etc/default
trap restore_locale RETURN
if command -v locale-gen >/dev/null 2>&1 &&
! localectl list-locales | grep -F "en_US.UTF-8"; then
# ensure at least one utf8 locale exist
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen en_US.UTF-8
fi
# create invalid locale
mkdir -p /usr/lib/locale/xx_XX.UTF-8
assert_not_in "xx_XX.UTF-8" "$(localectl list-locales)"
if [[ -z "$(localectl list-locales)" ]]; then
echo "No locale installed, skipping test."
return
fi
# warn when kernel command line has locale settings
output=$(SYSTEMD_PROC_CMDLINE="locale.LANG=C.UTF-8 locale.LC_CTYPE=ja_JP.UTF-8" localectl 2>&1)
assert_in "Warning:" "$output"
assert_in "Command Line: LANG=C.UTF-8" "$output"
assert_in "LC_CTYPE=ja_JP.UTF-8" "$output"
assert_in "System Locale:" "$output"
# change locale
for i in $(localectl list-locales); do
assert_rc 0 localectl set-locale "LANG=C" "LC_CTYPE=$i"
if [[ -f /etc/default/locale ]]; then
assert_eq "$(cat /etc/default/locale)" "LANG=C
LC_CTYPE=$i"
else
assert_eq "$(cat /etc/locale.conf)" "LANG=C
LC_CTYPE=$i"
fi
output=$(localectl)
assert_in "System Locale: LANG=C" "$output"
assert_in "LC_CTYPE=$i" "$output"
output=$(systemctl show-environment)
assert_in "LANG=C" "$output"
assert_in "LC_CTYPE=$i" "$output"
assert_rc 0 localectl set-locale "$i"
if [[ -f /etc/default/locale ]]; then
# Debian/Ubuntu patch is buggy, and LC_CTYPE= still exists.
assert_eq "$(cat /etc/default/locale)" "LANG=$i
LC_CTYPE=$i"
else
assert_eq "$(cat /etc/locale.conf)" "LANG=$i"
fi
output=$(localectl)
assert_in "System Locale: LANG=$i" "$output"
assert_not_in "LC_CTYPE=" "$output"
output=$(systemctl show-environment)
assert_in "LANG=$i" "$output"
assert_not_in "LC_CTYPE=" "$output"
done
# test if localed auto-runs locale-gen
if command -v locale-gen >/dev/null 2>&1 &&
! localectl list-locales | grep -F "de_DE.UTF-8"; then
# clear previous locale
systemctl stop systemd-localed.service
rm -f /etc/locale.conf /etc/default/locale
# change locale
assert_rc 0 localectl set-locale de_DE.UTF-8
if [[ -f /etc/default/locale ]]; then
assert_eq "$(cat /etc/default/locale)" "LANG=de_DE.UTF-8"
else
assert_eq "$(cat /etc/locale.conf)" "LANG=de_DE.UTF-8"
fi
assert_in "System Locale: LANG=de_DE.UTF-8" "$(localectl)"
assert_in "LANG=de_DE.UTF-8" "$(systemctl show-environment)"
# ensure tested locale exists and works now
assert_in "de_DE.UTF-8" "$(localectl list-locales)"
fi
}
backup_keymap() {
if [[ -f /etc/vconsole.conf ]]; then
cp /etc/vconsole.conf /tmp/vconsole.conf.bak
fi
if [[ -f /etc/X11/xorg.conf.d/00-keyboard.conf ]]; then
cp /etc/X11/xorg.conf.d/00-keyboard.conf /tmp/00-keyboard.conf.bak
fi
# Debian/Ubuntu specific file
if [[ -f /etc/default/keyboard ]]; then
cp /etc/default/keyboard /tmp/default-keyboard.bak
fi
mkdir -p /etc/default
}
restore_keymap() {
if [[ -f /tmp/vconsole.conf.bak ]]; then
mv /tmp/vconsole.conf.bak /etc/vconsole.conf
else
rm -f /etc/vconsole.conf
fi
if [[ -f /tmp/00-keyboard.conf.bak ]]; then
mv /tmp/00-keyboard.conf.bak /etc/X11/xorg.conf.d/00-keyboard.conf
else
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf
fi
if [[ -f /tmp/default-keyboard.bak ]]; then
mv /tmp/default-keyboard.bak /etc/default/keyboard
else
rm -f /etc/default/keyboard
rmdir --ignore-fail-on-non-empty /etc/default
fi
}
wait_vconsole_setup() {
local i ss
for ((i = 0; i < 20; i++)); do
if (( i != 0 )); then sleep .5; fi
ss="$(systemctl --property SubState --value show systemd-vconsole-setup.service)"
if [[ "$ss" == "exited" || "$ss" == "dead" || "$ss" == "condition" ]]; then
return 0
elif [[ "$ss" == "failed" ]]; then
echo "WARNING: systemd-vconsole-setup.service failed, ignoring." >&2
systemctl reset-failed systemd-vconsole-setup.service
return 0
fi
done
systemctl status systemd-vconsole-setup.service
return 1
}
test_vc_keymap() {
local i output
if [[ -z "$(localectl list-keymaps)" ]]; then
echo "No vconsole keymap installed, skipping test."
return
fi
backup_keymap
trap restore_keymap RETURN
# should activate daemon and work
assert_in "VC Keymap:" "$(localectl)"
for i in $(localectl list-keymaps); do
# clear previous conversion from VC -> X11 keymap
systemctl stop systemd-localed.service
wait_vconsole_setup
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
# set VC keymap
assert_rc 0 localectl set-keymap "$i"
output=$(localectl)
# check VC keymap
assert_in "KEYMAP=$i" "$(cat /etc/vconsole.conf)"
assert_in "VC Keymap: $i" "$output"
# check VC -> X11 keymap conversion
if [[ "$i" == "us" ]]; then
assert_in "X11 Layout: us" "$output"
assert_in "X11 Model: pc105\+inet" "$output"
assert_not_in "X11 Variant:" "$output"
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
elif [[ "$i" == "us-acentos" ]]; then
assert_in "X11 Layout: us" "$output"
assert_in 'X11 Model: pc105$' "$output"
assert_in "X11 Variant: intl" "$output"
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
elif [[ "$i" =~ ^us-.* ]]; then
assert_in "X11 Layout: n/a" "$output"
assert_not_in "X11 Model:" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
fi
done
# gets along without config file
systemctl stop systemd-localed.service
wait_vconsole_setup
rm -f /etc/vconsole.conf
assert_in "VC Keymap: n/a" "$(localectl)"
}
test_x11_keymap() {
local output
if [[ -z "$(localectl list-x11-keymap-layouts)" ]]; then
echo "No x11 keymap installed, skipping test."
return
fi
backup_keymap
trap restore_keymap RETURN
# should activate daemon and work
assert_in "X11 Layout:" "$(localectl)"
# set x11 keymap (layout, model, variant, options)
assert_rc 0 localectl set-x11-keymap us pc105+inet intl terminate:ctrl_alt_bksp
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us
XKBMODEL=pc105+inet
XKBVARIANT=intl
XKBOPTIONS=terminate:ctrl_alt_bksp"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
assert_in 'Option "XkbVariant" "intl"' "$output"
assert_in 'Option "XkbOptions" "terminate:ctrl_alt_bksp"' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_in "X11 Model: pc105\+inet" "$output"
assert_in "X11 Variant: intl" "$output"
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
# Debian/Ubuntu patch is buggy, unspecified settings are not cleared
rm -f /etc/default/keyboard
# set x11 keymap (layout, model, variant)
assert_rc 0 localectl set-x11-keymap us pc105+inet intl
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us
XKBMODEL=pc105+inet
XKBVARIANT=intl"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
assert_in 'Option "XkbVariant" "intl"' "$output"
assert_not_in 'Option "XkbOptions"' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_in "X11 Model: pc105\+inet" "$output"
assert_in "X11 Variant: intl" "$output"
assert_not_in "X11 Options:" "$output"
# Debian/Ubuntu patch is buggy, unspecified settings are not cleared
rm -f /etc/default/keyboard
# set x11 keymap (layout, model)
assert_rc 0 localectl set-x11-keymap us pc105+inet
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us
XKBMODEL=pc105+inet"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
assert_not_in 'Option "XkbVariant"' "$output"
assert_not_in 'Option "XkbOptions"' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_in "X11 Model: pc105\+inet" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
# Debian/Ubuntu patch is buggy, unspecified settings are not cleared
rm -f /etc/default/keyboard
# set x11 keymap (layout)
assert_rc 0 localectl set-x11-keymap us
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
assert_not_in 'Option "XkbModel"' "$output"
assert_not_in 'Option "XkbVariant"' "$output"
assert_not_in 'Option "XkbOptions"' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_not_in "X11 Model:" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
# gets along without config file
systemctl stop systemd-localed.service
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
output=$(localectl)
assert_in "X11 Layout: n/a" "$output"
assert_not_in "X11 Model:" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
}
: >/failed
enable_debug
test_locale
test_vc_keymap
test_x11_keymap
touch /testok
rm /failed