summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--man/systemctl.xml5
-rw-r--r--man/systemd.timer.xml14
-rw-r--r--src/basic/in-addr-util.c2
-rw-r--r--src/core/dbus-manager.c10
-rw-r--r--src/core/dbus-timer.c6
-rw-r--r--src/core/dbus-unit.c17
-rw-r--r--src/core/dbus-unit.h2
-rw-r--r--src/core/execute.c6
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c5
-rw-r--r--src/core/main.c2
-rw-r--r--src/core/mount.c2
-rw-r--r--src/core/socket.c2
-rw-r--r--src/core/swap.c2
-rw-r--r--src/core/triggers.systemd.in46
-rw-r--r--src/core/unit.c6
-rw-r--r--src/core/unit.h2
-rw-r--r--src/fstab-generator/fstab-generator.c10
-rw-r--r--src/journal/journald-stream.c10
-rw-r--r--src/libsystemd-network/dhcp-internal.h3
-rw-r--r--src/libsystemd-network/dhcp-option.c109
-rw-r--r--src/libsystemd-network/dhcp-protocol.h1
-rw-r--r--src/libsystemd-network/icmp6-util.c44
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c52
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c19
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c22
-rw-r--r--src/libsystemd-network/sd-ndisc.c75
-rw-r--r--src/libsystemd-network/test-dhcp-client.c6
-rw-r--r--src/libsystemd-network/test-dhcp-option.c22
-rw-r--r--src/shared/bus-util.c6
-rw-r--r--src/test/test-unit-file.c21
-rwxr-xr-xtest/TEST-01-BASIC/test.sh2
-rwxr-xr-xtest/TEST-02-CRYPTSETUP/test.sh2
-rwxr-xr-xtest/TEST-03-JOBS/test.sh2
l---------test/TEST-04-JOURNAL/Makefile1
-rwxr-xr-xtest/TEST-04-JOURNAL/test-journal.sh55
-rwxr-xr-xtest/TEST-04-JOURNAL/test.sh76
-rw-r--r--test/test-functions2
40 files changed, 480 insertions, 196 deletions
diff --git a/Makefile.am b/Makefile.am
index 296f2c7e5f..6597d305d1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5680,6 +5680,9 @@ EXTRA_DIST += \
test/TEST-03-JOBS/Makefile \
test/TEST-03-JOBS/test-jobs.sh \
test/TEST-03-JOBS/test.sh \
+ test/TEST-04-JOURNAL/Makefile \
+ test/TEST-04-JOURNAL/test-journal.sh \
+ test/TEST-04-JOURNAL/test.sh \
test/test-functions
EXTRA_DIST += \
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 755a74f987..1fb056874c 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -888,6 +888,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<para>Example: <command>systemctl set-property foobar.service CPUShares=777</command></para>
+ <para>If the specified unit appears to be inactive, the
+ changes will be only stored on disk as described
+ previously hence they will be effective when the unit will
+ be started.</para>
+
<para>Note that this command allows changing multiple
properties at the same time, which is preferable over
setting them individually. Like unit file configuration
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index fd03bda9cd..cfa13015b0 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -205,7 +205,7 @@
</varlistentry>
<varlistentry>
- <term><varname>RandomSec=</varname></term>
+ <term><varname>RandomizedDelaySec=</varname></term>
<listitem><para>Delay the timer by a randomly selected, evenly
distributed amount of time between 0 and the specified time
@@ -222,16 +222,16 @@
time range in order to minimize wakeups, the former does the
opposite: it stretches timer events over a time range, to make
it unlikely that they fire simultaneously. If
- <varname>RandomSec=</varname> and
+ <varname>RandomizedDelaySec=</varname> and
<varname>AccuracySec=</varname> are used in conjunction, first
- the a randomized time is added, and the result is then
- possibly shifted further to coalesce it with other timer
- events possibly happening on the system. As mentioned above
+ the randomized delay is added, and then the result is
+ possibly further shifted to coalesce it with other timer
+ events happening on the system. As mentioned above
<varname>AccuracySec=</varname> defaults to 1min and
- <varname>RandomSec=</varname> to 0, thus encouraging
+ <varname>RandomizedDelaySec=</varname> to 0, thus encouraging
coalescing of timer events. In order to optimally stretch
timer events over a certain range of time, make sure to set
- <varname>RandomSec=</varname> to a higher value, and
+ <varname>RandomizedDelaySec=</varname> to a higher value, and
<varname>AccuracySec=1us</varname>.</para></listitem>
</varlistentry>
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index 1f61b68efd..b75c39aac7 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -59,7 +59,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
/* All of 127.x.x.x is localhost. */
return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
- if (family == AF_INET)
+ if (family == AF_INET6)
return IN6_IS_ADDR_LOOPBACK(&u->in6);
return -EAFNOSUPPORT;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4d730290b2..2562396180 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -630,9 +630,13 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+ r = manager_load_unit(m, name, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ r = bus_unit_check_load_state(u, error);
+ if (r < 0)
+ return r;
return bus_unit_method_set_properties(message, u, error);
}
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index 4bee82df07..ec301df6d7 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -180,7 +180,7 @@ const sd_bus_vtable bus_timer_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -284,7 +284,7 @@ static int bus_timer_set_transient_property(
return 1;
- } else if (streq(name, "RandomUSec")) {
+ } else if (streq(name, "RandomizedDelayUSec")) {
usec_t u = 0;
r = sd_bus_message_read(message, "t", &u);
@@ -295,7 +295,7 @@ static int bus_timer_set_transient_property(
char time[FORMAT_TIMESPAN_MAX];
t->random_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
}
return 1;
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index d9b7382c82..66b465a0b7 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -1251,3 +1251,20 @@ int bus_unit_set_properties(
return n;
}
+
+int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
+
+ if (u->load_state == UNIT_LOADED)
+ return 0;
+
+ /* Give a better description of the unit error when
+ * possible. Note that in the case of UNIT_MASKED, load_error
+ * is not set. */
+ if (u->load_state == UNIT_MASKED)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit is masked.");
+
+ if (u->load_state == UNIT_NOT_FOUND)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit not found.");
+
+ return sd_bus_error_set_errnof(error, u->load_error, "Unit is not loaded properly: %m.");
+}
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index b8c6ec398a..ac9ee2d6b8 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -38,3 +38,5 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
+
+int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
diff --git a/src/core/execute.c b/src/core/execute.c
index 07979bf8b3..4f67a9de83 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2056,7 +2056,7 @@ int exec_spawn(Unit *unit,
NULL);
pid = fork();
if (pid < 0)
- return log_unit_error_errno(unit, r, "Failed to fork: %m");
+ return log_unit_error_errno(unit, errno, "Failed to fork: %m");
if (pid == 0) {
int exit_status;
@@ -2414,8 +2414,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i])
- fprintf(f, "%s%s: "RLIM_FMT"\n",
- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
+ fprintf(f, "%s%s: " RLIM_FMT " " RLIM_FMT "\n",
+ prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur, c->rlimit[i]->rlim_max);
if (c->ioprio_set) {
_cleanup_free_ char *class_str = NULL;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index c64850802e..0408b9a829 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -347,7 +347,7 @@ Timer.Persistent, config_parse_bool, 0,
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
-Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec)
+Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0
m4_dnl
Path.PathExists, config_parse_path_spec, 0, 0
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 8847578bd7..3c124495b6 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1173,6 +1173,7 @@ static int parse_rlimit_range(
struct rlimit **rl,
int (*rlim_parser)(const char *, rlim_t *)) {
+ const char *whole_value = value;
rlim_t soft, hard;
_cleanup_free_ char *sword = NULL, *hword = NULL;
int nwords, r;
@@ -1188,9 +1189,11 @@ static int parse_rlimit_range(
if (r == 0 && nwords == 2)
r = rlim_parser(hword, &hard);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value);
return 0;
}
+ if (nwords == 2 && soft > hard)
+ return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value);
if (!*rl) {
*rl = new(struct rlimit, 1);
diff --git a/src/core/main.c b/src/core/main.c
index 97f904b031..ba1feedb9a 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1665,7 +1665,7 @@ int main(int argc, char *argv[]) {
if (empty_etc) {
r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0);
if (r < 0)
- log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
+ log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
diff --git a/src/core/mount.c b/src/core/mount.c
index 9b44357e90..2ad4ad4f42 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -335,7 +335,7 @@ static int mount_add_device_links(Mount *m) {
if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
device_wants_mount = true;
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount);
+ r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
if (r < 0)
return r;
diff --git a/src/core/socket.c b/src/core/socket.c
index 687675b24e..860a1e3051 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -289,7 +289,7 @@ static int socket_add_device_link(Socket *s) {
return 0;
t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device);
- return unit_add_node_link(UNIT(s), t, false);
+ return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO);
}
static int socket_add_default_dependencies(Socket *s) {
diff --git a/src/core/swap.c b/src/core/swap.c
index b6e4372fc0..5568898bd7 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -202,7 +202,7 @@ static int swap_add_device_links(Swap *s) {
return 0;
if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM);
+ return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in
index 141f42dbcf..9e18a39a67 100644
--- a/src/core/triggers.systemd.in
+++ b/src/core/triggers.systemd.in
@@ -19,8 +19,46 @@
# The contents of this are an example to be copied into systemd.spec.
-%transfiletriggerin -- @systemunitdir@ /etc/systemd/system
-systemctl daemon-reload &>/dev/null || :
+%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
+-- This script will run after any package is initially installed or
+-- upgraded. We care about the case where a package is initially
+-- installed, because other cases are covered by the *un scriptlets,
+-- so sometimes we will reload needlessly.
-%transfiletriggerun -- @systemunitdir@ /etc/systemd/system
-systemctl daemon-reload &>/dev/null || :
+pid = posix.fork()
+if pid == 0 then
+ assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
+elseif pid > 0 then
+ posix.wait(pid)
+end
+
+%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system
+-- On removal, we need to run daemon-reload after any units have been
+-- removed. %transfiletriggerpostun would be ideal, but it does not get
+-- executed for some reason.
+-- On upgrade, we need to run daemon-reload after any new unit files
+-- have been installed, but before %postun scripts in packages get
+-- executed. %transfiletriggerun gets the right list of files
+-- but it is invoked too early (before changes happen).
+-- %filetriggerpostun happens at the right time, but it fires for
+-- every package.
+-- To execute the reload at the right time, we create a state
+-- file in %transfiletriggerun and execute the daemon-reload in
+-- the first %filetriggerpostun.
+
+posix.mkdir("%{_localstatedir}/lib")
+posix.mkdir("%{_localstatedir}/lib/rpm-state")
+posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd")
+io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w")
+
+%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
+if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
+ posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload")
+ posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd")
+ pid = posix.fork()
+ if pid == 0 then
+ assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
+ elseif pid > 0 then
+ posix.wait(pid)
+ end
+end
diff --git a/src/core/unit.c b/src/core/unit.c
index 0a02e38aa8..e6e67d27c8 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2840,7 +2840,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
}
}
-int unit_add_node_link(Unit *u, const char *what, bool wants) {
+int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
Unit *device;
_cleanup_free_ char *e = NULL;
int r;
@@ -2867,7 +2867,9 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
if (r < 0)
return r;
- r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == MANAGER_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true);
+ r = unit_add_two_dependencies(u, UNIT_AFTER,
+ u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS,
+ device, true);
if (r < 0)
return r;
diff --git a/src/core/unit.h b/src/core/unit.h
index 1681bbf53b..3eb3484fb7 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -528,7 +528,7 @@ int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *v
int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-int unit_add_node_link(Unit *u, const char *what, bool wants);
+int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
int unit_coldplug(Unit *u);
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index f7c8d11ace..87b8b77f22 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -248,6 +248,7 @@ static int add_mount(
assert(what);
assert(where);
assert(opts);
+ assert(post);
assert(source);
if (streq_ptr(fstype, "autofs"))
@@ -297,7 +298,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (post && !noauto && !nofail && !automount)
+ if (!noauto && !nofail && !automount)
fprintf(f, "Before=%s\n", post);
if (!automount && opts) {
@@ -337,7 +338,7 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
- if (!noauto && post) {
+ if (!noauto) {
lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
if (!lnk)
return log_oom();
@@ -368,10 +369,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (post)
- fprintf(f,
- "Before=%s\n",
- post);
+ fprintf(f, "Before=%s\n", post);
if (opts) {
r = write_requires_after(f, opts);
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index fb800782fb..07a0f1bf41 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -239,14 +239,14 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
assert(s);
assert(p);
- if (isempty(p))
- return 0;
-
priority = s->priority;
if (s->level_prefix)
syslog_parse_priority(&p, &priority, false);
+ if (isempty(p))
+ return 0;
+
if (s->forward_to_syslog || s->server->forward_to_syslog)
server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
@@ -286,10 +286,12 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
static int stdout_stream_line(StdoutStream *s, char *p) {
int r;
+ char *orig;
assert(s);
assert(p);
+ orig = p;
p = strstrip(p);
switch (s->state) {
@@ -378,7 +380,7 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
return 0;
case STDOUT_STREAM_RUNNING:
- return stdout_stream_log(s, p);
+ return stdout_stream_log(s, orig);
}
assert_not_reached("Unknown stream state");
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index a5daaa543a..7038212bcf 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -47,8 +47,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
const void *option, void *userdata);
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *userdata);
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, size_t optlen,
diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index a6c410ba91..1de7f3639c 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -24,6 +24,9 @@
#include <stdio.h>
#include <string.h>
+#include "alloc-util.h"
+#include "utf8.h"
+
#include "dhcp-internal.h"
static int option_append(uint8_t options[], size_t size, size_t *offset,
@@ -139,72 +142,84 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
- uint8_t *message_type, dhcp_option_cb_t cb,
+ uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
void *userdata) {
uint8_t code, len;
+ const uint8_t *option;
size_t offset = 0;
while (offset < buflen) {
- switch (options[offset]) {
- case DHCP_OPTION_PAD:
- offset++;
+ code = options[offset ++];
- break;
+ switch (code) {
+ case DHCP_OPTION_PAD:
+ continue;
case DHCP_OPTION_END:
return 0;
+ }
- case DHCP_OPTION_MESSAGE_TYPE:
- if (buflen < offset + 3)
- return -ENOBUFS;
+ if (buflen < offset + 1)
+ return -ENOBUFS;
+
+ len = options[offset ++];
- len = options[++offset];
+ if (buflen < offset + len)
+ return -EINVAL;
+
+ option = &options[offset];
+
+ switch (code) {
+ case DHCP_OPTION_MESSAGE_TYPE:
if (len != 1)
return -EINVAL;
if (message_type)
- *message_type = options[++offset];
- else
- offset++;
-
- offset++;
+ *message_type = *option;
break;
- case DHCP_OPTION_OVERLOAD:
- if (buflen < offset + 3)
- return -ENOBUFS;
-
- len = options[++offset];
- if (len != 1)
+ case DHCP_OPTION_ERROR_MESSAGE:
+ if (len == 0)
return -EINVAL;
- if (overload)
- *overload = options[++offset];
- else
- offset++;
+ if (error_message) {
+ _cleanup_free_ char *string = NULL;
- offset++;
+ /* Accept a trailing NUL byte */
+ if (memchr(option, 0, len - 1))
+ return -EINVAL;
- break;
+ string = strndup((const char *) option, len);
+ if (!string)
+ return -ENOMEM;
- default:
- if (buflen < offset + 3)
- return -ENOBUFS;
+ if (!ascii_is_valid(string))
+ return -EINVAL;
- code = options[offset];
- len = options[++offset];
+ free(*error_message);
+ *error_message = string;
+ string = NULL;
+ }
- if (buflen < ++offset + len)
+ break;
+ case DHCP_OPTION_OVERLOAD:
+ if (len != 1)
return -EINVAL;
- if (cb)
- cb(code, len, &options[offset], userdata);
+ if (overload)
+ *overload = *option;
- offset += len;
+ break;
+
+ default:
+ if (cb)
+ cb(code, len, option, userdata);
break;
}
+
+ offset += len;
}
if (offset < buflen)
@@ -213,8 +228,8 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *userdata) {
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
+ _cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;
int r;
@@ -227,27 +242,29 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
len -= sizeof(DHCPMessage);
- r = parse_options(message->options, len, &overload, &message_type,
- cb, userdata);
+ r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
if (overload & DHCP_OVERLOAD_FILE) {
- r = parse_options(message->file, sizeof(message->file),
- NULL, &message_type, cb, userdata);
+ r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
if (overload & DHCP_OVERLOAD_SNAME) {
- r = parse_options(message->sname, sizeof(message->sname),
- NULL, &message_type, cb, userdata);
+ r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
- if (message_type)
- return message_type;
+ if (message_type == 0)
+ return -ENOMSG;
+
+ if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) {
+ *_error_message = error_message;
+ error_message = NULL;
+ }
- return -ENOMSG;
+ return message_type;
}
diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h
index 05bb5ae493..f65529a00e 100644
--- a/src/libsystemd-network/dhcp-protocol.h
+++ b/src/libsystemd-network/dhcp-protocol.h
@@ -132,6 +132,7 @@ enum {
DHCP_OPTION_MESSAGE_TYPE = 53,
DHCP_OPTION_SERVER_IDENTIFIER = 54,
DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
+ DHCP_OPTION_ERROR_MESSAGE = 56,
DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
DHCP_OPTION_RENEWAL_T1_TIME = 58,
DHCP_OPTION_REBINDING_T2_TIME = 59,
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index 91308bf6c3..acad9d7d6a 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -47,17 +47,15 @@ int icmp6_bind_router_solicitation(int index) {
.ipv6mr_interface = index,
};
_cleanup_close_ int s = -1;
- int r, zero = 0, hops = 255;
+ int r, zero = 0, one = 1, hops = 255;
- s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
- IPPROTO_ICMPV6);
+ s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (s < 0)
return -errno;
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
- r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
- sizeof(filter));
+ r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter));
if (r < 0)
return -errno;
@@ -65,23 +63,23 @@ int icmp6_bind_router_solicitation(int index) {
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
Empirical experiments indicates otherwise and therefore an
IPV6_MULTICAST_IF socket option is used here instead */
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
- sizeof(index));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
- sizeof(zero));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
- sizeof(hops));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
if (r < 0)
return -errno;
- r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq));
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (r < 0)
+ return -errno;
+
+ r = setsockopt(s, SOL_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
if (r < 0)
return -errno;
@@ -101,25 +99,25 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
struct ether_addr rs_opt_mac;
} _packed_ rs = {
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
+ .rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR,
+ .rs_opt.nd_opt_len = 1,
};
- struct iovec iov[1] = {
- { &rs, },
+ struct iovec iov = {
+ .iov_base = &rs,
+ .iov_len = sizeof(rs),
};
struct msghdr msg = {
.msg_name = &dst,
.msg_namelen = sizeof(dst),
- .msg_iov = iov,
+ .msg_iov = &iov,
.msg_iovlen = 1,
};
int r;
- if (ether_addr) {
- memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
- rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
- rs.rs_opt.nd_opt_len = 1;
- iov[0].iov_len = sizeof(rs);
- } else
- iov[0].iov_len = sizeof(rs.rs);
+ assert(s >= 0);
+ assert(ether_addr);
+
+ rs.rs_opt_mac = *ether_addr;
r = sendmsg(s, &msg, 0);
if (r < 0)
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index f689c59a1a..7deb00af9c 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1082,7 +1082,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return r;
}
- r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
+ r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
if (r != DHCP_OFFER) {
log_dhcp_client(client, "received message was not an OFFER, ignoring");
return -ENOMSG;
@@ -1121,7 +1121,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
size_t len) {
int r;
- r = dhcp_option_parse(force, len, NULL, NULL);
+ r = dhcp_option_parse(force, len, NULL, NULL, NULL);
if (r != DHCP_FORCERENEW)
return -ENOMSG;
@@ -1133,6 +1133,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
size_t len) {
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
+ _cleanup_free_ char *error_message = NULL;
int r;
r = dhcp_lease_new(&lease);
@@ -1147,9 +1148,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
return r;
}
- r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
+ r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
if (r == DHCP_NAK) {
- log_dhcp_client(client, "NAK");
+ log_dhcp_client(client, "NAK: %s", strna(error_message));
return -EADDRNOTAVAIL;
}
@@ -1513,9 +1514,8 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0)
- return r;
-
- if (buflen < 0)
+ return -errno;
+ else if (buflen < 0)
/* this can't be right */
return -EIO;
@@ -1525,26 +1525,28 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
len = read(fd, message, buflen);
if (len < 0) {
- log_dhcp_client(client, "could not receive message from UDP "
- "socket: %m");
- return 0;
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp_client(client, "Could not receive message from UDP socket: %m");
+ return -errno;
} else if ((size_t)len < sizeof(DHCPMessage)) {
- log_dhcp_client(client, "too small to be a DHCP message: ignoring");
+ log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
return 0;
}
if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
- log_dhcp_client(client, "not a DHCP message: ignoring");
+ log_dhcp_client(client, "Not a DHCP message: ignoring");
return 0;
}
if (message->op != BOOTREPLY) {
- log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
+ log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
return 0;
}
if (message->htype != client->arp_type) {
- log_dhcp_client(client, "packet type does not match client type");
+ log_dhcp_client(client, "Packet type does not match client type");
return 0;
}
@@ -1558,13 +1560,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
}
if (message->hlen != expected_hlen) {
- log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
+ log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
return 0;
}
if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
- log_dhcp_client(client, "received chaddr does not match "
- "expected: ignoring");
+ log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
return 0;
}
@@ -1572,8 +1573,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
be32toh(message->xid) != client->xid) {
/* in BOUND state, we may receive FORCERENEW with xid set by server,
so ignore the xid in this case */
- log_dhcp_client(client, "received xid (%u) does not match "
- "expected (%u): ignoring",
+ log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
be32toh(message->xid), client->xid);
return 0;
}
@@ -1602,9 +1602,8 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0)
- return r;
-
- if (buflen < 0)
+ return -errno;
+ else if (buflen < 0)
/* this can't be right */
return -EIO;
@@ -1617,9 +1616,12 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- log_dhcp_client(client, "could not receive message from raw "
- "socket: %m");
- return 0;
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp_client(client, "Could not receive message from raw socket: %m");
+
+ return -errno;
} else if ((size_t)len < sizeof(DHCPPacket))
return 0;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 8befedc500..fccdc01bc3 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -661,7 +661,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
break;
default:
- log_debug("Ignoring option DHCP option %i while parsing.", code);
+ log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
break;
}
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 277c88e2b9..587ff936ba 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -699,6 +699,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length) {
_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
+ _cleanup_free_ char *error_message = NULL;
DHCPLease *existing_lease;
int type, r;
@@ -714,7 +715,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (!req)
return -ENOMEM;
- type = dhcp_option_parse(message, length, parse_request, req);
+ type = dhcp_option_parse(message, length, parse_request, req, &error_message);
if (type < 0)
return 0;
@@ -784,8 +785,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
break;
}
case DHCP_DECLINE:
- log_dhcp_server(server, "DECLINE (0x%x)",
- be32toh(req->message->xid));
+ log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
/* TODO: make sure we don't offer this address again */
@@ -963,10 +963,10 @@ static int server_receive_message(sd_event_source *s, int fd,
if (ioctl(fd, FIONREAD, &buflen) < 0)
return -errno;
- if (buflen < 0)
+ else if (buflen < 0)
return -EIO;
- message = malloc0(buflen);
+ message = malloc(buflen);
if (!message)
return -ENOMEM;
@@ -974,9 +974,12 @@ static int server_receive_message(sd_event_source *s, int fd,
iov.iov_len = buflen;
len = recvmsg(fd, &msg, 0);
- if (len < buflen)
- return 0;
- else if ((size_t)len < sizeof(DHCPMessage))
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return -errno;
+ } else if ((size_t)len < sizeof(DHCPMessage))
return 0;
CMSG_FOREACH(cmsg, &msg) {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 801331d270..36d909a4c5 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -895,7 +895,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
- _cleanup_free_ DHCP6Message *message;
+ _cleanup_free_ DHCP6Message *message = NULL;
int r, buflen, len;
assert(s);
@@ -903,18 +903,26 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
assert(client->event);
r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0 || buflen <= 0)
- buflen = DHCP6_MIN_OPTIONS_SIZE;
+ if (r < 0)
+ return -errno;
+ else if (buflen < 0)
+ /* This really should not happen */
+ return -EIO;
- message = malloc0(buflen);
+ message = malloc(buflen);
if (!message)
return -ENOMEM;
len = read(fd, message, buflen);
- if ((size_t)len < sizeof(DHCP6Message)) {
- log_dhcp6_client(client, "could not receive message from UDP socket: %m");
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
+
+ return -errno;
+ } else if ((size_t)len < sizeof(DHCP6Message))
return 0;
- }
switch(message->type) {
case DHCP6_SOLICIT:
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index 713438f212..f2bce3b99f 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -418,8 +418,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
return 0;
}
-static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
- ssize_t len) {
+static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) {
void *opt;
struct nd_opt_hdr *opt_hdr;
@@ -482,36 +481,79 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_free_ struct nd_router_advert *ra = NULL;
sd_ndisc *nd = userdata;
- int r, buflen = 0, pref, stateful;
- union sockaddr_union router = {};
- socklen_t router_len = sizeof(router);
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_LEN(sizeof(int))];
+ } control = {};
+ struct iovec iov = {};
+ union sockaddr_union sa = {};
+ struct msghdr msg = {
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
struct in6_addr *gw;
unsigned lifetime;
ssize_t len;
+ int r, pref, stateful, buflen = 0;
assert(s);
assert(nd);
assert(nd->event);
r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0 || buflen <= 0)
- buflen = ICMP6_RECV_SIZE;
+ if (r < 0)
+ return -errno;
+ else if (buflen < 0)
+ /* This really should not happen */
+ return -EIO;
+
+ iov.iov_len = buflen;
- ra = malloc(buflen);
+ ra = malloc(iov.iov_len);
if (!ra)
return -ENOMEM;
- len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len);
+ iov.iov_base = ra;
+
+ len = recvmsg(fd, &msg, 0);
if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
+ return -errno;
+ } else if ((size_t)len < sizeof(struct nd_router_advert)) {
return 0;
- } else if (router_len == 0)
+ } else if (msg.msg_namelen == 0)
gw = NULL; /* only happens when running the test-suite over a socketpair */
- else if (router_len != sizeof(router.in6)) {
- log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len);
+ else if (msg.msg_namelen != sizeof(sa.in6)) {
+ log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen);
return 0;
} else
- gw = &router.in6.sin6_addr;
+ gw = &sa.in6.sin6_addr;
+
+ assert(!(msg.msg_flags & MSG_CTRUNC));
+ assert(!(msg.msg_flags & MSG_TRUNC));
+
+ CMSG_FOREACH(cmsg, &msg) {
+ if (cmsg->cmsg_level == SOL_IPV6 &&
+ cmsg->cmsg_type == IPV6_HOPLIMIT &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ int hops = *(int*)CMSG_DATA(cmsg);
+
+ if (hops != 255) {
+ log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops);
+ return 0;
+ }
+
+ break;
+ }
+ }
if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) {
_cleanup_free_ char *addr = NULL;
@@ -566,8 +608,6 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
sd_ndisc *nd = userdata;
uint64_t time_now, next_timeout;
- struct ether_addr unset = { };
- struct ether_addr *addr = NULL;
int r;
assert(s);
@@ -581,10 +621,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
} else {
- if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
- addr = &nd->mac_addr;
-
- r = icmp6_send_router_solicitation(nd->fd, addr);
+ r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
if (r < 0)
log_ndisc(nd, "Error sending Router Solicitation");
else {
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 1200a7c251..4478147a83 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -223,7 +223,7 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const voi
static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
int res;
- res = dhcp_option_parse(dhcp, size, check_options, NULL);
+ res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
assert_se(res == DHCP_DISCOVER);
if (verbose)
@@ -390,7 +390,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
uint8_t *msg_bytes = (uint8_t *)request;
int res;
- res = dhcp_option_parse(request, size, check_options, NULL);
+ res = dhcp_option_parse(request, size, check_options, NULL, NULL);
assert_se(res == DHCP_REQUEST);
assert_se(xid == request->xid);
@@ -420,7 +420,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
uint8_t *msg_bytes = (uint8_t *)discover;
int res;
- res = dhcp_option_parse(discover, size, check_options, NULL);
+ res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
assert_se(res == DHCP_DISCOVER);
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 3607df63af..75d22c4df3 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -75,9 +75,8 @@ static const char *dhcp_type(int type) {
static void test_invalid_buffer_length(void) {
DHCPMessage message;
- assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
- assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL)
- == -EINVAL);
+ assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
+ assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
}
static void test_message_init(void) {
@@ -101,7 +100,7 @@ static void test_message_init(void) {
assert_se(magic[2] == 83);
assert_se(magic[3] == 99);
- assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0);
+ assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
}
static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
@@ -264,19 +263,12 @@ static void test_options(struct option_desc *desc) {
buflen = sizeof(DHCPMessage) + optlen;
if (!desc) {
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- NULL)) == -ENOMSG);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
} else if (desc->success) {
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) >= 0);
- assert_se(desc->pos == -1 && desc->filepos == -1 &&
- desc->snamepos == -1);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
+ assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
} else
- assert_se((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) < 0);
+ assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
if (verbose)
printf("DHCP type %s\n", dhcp_type(res));
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 38281045b8..8775808da4 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1443,14 +1443,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return 0;
- } else if (streq(field, "RandomSec")) {
+ } else if (streq(field, "RandomizedDelaySec")) {
usec_t t;
r = parse_sec(eq, &t);
if (r < 0)
- return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq);
+ return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq);
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec");
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec");
if (r < 0)
return bus_log_create_error(r);
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 854f60be80..0b3630f77c 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -695,6 +695,27 @@ static void test_config_parse_rlimit(void) {
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ /* Invalid values don't change rl */
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
+
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh
index 6ad2f3402b..6963d8c88d 100755
--- a/test/TEST-01-BASIC/test.sh
+++ b/test/TEST-01-BASIC/test.sh
@@ -58,7 +58,7 @@ Type=oneshot
EOF
setup_testsuite
- )
+ ) || return 1
setup_nspawn_root
# mask some services that we do not want to run in these tests
diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh
index 8ed39b118a..dada99df59 100755
--- a/test/TEST-02-CRYPTSETUP/test.sh
+++ b/test/TEST-02-CRYPTSETUP/test.sh
@@ -76,7 +76,7 @@ EOF
cat >>$initdir/etc/fstab <<EOF
/dev/mapper/varcrypt /var ext3 defaults 0 1
EOF
- )
+ ) || return 1
setup_nspawn_root
ddebug "umount $TESTDIR/root/var"
diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh
index 41e02e2c8a..83393435f0 100755
--- a/test/TEST-03-JOBS/test.sh
+++ b/test/TEST-03-JOBS/test.sh
@@ -63,7 +63,7 @@ EOF
cp test-jobs.sh $initdir/
setup_testsuite
- )
+ ) || return 1
setup_nspawn_root
ddebug "umount $TESTDIR/root"
diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-04-JOURNAL/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh
new file mode 100755
index 0000000000..1ee39df432
--- /dev/null
+++ b/test/TEST-04-JOURNAL/test-journal.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -x
+set -e
+set -o pipefail
+
+# Test stdout stream
+
+# Skip empty lines
+ID=$(journalctl --new-id128 | sed -n 2p)
+>/expected
+printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+>/expected
+printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Remove trailing spaces
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "Trailing spaces\n">/expected
+printf $'<5>Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "Trailing spaces\n">/expected
+printf $'Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Don't remove leading spaces
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf $' \t Leading spaces\n'>/expected
+printf $'<5> \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf $' \t Leading spaces\n'>/expected
+printf $' \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+touch /testok
+exit 0
diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh
new file mode 100755
index 0000000000..6c5b5cf34e
--- /dev/null
+++ b/test/TEST-04-JOURNAL/test.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="Journal-related tests"
+
+. $TEST_BASE_DIR/test-functions
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ if check_nspawn; then
+ run_nspawn
+ check_result_nspawn || return 1
+ else
+ dwarn "can't run systemd-nspawn, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-journal.sh
+Type=oneshot
+EOF
+
+ cp test-journal.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/test-functions b/test/test-functions
index 49bd35f688..9288200717 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -13,7 +13,7 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
ROOTLIBDIR=/usr/lib/systemd
fi
-BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe"
+BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname"
function find_qemu_bin() {