diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index c340e01d016..ab2d6795190 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -297,6 +297,9 @@ All tools: first existing unit listed in the environment variable, and `timedatectl set-ntp off` disables and stops all listed units. +* `$SYSTEMD_ETC_ADJTIME` - override the path to the hardware clock setting. + The default is `/etc/adjtime`. + `systemd-sulogin-shell`: * `$SYSTEMD_SULOGIN_FORCE=1` — This skips asking for the root password if the @@ -779,3 +782,24 @@ Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as `systemd.factory_reset=` kernel command line option: if set to false, requesting a TPM clearing is skipped, and the command immediately exits successfully. + +`systemd-timedated`, `systemd-firstboot`: + +* `$SYSTEMD_ETC_LOCALTIME` - override the path to the timezone symlink. The + default is `/etc/localtime`. + +`systemd-hostnamed`, `systemd-firstboot`: + +* `$SYSTEMD_ETC_HOSTNAME` - override the path to local system name + configuration. The default is `/etc/hostname`. + +* `$SYSTEMD_ETC_MACHINE_INFO` - override the path to the machine metadata. The + default is `/etc/machine-info`. + +`systemd-localed`, `systemd-firstboot`: + +* `$SYSTEMD_ETC_LOCALE_CONF` - override the path to the system-wide locale + configuration. The default is `/etc/locale.conf`. + +* `$SYSTEMD_ETC_VCONSOLE_CONF` - override the path to the virtual console + configuration. The default is `/etc/vconsole.conf`. diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 7159473b582..51594e96ece 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -160,13 +160,21 @@ bool is_localhost(const char *hostname) { endswith_no_case(hostname, ".localhost.localdomain."); } +const char* etc_hostname(void) { + return secure_getenv("SYSTEMD_ETC_HOSTNAME") ?: "/etc/hostname"; +} + +const char* etc_machine_info(void) { + return secure_getenv("SYSTEMD_ETC_MACHINE_INFO") ?: "/etc/machine-info"; +} + int get_pretty_hostname(char **ret) { _cleanup_free_ char *n = NULL; int r; assert(ret); - r = parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &n); + r = parse_env_file(NULL, etc_machine_info(), "PRETTY_HOSTNAME", &n); if (r < 0) return r; diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index 4c5abe760f0..6138e61d742 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -40,4 +40,7 @@ static inline bool is_dns_proxy_stub_hostname(const char *hostname) { return STRCASE_IN_SET(hostname, "_localdnsproxy", "_localdnsproxy."); } +const char* etc_hostname(void); +const char* etc_machine_info(void); + int get_pretty_hostname(char **ret); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index fcbedf9e9d1..a6a56a014f5 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1605,19 +1605,27 @@ bool clock_supported(clockid_t clock) { } int get_timezone(char **ret) { - _cleanup_free_ char *t = NULL; + _cleanup_free_ char *t = NULL, *link_dir = NULL, *abspath = NULL; int r; assert(ret); - r = readlink_malloc("/etc/localtime", &t); + r = readlink_malloc(etc_localtime(), &t); if (r == -ENOENT) /* If the symlink does not exist, assume "UTC", like glibc does */ return strdup_to(ret, "UTC"); if (r < 0) return r; /* Return EINVAL if not a symlink */ - const char *e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/"); + r = path_extract_directory(etc_localtime(), &link_dir); + if (r < 0) + return r; + + abspath = path_make_absolute(t, link_dir); + if (!abspath) + return -ENOMEM; + + const char *e = path_startswith(abspath, "/usr/share/zoneinfo/"); if (!e) return -EINVAL; if (!timezone_is_valid(e, LOG_DEBUG)) @@ -1626,6 +1634,10 @@ int get_timezone(char **ret) { return strdup_to(ret, e); } +const char* etc_localtime(void) { + return secure_getenv("SYSTEMD_ETC_LOCALTIME") ?: "/etc/localtime"; +} + int mktime_or_timegm_usec( struct tm *tm, /* input + normalized output */ bool utc, diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 14d660ee7e9..c403832cb10 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -176,6 +176,7 @@ bool clock_supported(clockid_t clock); usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to); int get_timezone(char **ret); +const char* etc_localtime(void); int mktime_or_timegm_usec(struct tm *tm, bool utc, usec_t *ret); int localtime_or_gmtime_usec(usec_t t, bool utc, struct tm *ret); diff --git a/src/core/manager.c b/src/core/manager.c index 36217ead14a..2b560461f97 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -428,7 +428,7 @@ static int manager_read_timezone_stat(Manager *m) { assert(m); /* Read the current stat() data of /etc/localtime so that we detect changes */ - if (lstat("/etc/localtime", &st) < 0) { + if (lstat(etc_localtime(), &st) < 0) { log_debug_errno(errno, "Failed to stat /etc/localtime, ignoring: %m"); changed = m->etc_localtime_accessible; m->etc_localtime_accessible = false; @@ -465,7 +465,7 @@ static int manager_setup_timezone_change(Manager *m) { * Note that we create the new event source first here, before releasing the old one. This should optimize * behaviour as this way sd-event can reuse the old watch in case the inode didn't change. */ - r = sd_event_add_inotify(m->event, &new_event, "/etc/localtime", + r = sd_event_add_inotify(m->event, &new_event, etc_localtime(), IN_ATTRIB|IN_MOVE_SELF|IN_CLOSE_WRITE|IN_DONT_FOLLOW, manager_dispatch_timezone_change, m); if (r == -ENOENT) { /* If the file doesn't exist yet, subscribe to /etc instead, and wait until it is created either by diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index cd72f543969..d8130c82147 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -28,6 +28,7 @@ #include "hostname-util.h" #include "kbd-util.h" #include "libcrypt-util.h" +#include "locale-setup.h" #include "locale-util.h" #include "lock-util.h" #include "main-func.h" @@ -400,7 +401,7 @@ static int process_locale(int rfd) { assert(rfd >= 0); - pfd = chase_and_open_parent_at(rfd, "/etc/locale.conf", + pfd = chase_and_open_parent_at(rfd, etc_locale_conf(), CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW, &f); if (pfd < 0) @@ -417,7 +418,7 @@ static int process_locale(int rfd) { return log_error_errno(r, "Failed to check if directory file descriptor is root: %m"); if (arg_copy_locale && r == 0) { - r = copy_file_atomic_at(AT_FDCWD, "/etc/locale.conf", pfd, f, 0644, COPY_REFLINK); + r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, COPY_REFLINK); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m"); @@ -507,7 +508,7 @@ static int process_keymap(int rfd) { assert(rfd >= 0); - pfd = chase_and_open_parent_at(rfd, "/etc/vconsole.conf", + pfd = chase_and_open_parent_at(rfd, etc_vconsole_conf(), CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW, &f); if (pfd < 0) @@ -524,7 +525,7 @@ static int process_keymap(int rfd) { return log_error_errno(r, "Failed to check if directory file descriptor is root: %m"); if (arg_copy_keymap && r == 0) { - r = copy_file_atomic_at(AT_FDCWD, "/etc/vconsole.conf", pfd, f, 0644, COPY_REFLINK); + r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, COPY_REFLINK); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m"); @@ -604,13 +605,13 @@ static int prompt_timezone(int rfd) { static int process_timezone(int rfd) { _cleanup_close_ int pfd = -EBADF; - _cleanup_free_ char *f = NULL; + _cleanup_free_ char *f = NULL, *relpath = NULL, *link_dir = NULL; const char *e; int r; assert(rfd >= 0); - pfd = chase_and_open_parent_at(rfd, "/etc/localtime", + pfd = chase_and_open_parent_at(rfd, etc_localtime(), CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW, &f); if (pfd < 0) @@ -629,7 +630,7 @@ static int process_timezone(int rfd) { if (arg_copy_timezone && r == 0) { _cleanup_free_ char *s = NULL; - r = readlink_malloc("/etc/localtime", &s); + r = readlink_malloc(etc_localtime(), &s); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to read host's /etc/localtime: %m"); @@ -650,9 +651,15 @@ static int process_timezone(int rfd) { if (isempty(arg_timezone)) return 0; - e = strjoina("../usr/share/zoneinfo/", arg_timezone); + r = path_extract_directory(etc_localtime(), &link_dir); + if (r < 0) + return r; + e = strjoina("/usr/share/zoneinfo/", arg_timezone); + r = path_make_relative(link_dir, e, &relpath); + if (r < 0) + return r; - r = symlinkat_atomic_full(e, pfd, f, /* make_relative= */ false); + r = symlinkat_atomic_full(relpath, pfd, f, /* make_relative= */ false); if (r < 0) return log_error_errno(r, "Failed to create /etc/localtime symlink: %m"); @@ -699,7 +706,7 @@ static int process_hostname(int rfd) { assert(rfd >= 0); - pfd = chase_and_open_parent_at(rfd, "/etc/hostname", + pfd = chase_and_open_parent_at(rfd, etc_hostname(), CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN, &f); if (pfd < 0) @@ -1215,12 +1222,12 @@ static int process_reset(int rfd) { return 0; FOREACH_STRING(p, - "/etc/locale.conf", - "/etc/vconsole.conf", - "/etc/hostname", + etc_locale_conf(), + etc_vconsole_conf(), + etc_hostname(), "/etc/machine-id", "/etc/kernel/cmdline", - "/etc/localtime") { + etc_localtime()) { r = reset_one(rfd, p); if (r < 0) return r; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index d9ec55455fb..44299ebb768 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -122,7 +122,7 @@ static void context_read_etc_hostname(Context *c) { assert(c); - if (stat("/etc/hostname", ¤t_stat) >= 0 && + if (stat(etc_hostname(), ¤t_stat) >= 0 && stat_inode_unmodified(&c->etc_hostname_stat, ¤t_stat)) return; @@ -155,7 +155,7 @@ static void context_read_machine_info(Context *c) { assert(c); - if (stat("/etc/machine-info", ¤t_stat) >= 0 && + if (stat(etc_machine_info(), ¤t_stat) >= 0 && stat_inode_unmodified(&c->etc_machine_info_stat, ¤t_stat)) return; @@ -168,7 +168,7 @@ static void context_read_machine_info(Context *c) { (UINT64_C(1) << PROP_HARDWARE_VENDOR) | (UINT64_C(1) << PROP_HARDWARE_MODEL)); - r = parse_env_file(NULL, "/etc/machine-info", + r = parse_env_file(NULL, etc_machine_info(), "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], "ICON_NAME", &c->data[PROP_ICON_NAME], "CHASSIS", &c->data[PROP_CHASSIS], @@ -749,14 +749,14 @@ static int context_write_data_static_hostname(Context *c) { s = &c->etc_hostname_stat; if (isempty(c->data[PROP_STATIC_HOSTNAME])) { - if (unlink("/etc/hostname") < 0 && errno != ENOENT) + if (unlink(etc_hostname()) < 0 && errno != ENOENT) return -errno; TAKE_PTR(s); return 0; } - r = write_string_file("/etc/hostname", c->data[PROP_STATIC_HOSTNAME], WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL); + r = write_string_file(etc_hostname(), c->data[PROP_STATIC_HOSTNAME], WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL); if (r < 0) return r; @@ -782,7 +782,7 @@ static int context_write_data_machine_info(Context *c) { * already, even if we can't make it hit the disk. */ s = &c->etc_machine_info_stat; - r = load_env_file(NULL, "/etc/machine-info", &l); + r = load_env_file(NULL, etc_machine_info(), &l); if (r < 0 && r != -ENOENT) return r; @@ -795,14 +795,14 @@ static int context_write_data_machine_info(Context *c) { } if (strv_isempty(l)) { - if (unlink("/etc/machine-info") < 0 && errno != ENOENT) + if (unlink(etc_machine_info()) < 0 && errno != ENOENT) return -errno; TAKE_PTR(s); return 0; } - r = write_env_file_label(AT_FDCWD, "/etc/machine-info", NULL, l); + r = write_env_file_label(AT_FDCWD, etc_machine_info(), NULL, l); if (r < 0) return r; @@ -1596,7 +1596,7 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant (void) vsock_get_local_cid(&local_cid); (void) load_os_release_pairs(/* root= */ NULL, &os_release_pairs); - (void) load_env_file_pairs(/* f=*/ NULL, "/etc/machine-info", &machine_info_pairs); + (void) load_env_file_pairs(/* f=*/ NULL, etc_machine_info(), &machine_info_pairs); r = sd_json_buildo( &v, diff --git a/src/locale/localed-util.c b/src/locale/localed-util.c index d43ee48e12f..d22a9477a8b 100644 --- a/src/locale/localed-util.c +++ b/src/locale/localed-util.c @@ -148,7 +148,7 @@ int vconsole_read_data(Context *c, sd_bus_message *m) { c->vc_cache = sd_bus_message_ref(m); } - fd = RET_NERRNO(open("/etc/vconsole.conf", O_CLOEXEC | O_PATH)); + fd = RET_NERRNO(open(etc_vconsole_conf(), O_CLOEXEC | O_PATH)); if (fd == -ENOENT) { c->vc_stat = (struct stat) {}; vc_context_clear(&c->vc); @@ -170,7 +170,7 @@ int vconsole_read_data(Context *c, sd_bus_message *m) { x11_context_clear(&c->x11_from_vc); r = parse_env_file_fd( - fd, "/etc/vconsole.conf", + fd, etc_vconsole_conf(), "KEYMAP", &c->vc.keymap, "KEYMAP_TOGGLE", &c->vc.toggle, "XKBLAYOUT", &c->x11_from_vc.layout, @@ -286,6 +286,7 @@ int x11_read_data(Context *c, sd_bus_message *m) { } int vconsole_write_data(Context *c) { + const char* vconsole_conf_path; _cleanup_strv_free_ char **l = NULL; const X11Context *xc; int r; @@ -294,7 +295,9 @@ int vconsole_write_data(Context *c) { xc = context_get_x11_context(c); - r = load_env_file(NULL, "/etc/vconsole.conf", &l); + vconsole_conf_path = etc_vconsole_conf(); + + r = load_env_file(NULL, vconsole_conf_path, &l); if (r < 0 && r != -ENOENT) return r; @@ -303,18 +306,18 @@ int vconsole_write_data(Context *c) { return r; if (strv_isempty(l)) { - if (unlink("/etc/vconsole.conf") < 0) + if (unlink(vconsole_conf_path) < 0) return errno == ENOENT ? 0 : -errno; c->vc_stat = (struct stat) {}; return 0; } - r = write_vconsole_conf_label(l); + r = write_vconsole_conf_label(vconsole_conf_path, l); if (r < 0) return r; - if (stat("/etc/vconsole.conf", &c->vc_stat) < 0) + if (stat(vconsole_conf_path, &c->vc_stat) < 0) return -errno; return 0; diff --git a/src/shared/env-file-label.c b/src/shared/env-file-label.c index 5917b6377f3..a0c0163c19f 100644 --- a/src/shared/env-file-label.c +++ b/src/shared/env-file-label.c @@ -20,14 +20,14 @@ int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l return r; } -int write_vconsole_conf_label(char **l) { +int write_vconsole_conf_label(const char* vconsole_conf_path, char **l) { int r; - r = mac_selinux_create_file_prepare("/etc/vconsole.conf", S_IFREG); + r = mac_selinux_create_file_prepare(vconsole_conf_path, S_IFREG); if (r < 0) return r; - r = write_vconsole_conf(AT_FDCWD, "/etc/vconsole.conf", l); + r = write_vconsole_conf(AT_FDCWD, vconsole_conf_path, l); mac_selinux_create_file_clear(); diff --git a/src/shared/env-file-label.h b/src/shared/env-file-label.h index 5ba45e40057..3cd772a626b 100644 --- a/src/shared/env-file-label.h +++ b/src/shared/env-file-label.h @@ -7,4 +7,4 @@ int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l); -int write_vconsole_conf_label(char **l); +int write_vconsole_conf_label(const char* vconsole_conf_path, char **l); diff --git a/src/shared/hostname-setup.c b/src/shared/hostname-setup.c index af89f92bdc4..6c761d022c8 100644 --- a/src/shared/hostname-setup.c +++ b/src/shared/hostname-setup.c @@ -142,7 +142,7 @@ int read_etc_hostname(const char *path, bool substitute_wildcards, char **ret) { assert(ret); if (!path) - path = "/etc/hostname"; + path = etc_hostname(); f = fopen(path, "re"); if (!f) diff --git a/src/shared/locale-setup.c b/src/shared/locale-setup.c index 5c4580cffff..85d05e5a6ce 100644 --- a/src/shared/locale-setup.c +++ b/src/shared/locale-setup.c @@ -64,7 +64,7 @@ static int locale_context_load_conf(LocaleContext *c, LocaleLoadFlag flag) { if (!FLAGS_SET(flag, LOCALE_LOAD_LOCALE_CONF)) return 0; - fd = RET_NERRNO(open("/etc/locale.conf", O_CLOEXEC | O_PATH)); + fd = RET_NERRNO(open(etc_locale_conf(), O_CLOEXEC | O_PATH)); if (fd == -ENOENT) return 0; if (fd < 0) @@ -80,7 +80,7 @@ static int locale_context_load_conf(LocaleContext *c, LocaleLoadFlag flag) { c->st = st; locale_context_clear(c); - r = parse_env_file_fd(fd, "/etc/locale.conf", + r = parse_env_file_fd(fd, etc_locale_conf(), "LANG", &c->locale[VARIABLE_LANG], "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], @@ -196,7 +196,7 @@ int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) { return r; if (strv_isempty(set)) { - if (unlink("/etc/locale.conf") < 0) + if (unlink(etc_locale_conf()) < 0) return errno == ENOENT ? 0 : -errno; c->st = (struct stat) {}; @@ -208,11 +208,11 @@ int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) { return 0; } - r = write_env_file_label(AT_FDCWD, "/etc/locale.conf", NULL, set); + r = write_env_file_label(AT_FDCWD, etc_locale_conf(), NULL, set); if (r < 0) return r; - if (stat("/etc/locale.conf", &c->st) < 0) + if (stat(etc_locale_conf(), &c->st) < 0) return -errno; if (ret_set) @@ -292,3 +292,11 @@ int locale_setup(char ***environment) { return 0; } + +const char* etc_locale_conf(void) { + return secure_getenv("SYSTEMD_ETC_LOCALE_CONF") ?: "/etc/locale.conf"; +} + +const char* etc_vconsole_conf(void) { + return secure_getenv("SYSTEMD_ETC_VCONSOLE_CONF") ?: "/etc/vconsole.conf"; +} diff --git a/src/shared/locale-setup.h b/src/shared/locale-setup.h index 537acc72df8..3f1cd6b88c2 100644 --- a/src/shared/locale-setup.h +++ b/src/shared/locale-setup.h @@ -27,3 +27,6 @@ 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); + +const char* etc_locale_conf(void); +const char* etc_vconsole_conf(void); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index d14ff5e0e7e..eabc4298bd1 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -292,8 +292,9 @@ static int context_read_data(Context *c) { } static int context_write_data_timezone(Context *c) { - _cleanup_free_ char *p = NULL; - const char *source; + _cleanup_free_ char *p = NULL, *link_dir = NULL, *relpath = NULL; + const char *source, *link_path; + int r; assert(c); @@ -306,22 +307,36 @@ static int context_write_data_timezone(Context *c) { if (access("/usr/share/zoneinfo/UTC", F_OK) < 0) { - if (unlink("/etc/localtime") < 0 && errno != ENOENT) + if (unlink(etc_localtime()) < 0 && errno != ENOENT) return -errno; return 0; } - source = "../usr/share/zoneinfo/UTC"; + source = "/usr/share/zoneinfo/UTC"; } else { - p = path_join("../usr/share/zoneinfo", c->zone); + p = path_join("/usr/share/zoneinfo", c->zone); if (!p) return -ENOMEM; source = p; } - return symlink_atomic(source, "/etc/localtime"); + link_path = etc_localtime(); + + r = path_extract_directory(link_path, &link_dir); + if (r < 0) + return r; + + r = path_make_relative(link_dir, source, &relpath); + if (r < 0) + return r; + + return symlink_atomic(relpath, link_path); +} + +static const char *etc_adjtime(void) { + return secure_getenv("SYSTEMD_ETC_ADJTIME") ?: "/etc/adjtime"; } static int context_write_data_local_rtc(Context *c) { @@ -330,7 +345,7 @@ static int context_write_data_local_rtc(Context *c) { assert(c); - r = read_full_file("/etc/adjtime", &s, NULL); + r = read_full_file(etc_adjtime(), &s, NULL); if (r < 0) { if (r != -ENOENT) return r; @@ -382,7 +397,7 @@ static int context_write_data_local_rtc(Context *c) { *mempcpy_typesafe(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; if (streq(w, NULL_ADJTIME_UTC)) { - if (unlink("/etc/adjtime") < 0) + if (unlink(etc_adjtime()) < 0) if (errno != ENOENT) return -errno; @@ -394,7 +409,7 @@ static int context_write_data_local_rtc(Context *c) { if (r < 0) return r; - return write_string_file("/etc/adjtime", w, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL); + return write_string_file(etc_adjtime(), w, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL); } static int context_update_ntp_status(Context *c, sd_bus *bus, sd_bus_message *m) { diff --git a/test/units/TEST-45-TIMEDATE.sh b/test/units/TEST-45-TIMEDATE.sh index 420ebefd017..8fe7c6cd5b7 100755 --- a/test/units/TEST-45-TIMEDATE.sh +++ b/test/units/TEST-45-TIMEDATE.sh @@ -403,6 +403,46 @@ EOF rm -f /run/systemd/network/ntp99.* } +teardown_timedated_alternate_paths() { + set +eu + + rm -rf /run/systemd/system/systemd-timedated.service.d + systemctl daemon-reload + systemctl restart systemd-timedated +} + +testcase_timedated_alternate_paths() { + trap teardown_timedated_alternate_paths RETURN + + mkdir -p /run/alternate-path + mkdir -p /run/systemd/system/systemd-timedated.service.d + cat >/run/systemd/system/systemd-timedated.service.d/override.conf <&1)" "" + assert_eq "$(readlink /run/alternate-path/mylocaltime | sed 's#^.*zoneinfo/##')" "Europe/Kyiv" + assert_in "Time zone: Europe/Kyiv \(EES*T, \+0[0-9]00\)" "$(timedatectl)" + + assert_in "RTC in local TZ: no" "$(timedatectl --no-pager)" + assert_rc 0 timedatectl set-local-rtc 1 + assert_in "RTC in local TZ: yes" "$(timedatectl --no-pager)" + assert_eq "$(cat /run/alternate-path/myadjtime)" "0.0 0 0 +0 +LOCAL" + assert_rc 0 timedatectl set-local-rtc 0 + if [[ -e /run/alternate-path/myadjtime ]]; then + echo "/run/alternate-path/myadjtime still exists" >&2 + exit 1 + fi +} + run_testcases touch /testok diff --git a/test/units/TEST-71-HOSTNAME.sh b/test/units/TEST-71-HOSTNAME.sh index f844ccfcdb0..d1eaa8106e3 100755 --- a/test/units/TEST-71-HOSTNAME.sh +++ b/test/units/TEST-71-HOSTNAME.sh @@ -278,6 +278,45 @@ test_wildcard() { hostnamectl set-hostname "$SAVED" } +teardown_hostnamed_alternate_paths() { + set +eu + + rm -rf /run/systemd/system/systemd-hostnamed.service.d + systemctl daemon-reload + systemctl restart systemd-hostnamed + if [[ -f /etc/hostname ]]; then + orig=$(cat /etc/hostname) + if [[ -n "${orig}" ]]; then + hostnamectl hostname "${orig}" + fi + fi +} + +testcase_hostnamed_alternate_paths() { + trap teardown_hostnamed_alternate_paths RETURN + + mkdir -p /run/alternate-path + + mkdir -p /run/systemd/system/systemd-hostnamed.service.d + cat >/run/systemd/system/systemd-hostnamed.service.d/override.conf </run/systemd/system/systemd-localed.service.d/override.conf </etc/otherpath/vconsole.conf +echo "LANG=en_US.UTF-8" >/etc/otherpath/locale.conf +ln -s "../$(readlink /etc/localtime)" /etc/otherpath/localtime + +SYSTEMD_ETC_LOCALE_CONF=/etc/otherpath/locale.conf \ +SYSTEMD_ETC_VCONSOLE_CONF=/etc/otherpath/vconsole.conf \ +SYSTEMD_ETC_LOCALTIME=/etc/otherpath/localtime \ +SYSTEMD_ETC_HOSTNAME=/etc/otherpath/hostname \ +systemd-firstboot --root="$ROOT" --copy-locale --copy-keymap --copy-timezone --hostname="weirdpaths" + +diff "${ROOT}/etc/otherpath/locale.conf" "/etc/otherpath/locale.conf" +diff "${ROOT}/etc/otherpath/vconsole.conf" "/etc/otherpath/vconsole.conf" +grep -q "weirdpaths" "${ROOT}/etc/otherpath/hostname" + +[[ "$(readlink /etc/otherpath/localtime)" = "$(readlink "${ROOT}/etc/otherpath/localtime")" ]] + +SYSTEMD_ETC_LOCALE_CONF=/etc/otherpath/locale.conf \ +SYSTEMD_ETC_VCONSOLE_CONF=/etc/otherpath/vconsole.conf \ +SYSTEMD_ETC_LOCALTIME=/etc/otherpath/localtime \ +SYSTEMD_ETC_HOSTNAME=/etc/otherpath/hostname \ +systemd-firstboot --root="$ROOT" --force \ + --hostname="weirdpaths2" \ + --locale=no_NO.UTF-8 \ + --keymap=no \ + --timezone=Europe/Oslo + +grep -q "LANG=no_NO.UTF-8" "${ROOT}/etc/otherpath/locale.conf" +grep -q "KEYMAP=no" "${ROOT}/etc/otherpath/vconsole.conf" +grep -q "weirdpaths2" "${ROOT}/etc/otherpath/hostname" +[[ "$(readlink "${ROOT}/etc/otherpath/localtime")" = "../../usr/share/zoneinfo/Europe/Oslo" ]]