1
0
mirror of https://github.com/systemd/systemd synced 2025-11-21 17:54:46 +01:00

Compare commits

..

8 Commits

Author SHA1 Message Date
Felix Pehla
39179ac5fe sd-boot: fix indentation of status output
64376936c70ac1cba18fcdcaec8eb337d80c48a7 missed some printf()s when
adjusting indentation.
2025-09-28 09:50:19 +09:00
Yu Watanabe
3e843e9513
time-util: fix using wrong timezone when parsing timestamp (#38876)
This mostly fixes issues workarounded several times, e.g. #28472 and
#35471.
2025-09-28 09:49:10 +09:00
Yu Watanabe
2e966a7c0a
bash-completion: systemd-sysext/systemd-confext missing options (#38948) 2025-09-28 09:48:13 +09:00
Yu Watanabe
514fa9d39a time-util: fix issues in parse_timestamp() and optimize performance
Previously, an input string ends with short timezone spec e.g. WET,
was parsed by setting $TZ environment variable to the timezone.
But the timezone might be different from the original local timezone,
thus the result might not follow the timezone change in the original
local timezone.

This makes the check of the short timezone spec with tzname[] earlier,
then it is not necessary to load another timezone file for e.g. WET,
and provides expected time.

This also make it use SAVE_TIMEZONE macro and drop use of forking
process. This makes greatly improve performance when parsing string
that contains timezone different from the current local timezone.

Unfortunately, there is still one corner case that our test fails.
When tzdata is built with rearguard enabled, then at least
Africa/Windhoek timezone does not provide correct time, but time shifted
1 hour from the original.
2025-09-27 11:52:24 +09:00
Yu Watanabe
23407c1806 time-util: introduce parse_gmtoff() helper function 2025-09-27 11:52:24 +09:00
Yu Watanabe
e3f561a624 time-util: introduce SAVE_TIMEZONE macro 2025-09-27 11:51:06 +09:00
Pascal Bachor
9b5f1a6112 bash-completion: update systemd-sysext, systemd-confext 2025-09-26 20:20:49 +02:00
Pascal Bachor
b85887ead1 sysext: support --mutable=help 2025-09-26 20:20:31 +02:00
8 changed files with 191 additions and 172 deletions

View File

@ -389,8 +389,8 @@
</varlistentry>
<varlistentry>
<term><option>--mutable=<replaceable>BOOL</replaceable>|<replaceable>auto</replaceable>|<replaceable>import</replaceable>|<replaceable>ephemeral</replaceable>|<replaceable>ephemeral-import</replaceable></option></term>
<listitem><para>Set mutable mode.</para>
<term><option>--mutable=<replaceable>BOOL</replaceable>|<replaceable>auto</replaceable>|<replaceable>import</replaceable>|<replaceable>ephemeral</replaceable>|<replaceable>ephemeral-import</replaceable>|<replaceable>help</replaceable></option></term>
<listitem><para>Set mutable mode. The special value <literal>help</literal> will list the known values.</para>
<variablelist>
<varlistentry>
@ -438,6 +438,12 @@
with the modifications made to the host file system being discarded after unmerge.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><option>help</option></term>
<listitem><para>list known values and exit immediately.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
</variablelist>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>

View File

@ -36,7 +36,8 @@ _systemd-confext() {
[ARG]='--root
--json
--noexec
--image-policy'
--image-policy
--mutable'
)
local -A VERBS=(
@ -59,11 +60,14 @@ _systemd-confext() {
comps='pretty short off'
;;
--noexec)
comps='false true'
comps='no yes'
;;
--image-policy)
comps=''
;;
--mutable)
comps=$( systemd-confext --no-legend --mutable=help 2>/dev/null; echo help )
;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0

View File

@ -31,9 +31,13 @@ _systemd-sysext() {
[STANDALONE]='-h --help --version
--no-pager
--no-legend
--no-reload
--force'
[ARG]='--root
--json'
--json
--noexec
--image-policy
--mutable'
)
local -A VERBS=(
@ -55,6 +59,15 @@ _systemd-sysext() {
--json)
comps='pretty short off'
;;
--noexec)
comps='no yes'
;;
--image-policy)
comps=''
;;
--mutable)
comps=$( systemd-sysext --no-legend --mutable=help 2>/dev/null; echo help )
;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0

View File

@ -7,6 +7,7 @@
#include <unistd.h>
#include "alloc-util.h"
#include "env-util.h"
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
@ -623,6 +624,19 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
return buf;
}
int parse_gmtoff(const char *t, long *ret) {
assert(t);
struct tm tm;
const char *k = strptime(t, "%z", &tm);
if (!k || *k != '\0')
return -EINVAL;
if (ret)
*ret = tm.tm_gmtoff;
return 0;
}
static int parse_timestamp_impl(
const char *t,
size_t max_len,
@ -952,44 +966,13 @@ finish:
return 0;
}
static int parse_timestamp_maybe_with_tz(const char *t, size_t tz_offset, bool valid_tz, usec_t *ret) {
assert(t);
tzset();
for (int j = 0; j <= 1; j++) {
if (isempty(tzname[j]))
continue;
if (!streq(t + tz_offset, tzname[j]))
continue;
/* The specified timezone matches tzname[] of the local timezone. */
return parse_timestamp_impl(t, tz_offset - 1, /* utc = */ false, /* isdst = */ j, /* gmtoff = */ 0, ret);
}
/* If we know that the last word is a valid timezone (e.g. Asia/Tokyo), then simply drop the timezone
* and parse the remaining string as a local time. If we know that the last word is not a timezone,
* then assume that it is a part of the time and try to parse the whole string as a local time. */
return parse_timestamp_impl(t, valid_tz ? tz_offset - 1 : SIZE_MAX,
/* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
}
typedef struct ParseTimestampResult {
usec_t usec;
int return_value;
} ParseTimestampResult;
int parse_timestamp(const char *t, usec_t *ret) {
ParseTimestampResult *shared, tmp;
const char *k, *tz, *current_tz;
size_t max_len, t_len;
struct tm tm;
long gmtoff;
int r;
assert(t);
t_len = strlen(t);
size_t t_len = strlen(t);
if (t_len > 2 && t[t_len - 1] == 'Z') {
/* Try to parse as RFC3339-style welded UTC: "1985-04-12T23:20:50.52Z" */
r = parse_timestamp_impl(t, t_len - 1, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ 0, ret);
@ -997,17 +980,15 @@ int parse_timestamp(const char *t, usec_t *ret) {
return r;
}
if (t_len > 7 && IN_SET(t[t_len - 6], '+', '-') && t[t_len - 7] != ' ') { /* RFC3339-style welded offset: "1990-12-31T15:59:60-08:00" */
k = strptime(&t[t_len - 6], "%z", &tm);
if (k && *k == '\0')
return parse_timestamp_impl(t, t_len - 6, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ tm.tm_gmtoff, ret);
}
/* RFC3339-style welded offset: "1990-12-31T15:59:60-08:00" */
if (t_len > 7 && IN_SET(t[t_len - 6], '+', '-') && t[t_len - 7] != ' ' && parse_gmtoff(&t[t_len - 6], &gmtoff) >= 0)
return parse_timestamp_impl(t, t_len - 6, /* utc = */ true, /* isdst = */ -1, gmtoff, ret);
tz = strrchr(t, ' ');
const char *tz = strrchr(t, ' ');
if (!tz)
return parse_timestamp_impl(t, /* max_len = */ SIZE_MAX, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
max_len = tz - t;
size_t max_len = tz - t;
tz++;
/* Shortcut, parse the string as UTC. */
@ -1017,65 +998,39 @@ int parse_timestamp(const char *t, usec_t *ret) {
/* If the timezone is compatible with RFC-822/ISO 8601 (e.g. +06, or -03:00) then parse the string as
* UTC and shift the result. Note, this must be earlier than the timezone check with tzname[], as
* tzname[] may be in the same format. */
k = strptime(tz, "%z", &tm);
if (k && *k == '\0')
return parse_timestamp_impl(t, max_len, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ tm.tm_gmtoff, ret);
if (parse_gmtoff(tz, &gmtoff) >= 0)
return parse_timestamp_impl(t, max_len, /* utc = */ true, /* isdst = */ -1, gmtoff, ret);
/* If the last word is not a timezone file (e.g. Asia/Tokyo), then let's check if it matches
* tzname[] of the local timezone, e.g. JST or CEST. */
if (!timezone_is_valid(tz, LOG_DEBUG))
return parse_timestamp_maybe_with_tz(t, tz - t, /* valid_tz = */ false, ret);
/* Check if the last word matches tzname[] of the local timezone. Note, this must be done earlier
* than the check by timezone_is_valid() below, as some short timezone specifications have their own
* timezone files (e.g. WET has its own timezone file, but JST does not), but using such files does
* not follow the timezone change in the current area. */
tzset();
for (int j = 0; j <= 1; j++) {
if (isempty(tzname[j]))
continue;
/* Shortcut. If the current $TZ is equivalent to the specified timezone, it is not necessary to fork
* the process. */
current_tz = getenv("TZ");
if (current_tz && *current_tz == ':' && streq(current_tz + 1, tz))
return parse_timestamp_maybe_with_tz(t, tz - t, /* valid_tz = */ true, ret);
if (!streq(tz, tzname[j]))
continue;
/* Otherwise, to avoid polluting the current environment variables, let's fork the process and set
* the specified timezone in the child process. */
shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (shared == MAP_FAILED)
return negative_errno();
/* The input string may be in argv. Let's copy it. */
_cleanup_free_ char *t_copy = strdup(t);
if (!t_copy)
return -ENOMEM;
t = t_copy;
assert_se(tz = endswith(t_copy, tz));
r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_WAIT, NULL);
if (r < 0) {
(void) munmap(shared, sizeof *shared);
return r;
}
if (r == 0) {
const char *colon_tz;
/* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */
colon_tz = strjoina(":", tz);
if (setenv("TZ", colon_tz, 1) != 0) {
shared->return_value = negative_errno();
_exit(EXIT_FAILURE);
}
shared->return_value = parse_timestamp_maybe_with_tz(t, tz - t, /* valid_tz = */ true, &shared->usec);
_exit(EXIT_SUCCESS);
/* The specified timezone matches tzname[] of the local timezone. */
return parse_timestamp_impl(t, max_len, /* utc = */ false, /* isdst = */ j, /* gmtoff = */ 0, ret);
}
tmp = *shared;
if (munmap(shared, sizeof *shared) != 0)
return negative_errno();
/* If the last word is a valid timezone file (e.g. Asia/Tokyo), then save the current timezone, apply
* the specified timezone, and parse the remaining string as a local time. */
if (timezone_is_valid(tz, LOG_DEBUG)) {
SAVE_TIMEZONE;
if (tmp.return_value == 0 && ret)
*ret = tmp.usec;
if (setenv("TZ", strjoina(":", tz), /* overwrite = */ true) < 0)
return negative_errno();
return tmp.return_value;
return parse_timestamp_impl(t, max_len, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
}
/* Otherwise, assume that the last word is a part of the time and try to parse the whole string as a
* local time. */
return parse_timestamp_impl(t, SIZE_MAX, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
}
static const char* extract_multiplier(const char *p, usec_t *ret) {
@ -1592,6 +1547,26 @@ int verify_timezone(const char *name, int log_level) {
return 0;
}
void reset_timezonep(char **p) {
assert(p);
(void) set_unset_env("TZ", *p, /* overwrite = */ true);
tzset();
*p = mfree(*p);
}
char* save_timezone(void) {
const char *e = getenv("TZ");
if (!e)
return NULL;
char *s = strdup(e);
if (!s)
log_debug("Failed to save $TZ=%s, unsetting the environment variable.", e);
return s;
}
bool clock_supported(clockid_t clock) {
struct timespec ts;

View File

@ -149,6 +149,7 @@ static inline char* format_timestamp(char *buf, size_t l, usec_t t) {
#define FORMAT_TIMESTAMP_STYLE(t, style) \
format_timestamp_style((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t, style)
int parse_gmtoff(const char *t, long *ret);
int parse_timestamp(const char *t, usec_t *ret);
int parse_sec(const char *t, usec_t *ret);
@ -163,6 +164,12 @@ static inline bool timezone_is_valid(const char *name, int log_level) {
return verify_timezone(name, log_level) >= 0;
}
void reset_timezonep(char **p);
char* save_timezone(void);
#define SAVE_TIMEZONE \
_unused_ _cleanup_(reset_timezonep) \
char *_saved_timezone_ = save_timezone()
bool clock_supported(clockid_t clock);
usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);

View File

@ -320,19 +320,19 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
if (!ps_continue())
return;
print_timeout_status(" timeout (config)", config->timeout_sec_config);
print_timeout_status(" timeout (EFI var)", config->timeout_sec_efivar);
print_timeout_status(" timeout (config)", config->timeout_sec_config);
print_timeout_status(" timeout (EFI var)", config->timeout_sec_efivar);
if (config->entry_default_config)
printf(" default (config): %ls\n", config->entry_default_config);
printf(" default (config): %ls\n", config->entry_default_config);
if (config->entry_default_efivar)
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
if (config->entry_oneshot)
printf(" default (one-shot): %ls\n", config->entry_oneshot);
printf(" default (one-shot): %ls\n", config->entry_oneshot);
if (config->entry_sysfail)
printf(" sysfail: %ls\n", config->entry_sysfail);
printf(" sysfail: %ls\n", config->entry_sysfail);
if (config->entry_saved)
printf(" saved entry: %ls\n", config->entry_saved);
printf(" saved entry: %ls\n", config->entry_saved);
printf(" editor: %ls\n", yes_no(config->editor));
printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));

View File

@ -79,7 +79,7 @@ static const char* const mutable_mode_table[_MUTABLE_MAX] = {
[MUTABLE_EPHEMERAL_IMPORT] = "ephemeral-import",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(mutable_mode, MutableMode, MUTABLE_YES);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(mutable_mode, MutableMode, MUTABLE_YES);
static char **arg_hierarchies = NULL; /* "/usr" + "/opt" by default for sysext and /etc by default for confext */
static char *arg_root = NULL;
@ -2462,7 +2462,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
" -h --help Show this help\n"
" --version Show package version\n"
"\n%3$sOptions:%4$s\n"
" --mutable=yes|no|auto|import|ephemeral|ephemeral-import\n"
" --mutable=yes|no|auto|import|ephemeral|ephemeral-import|help\n"
" Specify a mutability mode of the merged hierarchy\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
@ -2577,6 +2577,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_MUTABLE:
if (streq(optarg, "help")) {
if (arg_legend)
puts("Known mutability modes:");
DUMP_STRING_TABLE(mutable_mode, MutableMode, _MUTABLE_MAX);
return 0;
}
r = parse_mutable_mode(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse argument to --mutable=: %s", optarg);

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdlib.h>
#include "env-util.h"
#include "random-util.h"
#include "serialize.h"
@ -11,6 +12,18 @@
#define TRIAL 100u
static void set_timezone(const char *tz) {
if (!tz)
ASSERT_OK_ERRNO(unsetenv("TZ"));
if (isempty(tz))
ASSERT_OK_ERRNO(setenv("TZ", tz, /* overwrite = */ true));
else
ASSERT_OK_ERRNO(setenv("TZ", strjoina(":", tz), /* overwrite = */ true));
tzset();
log_info("TZ=%s, tzname[0]=%s, tzname[1]=%s", strna(getenv("TZ")), strempty(tzname[0]), strempty(tzname[1]));
}
TEST(parse_sec) {
usec_t u;
@ -390,35 +403,33 @@ TEST(format_timestamp) {
}
static void test_format_timestamp_impl(usec_t x) {
bool success, override;
const char *xx, *yy;
usec_t y, x_sec, y_sec;
xx = FORMAT_TIMESTAMP(x);
const char *xx = FORMAT_TIMESTAMP(x);
ASSERT_NOT_NULL(xx);
usec_t y;
ASSERT_OK(parse_timestamp(xx, &y));
yy = FORMAT_TIMESTAMP(y);
const char *yy = FORMAT_TIMESTAMP(y);
ASSERT_NOT_NULL(yy);
x_sec = x / USEC_PER_SEC;
y_sec = y / USEC_PER_SEC;
success = (x_sec == y_sec) && streq(xx, yy);
/* Workaround for https://github.com/systemd/systemd/issues/28472
* and https://github.com/systemd/systemd/pull/35471. */
override = !success &&
(STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
(x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
usec_t x_sec = x / USEC_PER_SEC;
usec_t y_sec = y / USEC_PER_SEC;
if (x_sec == y_sec && streq(xx, yy))
return; /* Yay!*/
/* When the timezone is built with rearguard being enabled (e.g. old Ubuntu and RHEL), the following
* timezone may provide time shifted 1 hour from the original. See
* https://github.com/systemd/systemd/issues/28472 and https://github.com/systemd/systemd/pull/35471 */
bool ignore =
streq_ptr(getenv("TZ"), ":Africa/Windhoek") &&
(x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600;
log_full(ignore ? LOG_WARNING : LOG_ERR,
"@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
x, xx, y, yy,
override ? ", ignoring." : "");
if (!override) {
if (!success)
log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
ASSERT_EQ(x_sec, y_sec);
ASSERT_STREQ(xx, yy);
}
ignore ? ", ignoring." : "");
ASSERT_TRUE(ignore);
}
static void test_format_timestamp_loop(void) {
@ -445,24 +456,13 @@ TEST(FORMAT_TIMESTAMP) {
}
static void test_format_timestamp_with_tz_one(const char *tz) {
const char *saved_tz, *colon_tz;
if (!timezone_is_valid(tz, LOG_DEBUG))
return;
log_info("/* %s(%s) */", __func__, tz);
saved_tz = getenv("TZ");
assert_se(colon_tz = strjoina(":", tz));
assert_se(setenv("TZ", colon_tz, 1) >= 0);
tzset();
log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
SAVE_TIMEZONE;
set_timezone(tz);
test_format_timestamp_loop();
assert_se(set_unset_env("TZ", saved_tz, true) == 0);
tzset();
}
TEST(FORMAT_TIMESTAMP_with_tz) {
@ -661,6 +661,35 @@ TEST(format_timestamp_range) {
test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL);
}
TEST(parse_gmtoff) {
long t;
ASSERT_OK(parse_gmtoff("+14", &t));
ASSERT_EQ(t, (long) (14 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_OK(parse_gmtoff("-09", &t));
ASSERT_EQ(t, - (long) (9 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_OK(parse_gmtoff("+1400", &t));
ASSERT_EQ(t, (long) (14 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_OK(parse_gmtoff("-0900", &t));
ASSERT_EQ(t, - (long) (9 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_OK(parse_gmtoff("+14:00", &t));
ASSERT_EQ(t, (long) (14 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_OK(parse_gmtoff("-09:00", &t));
ASSERT_EQ(t, - (long) (9 * USEC_PER_HOUR / USEC_PER_SEC));
ASSERT_ERROR(parse_gmtoff("", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("UTC", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("09", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("0900", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("?0900", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("?0900", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("+0900abc", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("+0900 ", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("+090000", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("+0900:00", &t), EINVAL);
ASSERT_ERROR(parse_gmtoff("+0900.00", &t), EINVAL);
}
static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
usec_t usec = USEC_INFINITY;
int r;
@ -984,24 +1013,13 @@ TEST(parse_timestamp) {
}
static void test_parse_timestamp_with_tz_one(const char *tz) {
const char *saved_tz, *colon_tz;
if (!timezone_is_valid(tz, LOG_DEBUG))
return;
log_info("/* %s(%s) */", __func__, tz);
saved_tz = getenv("TZ");
assert_se(colon_tz = strjoina(":", tz));
assert_se(setenv("TZ", colon_tz, 1) >= 0);
tzset();
log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
SAVE_TIMEZONE;
set_timezone(tz);
test_parse_timestamp_impl(tz);
assert_se(set_unset_env("TZ", saved_tz, true) == 0);
tzset();
}
TEST(parse_timestamp_with_tz) {
@ -1093,7 +1111,7 @@ TEST(usec_shift_clock) {
}
TEST(in_utc_timezone) {
const char *tz = getenv("TZ");
SAVE_TIMEZONE;
assert_se(setenv("TZ", ":UTC", 1) >= 0);
assert_se(in_utc_timezone());
@ -1106,9 +1124,6 @@ TEST(in_utc_timezone) {
assert_se(!in_utc_timezone());
ASSERT_STREQ(tzname[0], "CET");
ASSERT_STREQ(tzname[1], "CEST");
assert_se(set_unset_env("TZ", tz, true) == 0);
tzset();
}
TEST(map_clock_usec) {
@ -1162,14 +1177,12 @@ static void test_timezone_offset_change_one(const char *utc, const char *pretty)
}
TEST(timezone_offset_change) {
const char *tz = getenv("TZ");
SAVE_TIMEZONE;
/* See issue #26370. */
if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0);
tzset();
log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
set_timezone("Africa/Casablanca");
test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01");
test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00");
@ -1180,9 +1193,7 @@ TEST(timezone_offset_change) {
}
if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
tzset();
log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
set_timezone("Asia/Atyrau");
test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04");
test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05");
@ -1191,18 +1202,13 @@ TEST(timezone_offset_change) {
}
if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0);
tzset();
log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
set_timezone("Chile/EasterIsland");
test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07");
test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06");
test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
}
assert_se(set_unset_env("TZ", tz, true) == 0);
tzset();
}
static usec_t absdiff(usec_t a, usec_t b) {