1
0
mirror of https://github.com/systemd/systemd synced 2026-03-20 03:54:45 +01:00

Compare commits

..

No commits in common. "7e4dcd2d1fa32c9f2d3497f514c2dc371cda3f45" and "fac6511e4943f9a873f136c0bb3185d3cd8cbbfa" have entirely different histories.

10 changed files with 81 additions and 113 deletions

32
NEWS
View File

@ -28,17 +28,17 @@ CHANGES WITH 249 in spe:
specified root user exists already in the image. (Note that specified root user exists already in the image. (Note that
--volatile=yes ensures it doesn't, though.) --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 * systemd-firstboot now also supports querying various system
parameters via the credential subsystems. Thus, as above this may be parameters via the credential subsystems. Thus, as above this may be
used to initialize important system parameters on first boot of used to initialize important system parameters on first boot of
previously unprovisioned images (i.e. images with a mostly empty previously unprovisioned images (i.e. images with a mostly empty
/etc/). /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 * 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 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 --root= operates on an OS file tree. This matches the existing switch
@ -69,10 +69,9 @@ CHANGES WITH 249 in spe:
and then stream their own root partition onto the target medium. and then stream their own root partition onto the target medium.
* systemd-repart's partition configuration files gained support for a * systemd-repart's partition configuration files gained support for a
Flags=, a ReadOnly= and a NoAuto= setting, allowing control of these Flags= and a ReadOnly= setting, allowing control of the GPT partition
GPT partition flags for the created partitions: this is useful for flags for the created partitions: this is useful for marking newly
marking newly created partitions as read-only, or as not being created partitions as read-only from the start.
subject for automatic mounting from creation on.
* The /etc/os-release file has been extended with two new (optional) * The /etc/os-release file has been extended with two new (optional)
variables IMAGE_VERSION= and IMAGE_ID=, carrying identity and version variables IMAGE_VERSION= and IMAGE_ID=, carrying identity and version
@ -448,11 +447,6 @@ CHANGES WITH 249 in spe:
(default, as before), turn echo off entirely, or echo the typed (default, as before), turn echo off entirely, or echo the typed
characters literally. 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 * New documentation has been added that describes the organization of
the systemd source code tree: the systemd source code tree:
@ -509,14 +503,6 @@ CHANGES WITH 249 in spe:
and friends), all file systems will be mounted with MS_NOSUID by and friends), all file systems will be mounted with MS_NOSUID by
default, unless the system is running with SELinux enabled. 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, Contributions from: Aakash Singh, adrian5, Albert Brox,
Alexander Sverdlin, Alexander Tsoy, alexlzhu, Allen Webb, Alexander Sverdlin, Alexander Tsoy, alexlzhu, Allen Webb,
Alvin Šipraga, Alyssa Ross, Anders Wenhaug, Andrea Pappacoda, Alvin Šipraga, Alyssa Ross, Anders Wenhaug, Andrea Pappacoda,
@ -548,7 +534,7 @@ CHANGES WITH 249 in spe:
William A. Kennington III, Yangyang Shen, Yegor Alexeyev, Yi Gao, William A. Kennington III, Yangyang Shen, Yegor Alexeyev, Yi Gao,
Yu Watanabe, Zbigniew Jędrzejewski-Szmek, zsien, наб Yu Watanabe, Zbigniew Jędrzejewski-Szmek, zsien, наб
Berlin, 2021-07-01 Warsaw, 2021-06-25
CHANGES WITH 248: CHANGES WITH 248:

3
TODO
View File

@ -1366,9 +1366,6 @@ Features:
but much rather a disconnect on success. 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 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 - 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: * unit files:
- allow port=0 in .socket units - allow port=0 in .socket units

View File

@ -216,12 +216,6 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnE4D6_HI-122LP:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnChuwi*:pnHi13:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnChuwi*:pnHi13:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 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
# Chuwi HiBook does not have its product name filled, so we # Chuwi HiBook does not have its product name filled, so we
# match the entire dmi-alias, assuming that the use of a BOSC0200 + # match the entire dmi-alias, assuming that the use of a BOSC0200 +

View File

@ -81,6 +81,9 @@ 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]", 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" 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 # Memstick
KERNEL=="msblk[0-9]|mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", \ 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}" ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"

View File

@ -1381,7 +1381,7 @@ int get_timezones(char ***ret) {
return 0; return 0;
} }
int verify_timezone(const char *name, int log_level) { bool timezone_is_valid(const char *name, int log_level) {
bool slash = false; bool slash = false;
const char *p, *t; const char *p, *t;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
@ -1389,26 +1389,26 @@ int verify_timezone(const char *name, int log_level) {
int r; int r;
if (isempty(name)) if (isempty(name))
return -EINVAL; return false;
/* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */ /* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */
if (streq(name, "UTC")) if (streq(name, "UTC"))
return 0; return true;
if (name[0] == '/') if (name[0] == '/')
return -EINVAL; return false;
for (p = name; *p; p++) { for (p = name; *p; p++) {
if (!(*p >= '0' && *p <= '9') && if (!(*p >= '0' && *p <= '9') &&
!(*p >= 'a' && *p <= 'z') && !(*p >= 'a' && *p <= 'z') &&
!(*p >= 'A' && *p <= 'Z') && !(*p >= 'A' && *p <= 'Z') &&
!IN_SET(*p, '-', '_', '+', '/')) !IN_SET(*p, '-', '_', '+', '/'))
return -EINVAL; return false;
if (*p == '/') { if (*p == '/') {
if (slash) if (slash)
return -EINVAL; return false;
slash = true; slash = true;
} else } else
@ -1416,31 +1416,38 @@ int verify_timezone(const char *name, int log_level) {
} }
if (slash) if (slash)
return -EINVAL; return false;
if (p - name >= PATH_MAX) if (p - name >= PATH_MAX)
return -ENAMETOOLONG; return false;
t = strjoina("/usr/share/zoneinfo/", name); t = strjoina("/usr/share/zoneinfo/", name);
fd = open(t, O_RDONLY|O_CLOEXEC); fd = open(t, O_RDONLY|O_CLOEXEC);
if (fd < 0) if (fd < 0) {
return log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t); log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
return false;
}
r = fd_verify_regular(fd); r = fd_verify_regular(fd);
if (r < 0) if (r < 0) {
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t); log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
return false;
}
r = loop_read_exact(fd, buf, 4, false); r = loop_read_exact(fd, buf, 4, false);
if (r < 0) if (r < 0) {
return log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t); log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
return false;
}
/* Magic from tzfile(5) */ /* Magic from tzfile(5) */
if (memcmp(buf, "TZif", 4) != 0) if (memcmp(buf, "TZif", 4) != 0) {
return log_full_errno(log_level, SYNTHETIC_ERRNO(EIO), log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
"Timezone file '%s' has wrong magic bytes", t); return false;
}
return 0; return true;
} }
bool clock_boottime_supported(void) { bool clock_boottime_supported(void) {

View File

@ -134,10 +134,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit);
int parse_nsec(const char *t, nsec_t *nsec); int parse_nsec(const char *t, nsec_t *nsec);
int get_timezones(char ***l); int get_timezones(char ***l);
int verify_timezone(const char *name, int log_level); bool timezone_is_valid(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_boottime_supported(void);
bool clock_supported(clockid_t clock); bool clock_supported(clockid_t clock);

View File

@ -3384,6 +3384,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else else
clean_mode = EXIT_CLEAN_DAEMON; 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)) if (is_clean_exit(code, status, clean_mode, &s->success_status))
f = SERVICE_SUCCESS; f = SERVICE_SUCCESS;
else if (code == CLD_EXITED) else if (code == CLD_EXITED)
@ -3396,11 +3401,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
assert_not_reached("Unknown code"); assert_not_reached("Unknown code");
if (s->main_pid == pid) { 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. /* Forking services may occasionally move to a new PID.
* As long as they update the PID file before exiting the old * As long as they update the PID file before exiting the old
* PID, they're fine. */ * PID, they're fine. */

View File

@ -1340,35 +1340,27 @@ const char* unit_description(Unit *u) {
return strna(u->id); return strna(u->id);
} }
const char* unit_status_string(Unit *u, char **ret_combined_buffer) { const char* unit_status_string(Unit *u, char **combined) {
assert(u); assert(u);
assert(u->id); assert(u->id);
/* Return u->id, u->description, or "{u->id} - {u->description}". /* Return u->id, u->description, or "{u->id} - {u->description}".
* Versions with u->description are only used if it is set. * Versions with u->description are only used if it is set.
* The last option is used if configured and the caller provided the 'ret_combined_buffer' * The last option is used if configured and the caller provided 'combined' pointer. */
* pointer.
*
* Note that *ret_combined_buffer may be set to NULL. */
if (!u->description || 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_NAME ||
(u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && !ret_combined_buffer) || (u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && !combined))
streq(u->description, u->id)) {
if (ret_combined_buffer)
*ret_combined_buffer = NULL;
return u->id; return u->id;
}
if (ret_combined_buffer) { if (u->description && u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && combined) {
if (u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED) { char *t = strjoin(u->id, " - ", u->description);
*ret_combined_buffer = strjoin(u->id, " - ", u->description); if (t) {
if (*ret_combined_buffer) *combined = t;
return *ret_combined_buffer; return t;
log_oom(); /* Fall back to ->description */
} else } else
*ret_combined_buffer = NULL; log_oom();
} }
return u->description; return u->description;

View File

@ -202,13 +202,13 @@ static void test_format_timespan_one(usec_t x, usec_t accuracy) {
const char *t; const char *t;
usec_t y; usec_t y;
log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy); log_info(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
assert_se(t = format_timespan(l, sizeof l, x, accuracy)); assert_se(t = format_timespan(l, sizeof l, x, accuracy));
log_debug(" = <%s>", t); log_info(" = <%s>", t);
assert_se(parse_sec(t, &y) >= 0); assert_se(parse_sec(t, &y) >= 0);
log_debug(" = "USEC_FMT, y); log_info(" = "USEC_FMT, y);
if (accuracy <= 0) if (accuracy <= 0)
accuracy = 1; accuracy = 1;
@ -243,17 +243,6 @@ static void test_format_timespan(usec_t accuracy) {
test_format_timespan_one(USEC_INFINITY, 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) { static void test_timezone_is_valid(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
@ -273,9 +262,8 @@ static void test_get_timezones(void) {
assert_se(r == 0); assert_se(r == 0);
STRV_FOREACH(zone, zones) { STRV_FOREACH(zone, zones) {
r = verify_timezone(*zone, LOG_ERR); log_info("zone: %s", *zone);
log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone); assert_se(timezone_is_valid(*zone, LOG_ERR));
assert_se(r >= 0 || r == -ENOENT);
} }
} }
@ -329,9 +317,11 @@ static void test_usec_sub_signed(void) {
} }
static void test_format_timestamp(void) { static void test_format_timestamp(void) {
unsigned i;
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
for (unsigned i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
usec_t x, y; usec_t x, y;
@ -339,27 +329,27 @@ static void test_format_timestamp(void) {
x = x % (2147483600 * USEC_PER_SEC) + 1; x = x % (2147483600 * USEC_PER_SEC) + 1;
assert_se(format_timestamp(buf, sizeof(buf), x)); assert_se(format_timestamp(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0); assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC)); assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
log_debug("%s", buf); log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0); assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US)); assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
log_debug("%s", buf); log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0); assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x == y); assert_se(x == y);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC)); assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
log_debug("%s", buf); log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0); assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x == y); assert_se(x == y);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0); 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 /* The two calls above will run with a slightly different local time. Make sure we are in the same
@ -383,64 +373,64 @@ static void test_format_timestamp_relative(void) {
/* Years and months */ /* Years and months */
x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 year 1 month ago")); assert_se(streq(buf, "1 year 1 month ago"));
x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH); x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 year 2 months ago")); assert_se(streq(buf, "1 year 2 months ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH); x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 years 1 month ago")); assert_se(streq(buf, "2 years 1 month ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH); x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 years 2 months ago")); assert_se(streq(buf, "2 years 2 months ago"));
/* Months and days */ /* Months and days */
x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 month 1 day ago")); assert_se(streq(buf, "1 month 1 day ago"));
x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 month 2 days ago")); assert_se(streq(buf, "1 month 2 days ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 months 1 day ago")); assert_se(streq(buf, "2 months 1 day ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 months 2 days ago")); assert_se(streq(buf, "2 months 2 days ago"));
/* Weeks and days */ /* Weeks and days */
x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 week 1 day ago")); assert_se(streq(buf, "1 week 1 day ago"));
x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "1 week 2 days ago")); assert_se(streq(buf, "1 week 2 days ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 weeks 1 day ago")); assert_se(streq(buf, "2 weeks 1 day ago"));
x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY); x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
assert_se(format_timestamp_relative(buf, sizeof(buf), x)); assert_se(format_timestamp_relative(buf, sizeof(buf), x));
log_debug("%s", buf); log_info("%s", buf);
assert_se(streq(buf, "2 weeks 2 days ago")); assert_se(streq(buf, "2 weeks 2 days ago"));
} }
@ -617,7 +607,6 @@ int main(int argc, char *argv[]) {
test_format_timespan(1); test_format_timespan(1);
test_format_timespan(USEC_PER_MSEC); test_format_timespan(USEC_PER_MSEC);
test_format_timespan(USEC_PER_SEC); test_format_timespan(USEC_PER_SEC);
test_verify_timezone();
test_timezone_is_valid(); test_timezone_is_valid();
test_get_timezones(); test_get_timezones();
test_usec_add(); test_usec_add();

View File

@ -66,6 +66,9 @@ 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}" 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" 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 # Memstick
KERNEL=="msblk[0-9]|mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", \ 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}" ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"