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:
+38
-15
@@ -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"
|
||||
};
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int locale_setup(char ***environment);
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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',
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../TEST-01-BASIC/Makefile
|
||||
Executable
+10
@@ -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 "$@"
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../TEST-01-BASIC/Makefile
|
||||
Executable
+10
@@ -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
@@ -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
@@ -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"
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Executable
+52
@@ -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
|
||||
@@ -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
|
||||
Executable
+391
@@ -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
|
||||
Reference in New Issue
Block a user