mirror of
https://github.com/systemd/systemd
synced 2025-11-22 02:04:45 +01:00
Compare commits
No commits in common. "39179ac5fecffdafa2d199cb8677fa13f83212cb" and "dbcbe4aa0488ce130d574ef1a6d457045eac0bbb" have entirely different histories.
39179ac5fe
...
dbcbe4aa04
@ -389,8 +389,8 @@
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--mutable=<replaceable>BOOL</replaceable>|<replaceable>auto</replaceable>|<replaceable>import</replaceable>|<replaceable>ephemeral</replaceable>|<replaceable>ephemeral-import</replaceable>|<replaceable>help</replaceable></option></term>
|
<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. The special value <literal>help</literal> will list the known values.</para>
|
<listitem><para>Set mutable mode.</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -438,12 +438,6 @@
|
|||||||
with the modifications made to the host file system being discarded after unmerge.</para>
|
with the modifications made to the host file system being discarded after unmerge.</para>
|
||||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
|
|||||||
@ -36,8 +36,7 @@ _systemd-confext() {
|
|||||||
[ARG]='--root
|
[ARG]='--root
|
||||||
--json
|
--json
|
||||||
--noexec
|
--noexec
|
||||||
--image-policy
|
--image-policy'
|
||||||
--mutable'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
local -A VERBS=(
|
local -A VERBS=(
|
||||||
@ -60,14 +59,11 @@ _systemd-confext() {
|
|||||||
comps='pretty short off'
|
comps='pretty short off'
|
||||||
;;
|
;;
|
||||||
--noexec)
|
--noexec)
|
||||||
comps='no yes'
|
comps='false true'
|
||||||
;;
|
;;
|
||||||
--image-policy)
|
--image-policy)
|
||||||
comps=''
|
comps=''
|
||||||
;;
|
;;
|
||||||
--mutable)
|
|
||||||
comps=$( systemd-confext --no-legend --mutable=help 2>/dev/null; echo help )
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -31,13 +31,9 @@ _systemd-sysext() {
|
|||||||
[STANDALONE]='-h --help --version
|
[STANDALONE]='-h --help --version
|
||||||
--no-pager
|
--no-pager
|
||||||
--no-legend
|
--no-legend
|
||||||
--no-reload
|
|
||||||
--force'
|
--force'
|
||||||
[ARG]='--root
|
[ARG]='--root
|
||||||
--json
|
--json'
|
||||||
--noexec
|
|
||||||
--image-policy
|
|
||||||
--mutable'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
local -A VERBS=(
|
local -A VERBS=(
|
||||||
@ -59,15 +55,6 @@ _systemd-sysext() {
|
|||||||
--json)
|
--json)
|
||||||
comps='pretty short off'
|
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
|
esac
|
||||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "env-util.h"
|
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
@ -624,19 +623,6 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
|
|||||||
return buf;
|
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(
|
static int parse_timestamp_impl(
|
||||||
const char *t,
|
const char *t,
|
||||||
size_t max_len,
|
size_t max_len,
|
||||||
@ -966,13 +952,44 @@ finish:
|
|||||||
return 0;
|
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) {
|
int parse_timestamp(const char *t, usec_t *ret) {
|
||||||
long gmtoff;
|
ParseTimestampResult *shared, tmp;
|
||||||
|
const char *k, *tz, *current_tz;
|
||||||
|
size_t max_len, t_len;
|
||||||
|
struct tm tm;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
size_t t_len = strlen(t);
|
t_len = strlen(t);
|
||||||
if (t_len > 2 && t[t_len - 1] == 'Z') {
|
if (t_len > 2 && t[t_len - 1] == 'Z') {
|
||||||
/* Try to parse as RFC3339-style welded UTC: "1985-04-12T23:20:50.52Z" */
|
/* 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);
|
r = parse_timestamp_impl(t, t_len - 1, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ 0, ret);
|
||||||
@ -980,15 +997,17 @@ int parse_timestamp(const char *t, usec_t *ret) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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] != ' ') { /* 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)
|
k = strptime(&t[t_len - 6], "%z", &tm);
|
||||||
return parse_timestamp_impl(t, t_len - 6, /* utc = */ true, /* isdst = */ -1, gmtoff, ret);
|
if (k && *k == '\0')
|
||||||
|
return parse_timestamp_impl(t, t_len - 6, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ tm.tm_gmtoff, ret);
|
||||||
|
}
|
||||||
|
|
||||||
const char *tz = strrchr(t, ' ');
|
tz = strrchr(t, ' ');
|
||||||
if (!tz)
|
if (!tz)
|
||||||
return parse_timestamp_impl(t, /* max_len = */ SIZE_MAX, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
|
return parse_timestamp_impl(t, /* max_len = */ SIZE_MAX, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
|
||||||
|
|
||||||
size_t max_len = tz - t;
|
max_len = tz - t;
|
||||||
tz++;
|
tz++;
|
||||||
|
|
||||||
/* Shortcut, parse the string as UTC. */
|
/* Shortcut, parse the string as UTC. */
|
||||||
@ -998,39 +1017,65 @@ 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
|
/* 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
|
* UTC and shift the result. Note, this must be earlier than the timezone check with tzname[], as
|
||||||
* tzname[] may be in the same format. */
|
* tzname[] may be in the same format. */
|
||||||
if (parse_gmtoff(tz, &gmtoff) >= 0)
|
k = strptime(tz, "%z", &tm);
|
||||||
return parse_timestamp_impl(t, max_len, /* utc = */ true, /* isdst = */ -1, gmtoff, ret);
|
if (k && *k == '\0')
|
||||||
|
return parse_timestamp_impl(t, max_len, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ tm.tm_gmtoff, ret);
|
||||||
|
|
||||||
/* Check if the last word matches tzname[] of the local timezone. Note, this must be done earlier
|
/* If the last word is not a timezone file (e.g. Asia/Tokyo), then let's check if it matches
|
||||||
* than the check by timezone_is_valid() below, as some short timezone specifications have their own
|
* tzname[] of the local timezone, e.g. JST or CEST. */
|
||||||
* timezone files (e.g. WET has its own timezone file, but JST does not), but using such files does
|
if (!timezone_is_valid(tz, LOG_DEBUG))
|
||||||
* not follow the timezone change in the current area. */
|
return parse_timestamp_maybe_with_tz(t, tz - t, /* valid_tz = */ false, ret);
|
||||||
tzset();
|
|
||||||
for (int j = 0; j <= 1; j++) {
|
|
||||||
if (isempty(tzname[j]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!streq(tz, tzname[j]))
|
/* Shortcut. If the current $TZ is equivalent to the specified timezone, it is not necessary to fork
|
||||||
continue;
|
* 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);
|
||||||
|
|
||||||
/* The specified timezone matches tzname[] of the local timezone. */
|
/* Otherwise, to avoid polluting the current environment variables, let's fork the process and set
|
||||||
return parse_timestamp_impl(t, max_len, /* utc = */ false, /* isdst = */ j, /* gmtoff = */ 0, ret);
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the last word is a valid timezone file (e.g. Asia/Tokyo), then save the current timezone, apply
|
tmp = *shared;
|
||||||
* the specified timezone, and parse the remaining string as a local time. */
|
if (munmap(shared, sizeof *shared) != 0)
|
||||||
if (timezone_is_valid(tz, LOG_DEBUG)) {
|
return negative_errno();
|
||||||
SAVE_TIMEZONE;
|
|
||||||
|
|
||||||
if (setenv("TZ", strjoina(":", tz), /* overwrite = */ true) < 0)
|
if (tmp.return_value == 0 && ret)
|
||||||
return negative_errno();
|
*ret = tmp.usec;
|
||||||
|
|
||||||
return parse_timestamp_impl(t, max_len, /* utc = */ false, /* isdst = */ -1, /* gmtoff = */ 0, ret);
|
return tmp.return_value;
|
||||||
}
|
|
||||||
|
|
||||||
/* 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) {
|
static const char* extract_multiplier(const char *p, usec_t *ret) {
|
||||||
@ -1547,26 +1592,6 @@ int verify_timezone(const char *name, int log_level) {
|
|||||||
return 0;
|
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) {
|
bool clock_supported(clockid_t clock) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
|
|||||||
@ -149,7 +149,6 @@ static inline char* format_timestamp(char *buf, size_t l, usec_t t) {
|
|||||||
#define FORMAT_TIMESTAMP_STYLE(t, style) \
|
#define FORMAT_TIMESTAMP_STYLE(t, style) \
|
||||||
format_timestamp_style((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, 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_timestamp(const char *t, usec_t *ret);
|
||||||
|
|
||||||
int parse_sec(const char *t, usec_t *ret);
|
int parse_sec(const char *t, usec_t *ret);
|
||||||
@ -164,12 +163,6 @@ static inline bool timezone_is_valid(const char *name, int log_level) {
|
|||||||
return verify_timezone(name, log_level) >= 0;
|
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);
|
bool clock_supported(clockid_t clock);
|
||||||
|
|
||||||
usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
|
usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
|
||||||
|
|||||||
@ -320,19 +320,19 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
|||||||
if (!ps_continue())
|
if (!ps_continue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print_timeout_status(" timeout (config)", config->timeout_sec_config);
|
print_timeout_status(" timeout (config)", config->timeout_sec_config);
|
||||||
print_timeout_status(" timeout (EFI var)", config->timeout_sec_efivar);
|
print_timeout_status(" timeout (EFI var)", config->timeout_sec_efivar);
|
||||||
|
|
||||||
if (config->entry_default_config)
|
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)
|
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)
|
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)
|
if (config->entry_sysfail)
|
||||||
printf(" sysfail: %ls\n", config->entry_sysfail);
|
printf(" sysfail: %ls\n", config->entry_sysfail);
|
||||||
if (config->entry_saved)
|
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(" editor: %ls\n", yes_no(config->editor));
|
||||||
printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
|
printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
|
||||||
printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));
|
printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));
|
||||||
|
|||||||
@ -79,7 +79,7 @@ static const char* const mutable_mode_table[_MUTABLE_MAX] = {
|
|||||||
[MUTABLE_EPHEMERAL_IMPORT] = "ephemeral-import",
|
[MUTABLE_EPHEMERAL_IMPORT] = "ephemeral-import",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(mutable_mode, MutableMode, MUTABLE_YES);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_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_hierarchies = NULL; /* "/usr" + "/opt" by default for sysext and /etc by default for confext */
|
||||||
static char *arg_root = NULL;
|
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"
|
" -h --help Show this help\n"
|
||||||
" --version Show package version\n"
|
" --version Show package version\n"
|
||||||
"\n%3$sOptions:%4$s\n"
|
"\n%3$sOptions:%4$s\n"
|
||||||
" --mutable=yes|no|auto|import|ephemeral|ephemeral-import|help\n"
|
" --mutable=yes|no|auto|import|ephemeral|ephemeral-import\n"
|
||||||
" Specify a mutability mode of the merged hierarchy\n"
|
" Specify a mutability mode of the merged hierarchy\n"
|
||||||
" --no-pager Do not pipe output into a pager\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
" --no-legend Do not show the headers and footers\n"
|
" --no-legend Do not show the headers and footers\n"
|
||||||
@ -2577,14 +2577,6 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARG_MUTABLE:
|
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);
|
r = parse_mutable_mode(optarg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse argument to --mutable=: %s", optarg);
|
return log_error_errno(r, "Failed to parse argument to --mutable=: %s", optarg);
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
@ -12,18 +11,6 @@
|
|||||||
|
|
||||||
#define TRIAL 100u
|
#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) {
|
TEST(parse_sec) {
|
||||||
usec_t u;
|
usec_t u;
|
||||||
|
|
||||||
@ -403,33 +390,35 @@ TEST(format_timestamp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_format_timestamp_impl(usec_t x) {
|
static void test_format_timestamp_impl(usec_t x) {
|
||||||
const char *xx = FORMAT_TIMESTAMP(x);
|
bool success, override;
|
||||||
ASSERT_NOT_NULL(xx);
|
const char *xx, *yy;
|
||||||
|
usec_t y, x_sec, y_sec;
|
||||||
|
|
||||||
usec_t y;
|
xx = FORMAT_TIMESTAMP(x);
|
||||||
|
ASSERT_NOT_NULL(xx);
|
||||||
ASSERT_OK(parse_timestamp(xx, &y));
|
ASSERT_OK(parse_timestamp(xx, &y));
|
||||||
const char *yy = FORMAT_TIMESTAMP(y);
|
yy = FORMAT_TIMESTAMP(y);
|
||||||
ASSERT_NOT_NULL(yy);
|
ASSERT_NOT_NULL(yy);
|
||||||
|
|
||||||
usec_t x_sec = x / USEC_PER_SEC;
|
x_sec = x / USEC_PER_SEC;
|
||||||
usec_t y_sec = y / USEC_PER_SEC;
|
y_sec = y / USEC_PER_SEC;
|
||||||
|
success = (x_sec == y_sec) && streq(xx, yy);
|
||||||
if (x_sec == y_sec && streq(xx, yy))
|
/* Workaround for https://github.com/systemd/systemd/issues/28472
|
||||||
return; /* Yay!*/
|
* and https://github.com/systemd/systemd/pull/35471. */
|
||||||
|
override = !success &&
|
||||||
/* When the timezone is built with rearguard being enabled (e.g. old Ubuntu and RHEL), the following
|
(STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
|
||||||
* timezone may provide time shifted 1 hour from the original. See
|
STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
|
||||||
* https://github.com/systemd/systemd/issues/28472 and https://github.com/systemd/systemd/pull/35471 */
|
(x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
|
||||||
bool ignore =
|
log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
|
||||||
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",
|
"@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
|
||||||
x, xx, y, yy,
|
x, xx, y, yy,
|
||||||
ignore ? ", ignoring." : "");
|
override ? ", ignoring." : "");
|
||||||
|
if (!override) {
|
||||||
ASSERT_TRUE(ignore);
|
if (!success)
|
||||||
|
log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
|
||||||
|
ASSERT_EQ(x_sec, y_sec);
|
||||||
|
ASSERT_STREQ(xx, yy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_format_timestamp_loop(void) {
|
static void test_format_timestamp_loop(void) {
|
||||||
@ -456,13 +445,24 @@ TEST(FORMAT_TIMESTAMP) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_format_timestamp_with_tz_one(const char *tz) {
|
static void test_format_timestamp_with_tz_one(const char *tz) {
|
||||||
|
const char *saved_tz, *colon_tz;
|
||||||
|
|
||||||
if (!timezone_is_valid(tz, LOG_DEBUG))
|
if (!timezone_is_valid(tz, LOG_DEBUG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SAVE_TIMEZONE;
|
log_info("/* %s(%s) */", __func__, tz);
|
||||||
set_timezone(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]));
|
||||||
|
|
||||||
test_format_timestamp_loop();
|
test_format_timestamp_loop();
|
||||||
|
|
||||||
|
assert_se(set_unset_env("TZ", saved_tz, true) == 0);
|
||||||
|
tzset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FORMAT_TIMESTAMP_with_tz) {
|
TEST(FORMAT_TIMESTAMP_with_tz) {
|
||||||
@ -661,35 +661,6 @@ TEST(format_timestamp_range) {
|
|||||||
test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL);
|
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) {
|
static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
|
||||||
usec_t usec = USEC_INFINITY;
|
usec_t usec = USEC_INFINITY;
|
||||||
int r;
|
int r;
|
||||||
@ -1013,13 +984,24 @@ TEST(parse_timestamp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_parse_timestamp_with_tz_one(const char *tz) {
|
static void test_parse_timestamp_with_tz_one(const char *tz) {
|
||||||
|
const char *saved_tz, *colon_tz;
|
||||||
|
|
||||||
if (!timezone_is_valid(tz, LOG_DEBUG))
|
if (!timezone_is_valid(tz, LOG_DEBUG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SAVE_TIMEZONE;
|
log_info("/* %s(%s) */", __func__, tz);
|
||||||
set_timezone(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]));
|
||||||
|
|
||||||
test_parse_timestamp_impl(tz);
|
test_parse_timestamp_impl(tz);
|
||||||
|
|
||||||
|
assert_se(set_unset_env("TZ", saved_tz, true) == 0);
|
||||||
|
tzset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(parse_timestamp_with_tz) {
|
TEST(parse_timestamp_with_tz) {
|
||||||
@ -1111,7 +1093,7 @@ TEST(usec_shift_clock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(in_utc_timezone) {
|
TEST(in_utc_timezone) {
|
||||||
SAVE_TIMEZONE;
|
const char *tz = getenv("TZ");
|
||||||
|
|
||||||
assert_se(setenv("TZ", ":UTC", 1) >= 0);
|
assert_se(setenv("TZ", ":UTC", 1) >= 0);
|
||||||
assert_se(in_utc_timezone());
|
assert_se(in_utc_timezone());
|
||||||
@ -1124,6 +1106,9 @@ TEST(in_utc_timezone) {
|
|||||||
assert_se(!in_utc_timezone());
|
assert_se(!in_utc_timezone());
|
||||||
ASSERT_STREQ(tzname[0], "CET");
|
ASSERT_STREQ(tzname[0], "CET");
|
||||||
ASSERT_STREQ(tzname[1], "CEST");
|
ASSERT_STREQ(tzname[1], "CEST");
|
||||||
|
|
||||||
|
assert_se(set_unset_env("TZ", tz, true) == 0);
|
||||||
|
tzset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(map_clock_usec) {
|
TEST(map_clock_usec) {
|
||||||
@ -1177,12 +1162,14 @@ static void test_timezone_offset_change_one(const char *utc, const char *pretty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(timezone_offset_change) {
|
TEST(timezone_offset_change) {
|
||||||
SAVE_TIMEZONE;
|
const char *tz = getenv("TZ");
|
||||||
|
|
||||||
/* See issue #26370. */
|
/* See issue #26370. */
|
||||||
|
|
||||||
if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
|
if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
|
||||||
set_timezone("Africa/Casablanca");
|
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]));
|
||||||
|
|
||||||
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 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");
|
test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00");
|
||||||
@ -1193,7 +1180,9 @@ TEST(timezone_offset_change) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
|
if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
|
||||||
set_timezone("Asia/Atyrau");
|
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]));
|
||||||
|
|
||||||
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 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");
|
test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05");
|
||||||
@ -1202,13 +1191,18 @@ TEST(timezone_offset_change) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
|
if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
|
||||||
set_timezone("Chile/EasterIsland");
|
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]));
|
||||||
|
|
||||||
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 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 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 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");
|
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) {
|
static usec_t absdiff(usec_t a, usec_t b) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user