mirror of
https://github.com/systemd/systemd
synced 2026-03-19 19:44:48 +01:00
Compare commits
10 Commits
fac6511e49
...
7e4dcd2d1f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e4dcd2d1f | ||
|
|
66e6128fc3 | ||
|
|
37923b3d48 | ||
|
|
4b6bc397b4 | ||
|
|
e6a16a821c | ||
|
|
a7b73cc867 | ||
|
|
13bb1ffb91 | ||
|
|
41bc83ed51 | ||
|
|
dc9849b1e5 | ||
|
|
bdaeafea5d |
32
NEWS
32
NEWS
@ -28,17 +28,17 @@ CHANGES WITH 249 in spe:
|
||||
specified root user exists already in the image. (Note that
|
||||
--volatile=yes ensures it doesn't, though.)
|
||||
|
||||
* PID 1 may now show both the unit name and the unit description
|
||||
strings in its status output during boot. This may be configured with
|
||||
StatusUnitFormat=combined in system.conf or
|
||||
systemd.status-unit-format=combined on the kernel command line.
|
||||
|
||||
* systemd-firstboot now also supports querying various system
|
||||
parameters via the credential subsystems. Thus, as above this may be
|
||||
used to initialize important system parameters on first boot of
|
||||
previously unprovisioned images (i.e. images with a mostly empty
|
||||
/etc/).
|
||||
|
||||
* PID 1 may now show both the unit name and the unit description
|
||||
strings in its status output during boot. This may be configured with
|
||||
StatusUnitFormat=combined in system.conf or
|
||||
systemd.status-unit-format=combined on the kernel command line.
|
||||
|
||||
* The systemd-machine-id-setup tool now supports a --image= switch for
|
||||
provisioning a machine ID file into an OS disk image, similar to how
|
||||
--root= operates on an OS file tree. This matches the existing switch
|
||||
@ -69,9 +69,10 @@ CHANGES WITH 249 in spe:
|
||||
and then stream their own root partition onto the target medium.
|
||||
|
||||
* systemd-repart's partition configuration files gained support for a
|
||||
Flags= and a ReadOnly= setting, allowing control of the GPT partition
|
||||
flags for the created partitions: this is useful for marking newly
|
||||
created partitions as read-only from the start.
|
||||
Flags=, a ReadOnly= and a NoAuto= setting, allowing control of these
|
||||
GPT partition flags for the created partitions: this is useful for
|
||||
marking newly created partitions as read-only, or as not being
|
||||
subject for automatic mounting from creation on.
|
||||
|
||||
* The /etc/os-release file has been extended with two new (optional)
|
||||
variables IMAGE_VERSION= and IMAGE_ID=, carrying identity and version
|
||||
@ -447,6 +448,11 @@ CHANGES WITH 249 in spe:
|
||||
(default, as before), turn echo off entirely, or echo the typed
|
||||
characters literally.
|
||||
|
||||
* The systemd-ask-password tool also gained a new -n switch for
|
||||
suppressing output of a trailing newline character when writing the
|
||||
acquired password to standard output, similar to /bin/echo's -n
|
||||
switch.
|
||||
|
||||
* New documentation has been added that describes the organization of
|
||||
the systemd source code tree:
|
||||
|
||||
@ -503,6 +509,14 @@ CHANGES WITH 249 in spe:
|
||||
and friends), all file systems will be mounted with MS_NOSUID by
|
||||
default, unless the system is running with SELinux enabled.
|
||||
|
||||
* When enumerating time zones the timedatectl tool will now consult the
|
||||
'tzdata.zi' file shipped by the IANA time zone database package, in
|
||||
addition to 'zone1970.tab', as before. This makes sure time zone
|
||||
aliases are now correctly supported. Some distributions so far did
|
||||
not install this additional file, most do however. If you
|
||||
distribution does not install it yet, it might make sense to change
|
||||
that.
|
||||
|
||||
Contributions from: Aakash Singh, adrian5, Albert Brox,
|
||||
Alexander Sverdlin, Alexander Tsoy, alexlzhu, Allen Webb,
|
||||
Alvin Šipraga, Alyssa Ross, Anders Wenhaug, Andrea Pappacoda,
|
||||
@ -534,7 +548,7 @@ CHANGES WITH 249 in spe:
|
||||
William A. Kennington III, Yangyang Shen, Yegor Alexeyev, Yi Gao,
|
||||
Yu Watanabe, Zbigniew Jędrzejewski-Szmek, zsien, наб
|
||||
|
||||
— Warsaw, 2021-06-25
|
||||
— Berlin, 2021-07-01
|
||||
|
||||
CHANGES WITH 248:
|
||||
|
||||
|
||||
3
TODO
3
TODO
@ -1366,6 +1366,9 @@ Features:
|
||||
but much rather a disconnect on success.
|
||||
- when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr
|
||||
- when a bus name of a service disappears from the bus make sure to queue further activation requests
|
||||
- maybe introduce CoreScheduling=yes/no to optionally set a PR_SCHED_CORE cookie, so that all
|
||||
processes in a service's cgroup share the same cookie and are guaranteed not to share SMT cores
|
||||
with other units https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/hw-vuln/core-scheduling.rst
|
||||
|
||||
* unit files:
|
||||
- allow port=0 in .socket units
|
||||
|
||||
@ -216,6 +216,12 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnE4D6_HI-122LP:*
|
||||
sensor:modalias:acpi:KIOX000A*:dmi:*:svnChuwi*:pnHi13:*
|
||||
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
||||
|
||||
# Chuwi Hi13 (CWI534) with BMA250 sensor
|
||||
# Note this sets the norm matrix, since the matrix which the kernel reads
|
||||
# from the ACPI tables is actually wrong on these models
|
||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnChuwi*:pnHi13:*
|
||||
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, 1, 0; 0, 0, 1
|
||||
|
||||
# Chuwi HiBook
|
||||
# Chuwi HiBook does not have its product name filled, so we
|
||||
# match the entire dmi-alias, assuming that the use of a BOSC0200 +
|
||||
|
||||
@ -81,9 +81,6 @@ KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ENV{ID_NAME}="$attr
|
||||
KERNEL=="mmcblk[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
|
||||
KERNEL=="mmcblk[0-9]p[0-9]*", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
|
||||
|
||||
# UBI-MTD
|
||||
SUBSYSTEM=="ubi", KERNEL=="ubi*_*", ATTRS{mtd_num}=="*", SYMLINK+="ubi_mtd%s{mtd_num}_%s{name}"
|
||||
|
||||
# Memstick
|
||||
KERNEL=="msblk[0-9]|mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", \
|
||||
ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
|
||||
|
||||
@ -1381,7 +1381,7 @@ int get_timezones(char ***ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool timezone_is_valid(const char *name, int log_level) {
|
||||
int verify_timezone(const char *name, int log_level) {
|
||||
bool slash = false;
|
||||
const char *p, *t;
|
||||
_cleanup_close_ int fd = -1;
|
||||
@ -1389,26 +1389,26 @@ bool timezone_is_valid(const char *name, int log_level) {
|
||||
int r;
|
||||
|
||||
if (isempty(name))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */
|
||||
if (streq(name, "UTC"))
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
if (name[0] == '/')
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
for (p = name; *p; p++) {
|
||||
if (!(*p >= '0' && *p <= '9') &&
|
||||
!(*p >= 'a' && *p <= 'z') &&
|
||||
!(*p >= 'A' && *p <= 'Z') &&
|
||||
!IN_SET(*p, '-', '_', '+', '/'))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (*p == '/') {
|
||||
|
||||
if (slash)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
slash = true;
|
||||
} else
|
||||
@ -1416,38 +1416,31 @@ bool timezone_is_valid(const char *name, int log_level) {
|
||||
}
|
||||
|
||||
if (slash)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (p - name >= PATH_MAX)
|
||||
return false;
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
t = strjoina("/usr/share/zoneinfo/", name);
|
||||
|
||||
fd = open(t, O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
|
||||
return false;
|
||||
}
|
||||
if (fd < 0)
|
||||
return log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
|
||||
|
||||
r = fd_verify_regular(fd);
|
||||
if (r < 0) {
|
||||
log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
|
||||
return false;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
|
||||
|
||||
r = loop_read_exact(fd, buf, 4, false);
|
||||
if (r < 0) {
|
||||
log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
|
||||
return false;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
|
||||
|
||||
/* Magic from tzfile(5) */
|
||||
if (memcmp(buf, "TZif", 4) != 0) {
|
||||
log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
|
||||
return false;
|
||||
}
|
||||
if (memcmp(buf, "TZif", 4) != 0)
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EIO),
|
||||
"Timezone file '%s' has wrong magic bytes", t);
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool clock_boottime_supported(void) {
|
||||
|
||||
@ -134,7 +134,10 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit);
|
||||
int parse_nsec(const char *t, nsec_t *nsec);
|
||||
|
||||
int get_timezones(char ***l);
|
||||
bool timezone_is_valid(const char *name, int log_level);
|
||||
int verify_timezone(const char *name, int log_level);
|
||||
static inline bool timezone_is_valid(const char *name, int log_level) {
|
||||
return verify_timezone(name, log_level) >= 0;
|
||||
}
|
||||
|
||||
bool clock_boottime_supported(void);
|
||||
bool clock_supported(clockid_t clock);
|
||||
|
||||
@ -3384,11 +3384,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
else
|
||||
clean_mode = EXIT_CLEAN_DAEMON;
|
||||
|
||||
if (s->main_pid == pid)
|
||||
/* Clean up the exec_fd event source. The source owns its end of the pipe, so this will close
|
||||
* that too. */
|
||||
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
|
||||
|
||||
if (is_clean_exit(code, status, clean_mode, &s->success_status))
|
||||
f = SERVICE_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
@ -3401,6 +3396,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
assert_not_reached("Unknown code");
|
||||
|
||||
if (s->main_pid == pid) {
|
||||
/* Clean up the exec_fd event source. We want to do this here, not later in
|
||||
* service_set_state(), because service_enter_stop_post() calls service_spawn().
|
||||
* The source owns its end of the pipe, so this will close that too. */
|
||||
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
|
||||
|
||||
/* Forking services may occasionally move to a new PID.
|
||||
* As long as they update the PID file before exiting the old
|
||||
* PID, they're fine. */
|
||||
|
||||
@ -1340,27 +1340,35 @@ const char* unit_description(Unit *u) {
|
||||
return strna(u->id);
|
||||
}
|
||||
|
||||
const char* unit_status_string(Unit *u, char **combined) {
|
||||
const char* unit_status_string(Unit *u, char **ret_combined_buffer) {
|
||||
assert(u);
|
||||
assert(u->id);
|
||||
|
||||
/* Return u->id, u->description, or "{u->id} - {u->description}".
|
||||
* Versions with u->description are only used if it is set.
|
||||
* The last option is used if configured and the caller provided 'combined' pointer. */
|
||||
* The last option is used if configured and the caller provided the 'ret_combined_buffer'
|
||||
* pointer.
|
||||
*
|
||||
* Note that *ret_combined_buffer may be set to NULL. */
|
||||
|
||||
if (!u->description ||
|
||||
streq(u->description, u->id) ||
|
||||
u->manager->status_unit_format == STATUS_UNIT_FORMAT_NAME ||
|
||||
(u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && !combined))
|
||||
return u->id;
|
||||
(u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && !ret_combined_buffer) ||
|
||||
streq(u->description, u->id)) {
|
||||
|
||||
if (u->description && u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && combined) {
|
||||
char *t = strjoin(u->id, " - ", u->description);
|
||||
if (t) {
|
||||
*combined = t;
|
||||
return t;
|
||||
if (ret_combined_buffer)
|
||||
*ret_combined_buffer = NULL;
|
||||
return u->id;
|
||||
}
|
||||
|
||||
if (ret_combined_buffer) {
|
||||
if (u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED) {
|
||||
*ret_combined_buffer = strjoin(u->id, " - ", u->description);
|
||||
if (*ret_combined_buffer)
|
||||
return *ret_combined_buffer;
|
||||
log_oom(); /* Fall back to ->description */
|
||||
} else
|
||||
log_oom();
|
||||
*ret_combined_buffer = NULL;
|
||||
}
|
||||
|
||||
return u->description;
|
||||
|
||||
@ -202,13 +202,13 @@ static void test_format_timespan_one(usec_t x, usec_t accuracy) {
|
||||
const char *t;
|
||||
usec_t y;
|
||||
|
||||
log_info(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
|
||||
log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
|
||||
|
||||
assert_se(t = format_timespan(l, sizeof l, x, accuracy));
|
||||
log_info(" = <%s>", t);
|
||||
log_debug(" = <%s>", t);
|
||||
|
||||
assert_se(parse_sec(t, &y) >= 0);
|
||||
log_info(" = "USEC_FMT, y);
|
||||
log_debug(" = "USEC_FMT, y);
|
||||
|
||||
if (accuracy <= 0)
|
||||
accuracy = 1;
|
||||
@ -243,6 +243,17 @@ static void test_format_timespan(usec_t accuracy) {
|
||||
test_format_timespan_one(USEC_INFINITY, accuracy);
|
||||
}
|
||||
|
||||
static void test_verify_timezone(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(verify_timezone("Europe/Berlin", LOG_DEBUG) == 0);
|
||||
assert_se(verify_timezone("Australia/Sydney", LOG_DEBUG) == 0);
|
||||
assert_se(verify_timezone("Europe/Do not exist", LOG_DEBUG) == -EINVAL);
|
||||
assert_se(verify_timezone("Europe/DoNotExist", LOG_DEBUG) == -ENOENT);
|
||||
assert_se(verify_timezone("/DoNotExist", LOG_DEBUG) == -EINVAL);
|
||||
assert_se(verify_timezone("DoNotExist/", LOG_DEBUG) == -EINVAL);
|
||||
}
|
||||
|
||||
static void test_timezone_is_valid(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
@ -262,8 +273,9 @@ static void test_get_timezones(void) {
|
||||
assert_se(r == 0);
|
||||
|
||||
STRV_FOREACH(zone, zones) {
|
||||
log_info("zone: %s", *zone);
|
||||
assert_se(timezone_is_valid(*zone, LOG_ERR));
|
||||
r = verify_timezone(*zone, LOG_ERR);
|
||||
log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone);
|
||||
assert_se(r >= 0 || r == -ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,11 +329,9 @@ static void test_usec_sub_signed(void) {
|
||||
}
|
||||
|
||||
static void test_format_timestamp(void) {
|
||||
unsigned i;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
for (unsigned i = 0; i < 100; i++) {
|
||||
char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
|
||||
usec_t x, y;
|
||||
|
||||
@ -329,27 +339,27 @@ static void test_format_timestamp(void) {
|
||||
x = x % (2147483600 * USEC_PER_SEC) + 1;
|
||||
|
||||
assert_se(format_timestamp(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
|
||||
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
|
||||
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x == y);
|
||||
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x == y);
|
||||
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
|
||||
/* The two calls above will run with a slightly different local time. Make sure we are in the same
|
||||
@ -373,64 +383,64 @@ static void test_format_timestamp_relative(void) {
|
||||
/* Years and months */
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 year 1 month ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 year 2 months ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 years 1 month ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 years 2 months ago"));
|
||||
|
||||
/* Months and days */
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 month 1 day ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 month 2 days ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 months 1 day ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 months 2 days ago"));
|
||||
|
||||
/* Weeks and days */
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 week 1 day ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "1 week 2 days ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 weeks 1 day ago"));
|
||||
|
||||
x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
|
||||
assert_se(format_timestamp_relative(buf, sizeof(buf), x));
|
||||
log_info("%s", buf);
|
||||
log_debug("%s", buf);
|
||||
assert_se(streq(buf, "2 weeks 2 days ago"));
|
||||
}
|
||||
|
||||
@ -607,6 +617,7 @@ int main(int argc, char *argv[]) {
|
||||
test_format_timespan(1);
|
||||
test_format_timespan(USEC_PER_MSEC);
|
||||
test_format_timespan(USEC_PER_SEC);
|
||||
test_verify_timezone();
|
||||
test_timezone_is_valid();
|
||||
test_get_timezones();
|
||||
test_usec_add();
|
||||
|
||||
@ -66,9 +66,6 @@ KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*"
|
||||
ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
|
||||
KERNEL=="mmcblk[0-9]p[0-9]*", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
|
||||
|
||||
# UBI-MTD
|
||||
SUBSYSTEM=="ubi", KERNEL=="ubi*_*", ATTRS{mtd_num}=="*", SYMLINK+="ubi_mtd%s{mtd_num}_%s{name}"
|
||||
|
||||
# Memstick
|
||||
KERNEL=="msblk[0-9]|mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", \
|
||||
ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user