summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/fs-util.c56
-rw-r--r--src/basic/fs-util.h1
-rw-r--r--src/basic/hostname-util.c56
-rw-r--r--src/basic/hostname-util.h1
-rw-r--r--src/basic/meson.build1
-rw-r--r--src/basic/missing.h1
-rw-r--r--src/basic/missing_drm.h10
-rw-r--r--src/basic/mountpoint-util.c2
-rw-r--r--src/core/device.c48
-rw-r--r--src/core/mount.c348
-rw-r--r--src/core/mount.h13
-rw-r--r--src/core/service.c4
-rw-r--r--src/core/swap.c157
-rw-r--r--src/journal-remote/journal-gatewayd.c143
-rw-r--r--src/journal-remote/journal-remote-main.c87
-rw-r--r--src/journal-remote/journal-remote.c3
-rw-r--r--src/journal-remote/journal-remote.h2
-rw-r--r--src/journal-remote/journal-upload.c57
-rw-r--r--src/journal-remote/microhttpd-util.h2
-rw-r--r--src/libsystemd-network/ndisc-router.c2
-rw-r--r--src/libsystemd-network/network-internal.c30
-rw-r--r--src/libsystemd-network/network-internal.h1
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c27
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c2
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c8
-rw-r--r--src/libsystemd/meson.build4
-rw-r--r--src/login/logind-session-device.c4
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-dhcp4.c2
-rw-r--r--src/network/networkd-dhcp6.c8
-rw-r--r--src/network/networkd-link.c92
-rw-r--r--src/network/networkd-link.h9
-rw-r--r--src/network/networkd-neighbor.c237
-rw-r--r--src/network/networkd-neighbor.h37
-rw-r--r--src/network/networkd-network-gperf.gperf4
-rw-r--r--src/network/networkd-network.c40
-rw-r--r--src/network/networkd-network.h7
-rw-r--r--src/network/networkd.c86
-rw-r--r--src/network/wait-online/wait-online.c49
-rw-r--r--src/resolve/resolved-bus.c8
-rw-r--r--src/resolve/resolved-dns-dnssec.c8
-rw-r--r--src/resolve/resolved-dns-packet.c2
-rw-r--r--src/resolve/resolved-dns-rr.c6
-rw-r--r--src/resolve/resolved-dns-search-domain.c2
-rw-r--r--src/resolve/resolved-dns-server.c38
-rw-r--r--src/resolve/resolved-dns-server.h4
-rw-r--r--src/resolve/resolved-dns-stream.c115
-rw-r--r--src/resolve/resolved-dns-stream.h7
-rw-r--r--src/resolve/resolved-dns-stub.c12
-rw-r--r--src/resolve/resolved-dns-transaction.c63
-rw-r--r--src/resolve/resolved-dnssd.c4
-rw-r--r--src/resolve/resolved-etc-hosts.c41
-rw-r--r--src/resolve/resolved-llmnr.c13
-rw-r--r--src/resolve/resolved-manager.c10
-rw-r--r--src/resolve/resolved.c71
-rw-r--r--src/resolve/test-resolved-etc-hosts.c133
-rw-r--r--src/shared/daemon-util.h22
-rw-r--r--src/shared/dns-domain.c95
-rw-r--r--src/shared/dns-domain.h28
-rw-r--r--src/shared/meson.build1
-rw-r--r--src/systemctl/systemctl.c11
-rw-r--r--src/systemd/sd-dhcp-client.h3
-rw-r--r--src/test/test-dns-domain.c175
-rw-r--r--src/test/test-fs-util.c4
-rw-r--r--src/test/test-hostname-util.c8
-rwxr-xr-xsrc/test/test-systemd-tmpfiles.py10
-rw-r--r--src/timesync/timesyncd.c66
-rw-r--r--src/tmpfiles/tmpfiles.c19
68 files changed, 1661 insertions, 961 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index f70878fb8e..06bae8decf 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -14,6 +14,7 @@
#include "dirent-util.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@@ -663,15 +664,42 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r;
}
-static bool safe_transition(const struct stat *a, const struct stat *b) {
+static bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
* making us believe we read something safe even though it isn't safe in the specific context we open it in. */
if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
- return true;
+ return false;
- return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */
+ return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
+}
+
+static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
+ _cleanup_free_ char *n1 = NULL, *n2 = NULL;
+
+ if (!FLAGS_SET(flags, CHASE_WARN))
+ return -ENOLINK;
+
+ (void) fd_get_path(a, &n1);
+ (void) fd_get_path(b, &n2);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
+ "Detected unsafe path transition %s %s %s during canonicalization of %s.",
+ n1, special_glyph(ARROW), n2, path);
+}
+
+static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
+ _cleanup_free_ char *n1 = NULL;
+
+ if (!FLAGS_SET(flags, CHASE_WARN))
+ return -EREMOTE;
+
+ (void) fd_get_path(fd, &n1);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
+ "Detected autofs mount point %s during canonicalization of %s.",
+ n1, path);
}
int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
@@ -734,6 +762,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* path is fully normalized, and == 0 for each normalization step. This may be combined with
* CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
*
+ * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
+ * unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
+ * CHASE_WARN is also set a warning describing the unsafe transition is emitted.
+ *
+ * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, the path normalization is
+ * aborted and -EREMOTE is returned. If CHASE_WARN is also set a warning showing the path of the mount point
+ * is emitted.
+ *
* */
/* A root directory of "/" or "" is identical to none */
@@ -848,8 +884,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(fd_parent, &st) < 0)
return -errno;
- if (!safe_transition(&previous_stat, &st))
- return -EPERM;
+ if (unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(fd, fd_parent, path, flags);
previous_stat = st;
}
@@ -889,14 +925,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_SAFE) &&
- !safe_transition(&previous_stat, &st))
- return -EPERM;
+ unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(fd, child, path, flags);
previous_stat = st;
if ((flags & CHASE_NO_AUTOFS) &&
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
- return -EREMOTE;
+ return log_autofs_mount_point(child, path, flags);
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
char *joined;
@@ -928,8 +964,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(fd, &st) < 0)
return -errno;
- if (!safe_transition(&previous_stat, &st))
- return -EPERM;
+ if (unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(child, fd, path, flags);
previous_stat = st;
}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 955b146a6a..7ad030be5d 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -74,6 +74,7 @@ enum {
CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */
CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
+ CHASE_WARN = 1 << 8, /* Emit an appropriate warning when an error is encountered */
};
/* How many iterations to execute before returning -ELOOP */
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index 3a3479910d..5bfa028b39 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -69,12 +69,12 @@ int gethostname_strict(char **ret) {
return 0;
}
-static bool hostname_valid_char(char c) {
+bool valid_ldh_char(char c) {
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
- IN_SET(c, '-', '_', '.');
+ c == '-';
}
/**
@@ -90,7 +90,7 @@ static bool hostname_valid_char(char c) {
bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
unsigned n_dots = 0;
const char *p;
- bool dot;
+ bool dot, hyphen;
if (isempty(s))
return false;
@@ -100,23 +100,34 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
* sequence. Also ensures that the length stays below
* HOST_NAME_MAX. */
- for (p = s, dot = true; *p; p++) {
+ for (p = s, dot = hyphen = true; *p; p++)
if (*p == '.') {
- if (dot)
+ if (dot || hyphen)
return false;
dot = true;
+ hyphen = false;
n_dots++;
+
+ } else if (*p == '-') {
+ if (dot)
+ return false;
+
+ dot = false;
+ hyphen = true;
+
} else {
- if (!hostname_valid_char(*p))
+ if (!valid_ldh_char(*p))
return false;
dot = false;
+ hyphen = false;
}
- }
if (dot && (n_dots < 2 || !allow_trailing_dot))
return false;
+ if (hyphen)
+ return false;
if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
* Linux, but DNS allows domain names
@@ -128,29 +139,38 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
char* hostname_cleanup(char *s) {
char *p, *d;
- bool dot;
+ bool dot, hyphen;
assert(s);
- strshorten(s, HOST_NAME_MAX);
-
- for (p = s, d = s, dot = true; *p; p++) {
+ for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
if (*p == '.') {
- if (dot)
+ if (dot || hyphen)
continue;
*(d++) = '.';
dot = true;
- } else if (hostname_valid_char(*p)) {
+ hyphen = false;
+
+ } else if (*p == '-') {
+ if (dot)
+ continue;
+
+ *(d++) = '-';
+ dot = false;
+ hyphen = true;
+
+ } else if (valid_ldh_char(*p)) {
*(d++) = *p;
dot = false;
+ hyphen = false;
}
- }
- if (dot && d > s)
- d[-1] = 0;
- else
- *d = 0;
+ if (d > s && IN_SET(d[-1], '-', '.'))
+ /* The dot can occur at most once, but we might have multiple
+ * hyphens, hence the loop */
+ d--;
+ *d = 0;
return s;
}
diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h
index 749481723d..7ba386a0fd 100644
--- a/src/basic/hostname-util.h
+++ b/src/basic/hostname-util.h
@@ -11,6 +11,7 @@ bool hostname_is_set(void);
char* gethostname_malloc(void);
int gethostname_strict(char **ret);
+bool valid_ldh_char(char c) _const_;
bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
char* hostname_cleanup(char *s);
diff --git a/src/basic/meson.build b/src/basic/meson.build
index fb6fa2fcfa..23b5e75bd8 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -96,6 +96,7 @@ basic_sources = files('''
missing_btrfs.h
missing_btrfs_tree.h
missing_capability.h
+ missing_drm.h
missing_ethtool.h
missing_fcntl.h
missing_fib_rules.h
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 7e14e0a2a4..5067c8fd00 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -6,6 +6,7 @@
#include "missing_audit.h"
#include "missing_btrfs_tree.h"
#include "missing_capability.h"
+#include "missing_drm.h"
#include "missing_fcntl.h"
#include "missing_fs.h"
#include "missing_input.h"
diff --git a/src/basic/missing_drm.h b/src/basic/missing_drm.h
new file mode 100644
index 0000000000..a64f74efda
--- /dev/null
+++ b/src/basic/missing_drm.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#ifndef DRM_IOCTL_SET_MASTER
+#define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
+#endif
+
+#ifndef DRM_IOCTL_DROP_MASTER
+#define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
+#endif
diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c
index 0a9f479e42..1e946a0bb6 100644
--- a/src/basic/mountpoint-util.c
+++ b/src/basic/mountpoint-util.c
@@ -98,7 +98,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
if ((flags & AT_EMPTY_PATH) && isempty(filename))
xsprintf(path, "/proc/self/fdinfo/%i", fd);
else {
- subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
+ subfd = openat(fd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_FOLLOW ? 0 : O_NOFOLLOW));
if (subfd < 0)
return -errno;
diff --git a/src/core/device.c b/src/core/device.c
index f8b6961d3c..960f403718 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -112,6 +112,24 @@ static void device_done(Unit *u) {
d->wants_property = strv_free(d->wants_property);
}
+static int device_load(Unit *u) {
+ int r;
+
+ r = unit_load_fragment_and_dropin_optional(u);
+ if (r < 0)
+ return r;
+
+ if (!u->description) {
+ /* Generate a description based on the path, to be used until the
+ device is initialized properly */
+ r = unit_name_to_path(u->id, &u->description);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to unescape name: %m");
+ }
+
+ return 0;
+}
+
static void device_set_state(Device *d, DeviceState state) {
DeviceState old_state;
assert(d);
@@ -305,32 +323,32 @@ _pure_ static const char *device_sub_state_to_string(Unit *u) {
}
static int device_update_description(Unit *u, sd_device *dev, const char *path) {
- const char *model, *label;
+ _cleanup_free_ char *j = NULL;
+ const char *model, *label, *desc;
int r;
assert(u);
- assert(dev);
assert(path);
- if (sd_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE", &model) >= 0 ||
- sd_device_get_property_value(dev, "ID_MODEL", &model) >= 0) {
+ desc = path;
+
+ if (dev &&
+ (sd_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE", &model) >= 0 ||
+ sd_device_get_property_value(dev, "ID_MODEL", &model) >= 0)) {
+ desc = model;
/* Try to concatenate the device model string with a label, if there is one */
if (sd_device_get_property_value(dev, "ID_FS_LABEL", &label) >= 0 ||
sd_device_get_property_value(dev, "ID_PART_ENTRY_NAME", &label) >= 0 ||
sd_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER", &label) >= 0) {
- _cleanup_free_ char *j;
-
- j = strjoin(model, " ", label);
+ desc = j = strjoin(model, " ", label);
if (!j)
return log_oom();
+ }
+ }
- r = unit_set_description(u, j);
- } else
- r = unit_set_description(u, model);
- } else
- r = unit_set_description(u, path);
+ r = unit_set_description(u, desc);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set device description: %m");
@@ -530,13 +548,13 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
goto fail;
}
- (void) device_update_description(u, dev, path);
-
/* The additional systemd udev properties we only interpret for the main object */
if (main)
(void) device_add_udev_wants(u, dev);
}
+ (void) device_update_description(u, dev, path);
+
/* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
* before the device appears on its radar. In this case the device unit is partially initialized and includes
* the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
@@ -1041,7 +1059,7 @@ const UnitVTable device_vtable = {
.init = device_init,
.done = device_done,
- .load = unit_load_fragment_and_dropin_optional,
+ .load = device_load,
.coldplug = device_coldplug,
.catchup = device_catchup,
diff --git a/src/core/mount.c b/src/core/mount.c
index afdbaa1d9d..ead9bc1f44 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -68,22 +68,18 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
MOUNT_UNMOUNTING_SIGKILL);
}
-static bool mount_needs_network(const char *options, const char *fstype) {
- if (fstab_test_option(options, "_netdev\0"))
+static bool mount_is_network(const MountParameters *p) {
+ assert(p);
+
+ if (fstab_test_option(p->options, "_netdev\0"))
return true;
- if (fstype && fstype_is_network(fstype))
+ if (p->fstype && fstype_is_network(p->fstype))
return true;
return false;
}
-static bool mount_is_network(const MountParameters *p) {
- assert(p);
-
- return mount_needs_network(p->options, p->fstype);
-}
-
static bool mount_is_loop(const MountParameters *p) {
assert(p);
@@ -129,11 +125,11 @@ static bool mount_is_bound_to_device(const Mount *m) {
return fstab_test_option(p->options, "x-systemd.device-bound\0");
}
-static bool needs_quota(const MountParameters *p) {
+static bool mount_needs_quota(const MountParameters *p) {
assert(p);
- /* Quotas are not enabled on network filesystems,
- * but we want them, for example, on storage connected via iscsi */
+ /* Quotas are not enabled on network filesystems, but we want them, for example, on storage connected via
+ * iscsi. We hence don't use mount_is_network() here, as that would also return true for _netdev devices. */
if (p->fstype && fstype_is_network(p->fstype))
return false;
@@ -211,11 +207,9 @@ static void mount_unwatch_control_pid(Mount *m) {
static void mount_parameters_done(MountParameters *p) {
assert(p);
- free(p->what);
- free(p->options);
- free(p->fstype);
-
- p->what = p->options = p->fstype = NULL;
+ p->what = mfree(p->what);
+ p->options = mfree(p->options);
+ p->fstype = mfree(p->fstype);
}
static void mount_done(Unit *u) {
@@ -318,7 +312,7 @@ static int mount_add_mount_dependencies(Mount *m) {
}
static int mount_add_device_dependencies(Mount *m) {
- bool device_wants_mount = false;
+ bool device_wants_mount;
UnitDependencyMask mask;
MountParameters *p;
UnitDependency dep;
@@ -348,8 +342,8 @@ static int mount_add_device_dependencies(Mount *m) {
if (path_equal(m->where, "/"))
return 0;
- if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
- device_wants_mount = true;
+ device_wants_mount =
+ mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager);
/* Mount units from /proc/self/mountinfo are not bound to devices
* by default since they're subject to races when devices are
@@ -381,7 +375,7 @@ static int mount_add_quota_dependencies(Mount *m) {
if (!p)
return 0;
- if (!needs_quota(p))
+ if (!mount_needs_quota(p))
return 0;
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
@@ -429,10 +423,10 @@ static bool mount_is_extrinsic(Mount *m) {
}
static int mount_add_default_dependencies(Mount *m) {
+ const char *after, *before;
UnitDependencyMask mask;
- int r;
MountParameters *p;
- const char *after;
+ int r;
assert(m);
@@ -474,8 +468,15 @@ static int mount_add_default_dependencies(Mount *m) {
return r;
after = SPECIAL_REMOTE_FS_PRE_TARGET;
- } else
+ before = SPECIAL_REMOTE_FS_TARGET;
+ } else {
after = SPECIAL_LOCAL_FS_PRE_TARGET;
+ before = SPECIAL_LOCAL_FS_TARGET;
+ }
+
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
+ if (r < 0)
+ return r;
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
if (r < 0)
@@ -542,6 +543,10 @@ static int mount_add_extras(Mount *m) {
assert(m);
+ /* Note: this call might be called after we already have been loaded once (and even when it has already been
+ * activated), in case data from /proc/self/mountinfo has changed. This means all code here needs to be ready
+ * to run with an already set up unit. */
+
if (u->fragment_path)
m->from_fragment = true;
@@ -611,28 +616,33 @@ static int mount_load_root_mount(Unit *u) {
static int mount_load(Unit *u) {
Mount *m = MOUNT(u);
- int r;
+ int r, q, w;
assert(u);
assert(u->load_state == UNIT_STUB);
r = mount_load_root_mount(u);
- if (r < 0)
- return r;
if (m->from_proc_self_mountinfo || u->perpetual)
- r = unit_load_fragment_and_dropin_optional(u);
+ q = unit_load_fragment_and_dropin_optional(u);
else
- r = unit_load_fragment_and_dropin(u);
+ q = unit_load_fragment_and_dropin(u);
+
+ /* Add in some extras. Note we do this in all cases (even if we failed to load the unit) when announced by the
+ * kernel, because we need some things to be set up no matter what when the kernel establishes a mount and thus
+ * we need to update the state in our unit to track it. After all, consider that we don't allow changing the
+ * 'slice' field for a unit once it is active. */
+ if (u->load_state == UNIT_LOADED || m->from_proc_self_mountinfo || u->perpetual)
+ w = mount_add_extras(m);
+ else
+ w = 0;
+
if (r < 0)
return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
- r = mount_add_extras(m);
- if (r < 0)
- return r;
- }
+ if (q < 0)
+ return q;
+ if (w < 0)
+ return w;
return mount_verify(m);
}
@@ -944,7 +954,6 @@ static void mount_enter_mounting(Mount *m) {
(void) mkdir_p_label(m->where, m->directory_mode);
unit_warn_if_dir_nonempty(UNIT(m), m->where);
-
unit_warn_leftover_processes(UNIT(m));
m->control_command_id = MOUNT_EXEC_MOUNT;
@@ -1048,6 +1057,17 @@ fail:
mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
}
+static void mount_cycle_clear(Mount *m) {
+ assert(m);
+
+ /* Clear all state we shall forget for this new cycle */
+
+ m->result = MOUNT_SUCCESS;
+ m->reload_result = MOUNT_SUCCESS;
+ exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
+ UNIT(m)->reset_accounting = true;
+}
+
static int mount_start(Unit *u) {
Mount *m = MOUNT(u);
int r;
@@ -1078,13 +1098,9 @@ static int mount_start(Unit *u) {
if (r < 0)
return r;
- m->result = MOUNT_SUCCESS;
- m->reload_result = MOUNT_SUCCESS;
- exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
-
- u->reset_accounting = true;
-
+ mount_cycle_clear(m);
mount_enter_mounting(m);
+
return 1;
}
@@ -1148,6 +1164,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
(void) serialize_item(f, "state", mount_state_to_string(m->state));
(void) serialize_item(f, "result", mount_result_to_string(m->result));
(void) serialize_item(f, "reload-result", mount_result_to_string(m->reload_result));
+ (void) serialize_item_format(f, "n-retry-umount", "%u", m->n_retry_umount);
if (m->control_pid > 0)
(void) serialize_item_format(f, "control-pid", PID_FMT, m->control_pid);
@@ -1160,6 +1177,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
Mount *m = MOUNT(u);
+ int r;
assert(u);
assert(key);
@@ -1173,6 +1191,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
log_unit_debug(u, "Failed to parse state value: %s", value);
else
m->deserialized_state = state;
+
} else if (streq(key, "result")) {
MountResult f;
@@ -1191,13 +1210,17 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
else if (f != MOUNT_SUCCESS)
m->reload_result = f;
+ } else if (streq(key, "n-retry-umount")) {
+
+ r = safe_atou(value, &m->n_retry_umount);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse n-retry-umount value: %s", value);
+
} else if (streq(key, "control-pid")) {
- pid_t pid;
- if (parse_pid(value, &pid) < 0)
+ if (parse_pid(value, &m->control_pid) < 0)
log_unit_debug(u, "Failed to parse control-pid value: %s", value);
- else
- m->control_pid = pid;
+
} else if (streq(key, "control-command")) {
MountExecCommand id;
@@ -1405,59 +1428,77 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
return 0;
}
-typedef struct {
- bool is_mounted;
- bool just_mounted;
- bool just_changed;
-} MountSetupFlags;
+static int update_parameters_proc_self_mount_info(
+ Mount *m,
+ const char *what,
+ const char *options,
+ const char *fstype) {
+
+ MountParameters *p;
+ int r, q, w;
+
+ p = &m->parameters_proc_self_mountinfo;
+
+ r = free_and_strdup(&p->what, what);
+ if (r < 0)
+ return r;
+
+ q = free_and_strdup(&p->options, options);
+ if (q < 0)
+ return q;
+
+ w = free_and_strdup(&p->fstype, fstype);
+ if (w < 0)
+ return w;
+
+ return r > 0 || q > 0 || w > 0;
+}
static int mount_setup_new_unit(
- Unit *u,
+ Manager *m,
+ const char *name,
const char *what,
const char *where,
const char *options,
const char *fstype,
- MountSetupFlags *flags) {
-
- MountParameters *p;
+ MountProcFlags *ret_flags,
+ Unit **ret) {
- assert(u);
- assert(flags);
+ _cleanup_(unit_freep) Unit *u = NULL;
+ int r;
- u->source_path = strdup("/proc/self/mountinfo");
- MOUNT(u)->where = strdup(where);
- if (!u->source_path || !MOUNT(u)->where)
- return -ENOMEM;
+ assert(m);
+ assert(name);
+ assert(ret_flags);
+ assert(ret);
- /* Make sure to initialize those fields before mount_is_extrinsic(). */
- MOUNT(u)->from_proc_self_mountinfo = true;
- p = &MOUNT(u)->parameters_proc_self_mountinfo;
+ r = unit_new_for_name(m, sizeof(Mount), name, &u);
+ if (r < 0)
+ return r;
- p->what = strdup(what);
- p->options = strdup(options);
- p->fstype = strdup(fstype);
- if (!p->what || !p->options || !p->fstype)
- return -ENOMEM;
+ r = free_and_strdup(&u->source_path, "/proc/self/mountinfo");
+ if (r < 0)
+ return r;
- if (!mount_is_extrinsic(MOUNT(u))) {
- const char *target;
- int r;
+ r = free_and_strdup(&MOUNT(u)->where, where);
+ if (r < 0)
+ return r;
- target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
- if (r < 0)
- return r;
+ r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype);
+ if (r < 0)
+ return r;
- r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
- if (r < 0)
- return r;
- }
+ /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load
+ * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps
+ * to.*/
+ MOUNT(u)->from_proc_self_mountinfo = true;
+ /* We have only allocated the stub now, let's enqueue this unit for loading now, so that everything else is
+ * loaded in now. */
unit_add_to_load_queue(u);
- flags->is_mounted = true;
- flags->just_mounted = true;
- flags->just_changed = true;
+ *ret_flags = MOUNT_PROC_IS_MOUNTED | MOUNT_PROC_JUST_MOUNTED | MOUNT_PROC_JUST_CHANGED;
+ *ret = TAKE_PTR(u);
return 0;
}
@@ -1467,11 +1508,10 @@ static int mount_setup_existing_unit(
const char *where,
const char *options,
const char *fstype,
- MountSetupFlags *flags) {
+ MountProcFlags *ret_flags) {
- MountParameters *p;
- bool load_extras = false;
- int r1, r2, r3;
+ MountProcFlags flags = MOUNT_PROC_IS_MOUNTED;
+ int r;
assert(u);
assert(flags);
@@ -1482,49 +1522,38 @@ static int mount_setup_existing_unit(
return -ENOMEM;
}
- /* Make sure to initialize those fields before mount_is_extrinsic(). */
- p = &MOUNT(u)->parameters_proc_self_mountinfo;
-
- r1 = free_and_strdup(&p->what, what);
- r2 = free_and_strdup(&p->options, options);
- r3 = free_and_strdup(&p->fstype, fstype);
- if (r1 < 0 || r2 < 0 || r3 < 0)
- return -ENOMEM;
-
- flags->just_changed = r1 > 0 || r2 > 0 || r3 > 0;
- flags->is_mounted = true;
- flags->just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted;
-
- MOUNT(u)->from_proc_self_mountinfo = true;
+ r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ flags |= MOUNT_PROC_JUST_CHANGED;
- if (!mount_is_extrinsic(MOUNT(u)) && mount_is_network(p)) {
- /* _netdev option may have shown up late, or on a
- * remount. Add remote-fs dependencies, even though
- * local-fs ones may already be there.
- *
- * Note: due to a current limitation (we don't track
- * in the dependency "Set*" objects who created a
- * dependency), we can only add deps, never lose them,
- * until the next full daemon-reload. */
- unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
- load_extras = true;
+ if (!MOUNT(u)->from_proc_self_mountinfo) {
+ flags |= MOUNT_PROC_JUST_MOUNTED;
+ MOUNT(u)->from_proc_self_mountinfo = true;
}
- if (u->load_state == UNIT_NOT_FOUND) {
+ if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+ /* The unit was previously not found or otherwise not loaded. Now that the unit shows up in
+ * /proc/self/mountinfo we should reconsider it this, hence set it to UNIT_LOADED. */
u->load_state = UNIT_LOADED;
u->load_error = 0;
- /* Load in the extras later on, after we
- * finished initialization of the unit */
-
- /* FIXME: since we're going to load the unit later on, why setting load_extras=true ? */
- load_extras = true;
- flags->just_changed = true;
+ flags |= MOUNT_PROC_JUST_CHANGED;
}
- if (load_extras)
- return mount_add_extras(MOUNT(u));
+ if (FLAGS_SET(flags, MOUNT_PROC_JUST_CHANGED)) {
+ /* If things changed, then make sure that all deps are regenerated. Let's
+ * first remove all automatic deps, and then add in the new ones. */
+ unit_remove_dependencies(u, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
+
+ r = mount_add_extras(MOUNT(u));
+ if (r < 0)
+ return r;
+ }
+
+ *ret_flags = flags;
return 0;
}
@@ -1537,7 +1566,7 @@ static int mount_setup_unit(
bool set_flags) {
_cleanup_free_ char *e = NULL;
- MountSetupFlags flags;
+ MountProcFlags flags;
Unit *u;
int r;
@@ -1561,44 +1590,32 @@ static int mount_setup_unit(
r = unit_name_from_path(where, ".mount", &e);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to generate unit name from path '%s': %m", where);
u = manager_get_unit(m, e);
- if (!u) {
- /* First time we see this mount point meaning that it's
- * not been initiated by a mount unit but rather by the
- * sysadmin having called mount(8) directly. */
- r = unit_new_for_name(m, sizeof(Mount), e, &u);
- if (r < 0)
- goto fail;
-
- r = mount_setup_new_unit(u, what, where, options, fstype, &flags);
- if (r < 0)
- unit_free(u);
- } else
+ if (u)
r = mount_setup_existing_unit(u, what, where, options, fstype, &flags);
-
+ else
+ /* First time we see this mount point meaning that it's not been initiated by a mount unit but rather
+ * by the sysadmin having called mount(8) directly. */
+ r = mount_setup_new_unit(m, e, what, where, options, fstype, &flags, &u);
if (r < 0)
- goto fail;
-
- if (set_flags) {
- MOUNT(u)->is_mounted = flags.is_mounted;
- MOUNT(u)->just_mounted = flags.just_mounted;
- MOUNT(u)->just_changed = flags.just_changed;
- }
+ return log_warning_errno(r, "Failed to set up mount unit: %m");
- if (flags.just_changed)
+ /* If the mount changed properties or state, let's notify our clients */
+ if (flags & (MOUNT_PROC_JUST_CHANGED|MOUNT_PROC_JUST_MOUNTED))
unit_add_to_dbus_queue(u);
+ if (set_flags)
+ MOUNT(u)->proc_flags = flags;
+
return 0;
-fail:
- return log_warning_errno(r, "Failed to set up mount unit: %m");
}
static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
_cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
- int r = 0;
+ int r;
assert(m);
@@ -1611,7 +1628,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
if (r < 0)
return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
- r = 0;
for (;;) {
struct libmnt_fs *fs;
const char *device, *path, *options, *fstype;
@@ -1640,12 +1656,10 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
- k = mount_setup_unit(m, d, p, options, fstype, set_flags);
- if (r == 0 && k < 0)
- r = k;
+ (void) mount_setup_unit(m, d, p, options, fstype, set_flags);
}
- return r;
+ return 0;
}
static void mount_shutdown(Manager *m) {
@@ -1703,7 +1717,7 @@ static void mount_enumerate_perpetual(Manager *m) {
static bool mount_is_mounted(Mount *m) {
assert(m);
- return UNIT(m)->perpetual || m->is_mounted;
+ return UNIT(m)->perpetual || FLAGS_SET(m->proc_flags, MOUNT_PROC_IS_MOUNTED);
}
static void mount_enumerate(Manager *m) {
@@ -1767,7 +1781,7 @@ fail:
}
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_set_free_ Set *around = NULL, *gone = NULL;
+ _cleanup_set_free_free_ Set *around = NULL, *gone = NULL;
Manager *m = userdata;
const char *what;
Iterator i;
@@ -1803,11 +1817,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {
/* Reset flags, just in case, for later calls */
- LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
- Mount *mount = MOUNT(u);
-
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
- }
+ LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT])
+ MOUNT(u)->proc_flags = 0;
return 0;
}
@@ -1828,7 +1839,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
/* Remember that this device might just have disappeared */
if (set_ensure_allocated(&gone, &path_hash_ops) < 0 ||
- set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0)
+ set_put_strdup(gone, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom(); /* we don't care too much about OOM here... */
}
@@ -1837,10 +1848,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
switch (mount->state) {
case MOUNT_MOUNTED:
- /* This has just been unmounted by
- * somebody else, follow the state
- * change. */
- mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */
+ /* This has just been unmounted by somebody else, follow the state change. */
mount_enter_dead(mount, MOUNT_SUCCESS);
break;
@@ -1848,7 +1856,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
break;
}
- } else if (mount->just_mounted || mount->just_changed) {
+ } else if (mount->proc_flags & (MOUNT_PROC_JUST_MOUNTED|MOUNT_PROC_JUST_CHANGED)) {
/* A mount point was added or changed */
@@ -1859,7 +1867,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
/* This has just been mounted by somebody else, follow the state change, but let's
* generate a new invocation ID for this implicitly and automatically. */
- (void) unit_acquire_invocation_id(UNIT(mount));
+ (void) unit_acquire_invocation_id(u);
+ mount_cycle_clear(mount);
mount_enter_mounted(mount, MOUNT_SUCCESS);
break;
@@ -1881,14 +1890,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (mount_is_mounted(mount) &&
mount->from_proc_self_mountinfo &&
mount->parameters_proc_self_mountinfo.what) {
+ /* Track devices currently used */
if (set_ensure_allocated(&around, &path_hash_ops) < 0 ||
- set_put(around, mount->parameters_proc_self_mountinfo.what) < 0)
+ set_put_strdup(around, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom();
}
/* Reset the flags for later calls */
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
+ mount->proc_flags = 0;
}
SET_FOREACH(what, gone, i) {
diff --git a/src/core/mount.h b/src/core/mount.h
index 67ab8ecf93..2e59f1fe04 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -34,6 +34,13 @@ typedef struct MountParameters {
char *fstype;
} MountParameters;
+/* Used while looking for mount points that vanished or got added from/to /proc/self/mountinfo */
+typedef enum MountProcFlags {
+ MOUNT_PROC_IS_MOUNTED = 1 << 0,
+ MOUNT_PROC_JUST_MOUNTED = 1 << 1,
+ MOUNT_PROC_JUST_CHANGED = 1 << 2,
+} MountProcFlags;
+
struct Mount {
Unit meta;
@@ -45,11 +52,7 @@ struct Mount {
bool from_proc_self_mountinfo:1;
bool from_fragment:1;
- /* Used while looking for mount points that vanished or got
- * added from/to /proc/self/mountinfo */
- bool is_mounted:1;
- bool just_mounted:1;
- bool just_changed:1;
+ MountProcFlags proc_flags;
bool sloppy_options;
diff --git a/src/core/service.c b/src/core/service.c
index 76f1e16069..d631687205 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -935,8 +935,8 @@ static int service_load_pid_file(Service *s, bool may_warn) {
prio = may_warn ? LOG_INFO : LOG_DEBUG;
fd = chase_symlinks(s->pid_file, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
- if (fd == -EPERM) {
- log_unit_full(UNIT(s), LOG_DEBUG, fd, "Permission denied while opening PID file or potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
+ if (fd == -ENOLINK) {
+ log_unit_full(UNIT(s), LOG_DEBUG, fd, "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
questionable_pid_file = true;
diff --git a/src/core/swap.c b/src/core/swap.c
index 90207a48fa..2d8463b8b1 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -273,77 +273,92 @@ static int swap_load_devnode(Swap *s) {
return swap_set_devnode(s, p);
}
-static int swap_load(Unit *u) {
+static int swap_add_extras(Swap *s) {
int r;
- Swap *s = SWAP(u);
assert(s);
- assert(u->load_state == UNIT_STUB);
- /* Load a .swap file */
- if (SWAP(u)->from_proc_swaps)
- r = unit_load_fragment_and_dropin_optional(u);
- else
- r = unit_load_fragment_and_dropin(u);
+ if (UNIT(s)->fragment_path)
+ s->from_fragment = true;
+
+ if (!s->what) {
+ if (s->parameters_fragment.what)
+ s->what = strdup(s->parameters_fragment.what);
+ else if (s->parameters_proc_swaps.what)
+ s->what = strdup(s->parameters_proc_swaps.what);
+ else {
+ r = unit_name_to_path(UNIT(s)->id, &s->what);
+ if (r < 0)
+ return r;
+ }
+
+ if (!s->what)
+ return -ENOMEM;
+ }
+
+ path_simplify(s->what, false);
+
+ if (!UNIT(s)->description) {
+ r = unit_set_description(UNIT(s), s->what);
+ if (r < 0)
+ return r;
+ }
+
+ r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
- if (u->load_state == UNIT_LOADED) {
-
- if (UNIT(s)->fragment_path)
- s->from_fragment = true;
+ r = swap_add_device_dependencies(s);
+ if (r < 0)
+ return r;
- if (!s->what) {
- if (s->parameters_fragment.what)
- s->what = strdup(s->parameters_fragment.what);
- else if (s->parameters_proc_swaps.what)
- s->what = strdup(s->parameters_proc_swaps.what);
- else {
- r = unit_name_to_path(u->id, &s->what);
- if (r < 0)
- return r;
- }
+ r = swap_load_devnode(s);
+ if (r < 0)
+ return r;
- if (!s->what)
- return -ENOMEM;
- }
+ r = unit_patch_contexts(UNIT(s));
+ if (r < 0)
+ return r;
- path_simplify(s->what, false);
+ r = unit_add_exec_dependencies(UNIT(s), &s->exec_context);
+ if (r < 0)
+ return r;
- if (!UNIT(s)->description) {
- r = unit_set_description(u, s->what);
- if (r < 0)
- return r;
- }
+ r = unit_set_default_slice(UNIT(s));
+ if (r < 0)
+ return r;
- r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
- if (r < 0)
- return r;
+ r = swap_add_default_dependencies(s);
+ if (r < 0)
+ return r;
- r = swap_add_device_dependencies(s);
- if (r < 0)
- return r;
+ return 0;
+}
- r = swap_load_devnode(s);
- if (r < 0)
- return r;
+static int swap_load(Unit *u) {
+ Swap *s = SWAP(u);
+ int r, q;
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
+ assert(s);
+ assert(u->load_state == UNIT_STUB);
- r = unit_add_exec_dependencies(u, &s->exec_context);
- if (r < 0)
- return r;
+ /* Load a .swap file */
+ if (SWAP(u)->from_proc_swaps)
+ r = unit_load_fragment_and_dropin_optional(u);
+ else
+ r = unit_load_fragment_and_dropin(u);
- r = unit_set_default_slice(u);
- if (r < 0)
- return r;
+ /* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is already
+ * active. */
+ if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
+ q = swap_add_extras(s);
+ else
+ q = 0;
- r = swap_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ if (r < 0)
+ return r;
+ if (q < 0)
+ return q;
return swap_verify(s);
}
@@ -370,7 +385,6 @@ static int swap_setup_unit(
return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
u = manager_get_unit(m, e);
-
if (u &&
SWAP(u)->from_proc_swaps &&
!path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
@@ -405,6 +419,13 @@ static int swap_setup_unit(
}
}
+ /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
+ * loaded. After all we can load it now, from the data in /proc/swaps. */
+ if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+ u->load_state = UNIT_LOADED;
+ u->load_error = 0;
+ }
+
if (set_flags) {
SWAP(u)->is_active = true;
SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
@@ -472,7 +493,7 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f
swap_setup_unit(m, devlink, device, prio, set_flags);
}
- return r;
+ return 0;
}
static void swap_set_state(Swap *s, SwapState state) {
@@ -813,6 +834,14 @@ fail:
swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
}
+static void swap_cycle_clear(Swap *s) {
+ assert(s);
+
+ s->result = SWAP_SUCCESS;
+ exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
+ UNIT(s)->reset_accounting = true;
+}
+
static int swap_start(Unit *u) {
Swap *s = SWAP(u), *other;
int r;
@@ -852,11 +881,7 @@ static int swap_start(Unit *u) {
if (r < 0)
return r;
- s->result = SWAP_SUCCESS;
- exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
-
- u->reset_accounting = true;
-
+ swap_cycle_clear(s);
swap_enter_activating(s);
return 1;
}
@@ -1088,7 +1113,6 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
static int swap_load_proc_swaps(Manager *m, bool set_flags) {
unsigned i;
- int r = 0;
assert(m);
@@ -1120,12 +1144,10 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
- k = swap_process_new(m, d, prio, set_flags);
- if (k < 0)
- r = k;
+ (void) swap_process_new(m, d, prio, set_flags);
}
- return r;
+ return 0;
}
static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
@@ -1156,13 +1178,13 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
Swap *swap = SWAP(u);
if (!swap->is_active) {
- /* This has just been deactivated */
swap_unset_proc_swaps(swap);
switch (swap->state) {
case SWAP_ACTIVE:
+ /* This has just been deactivated */
swap_enter_dead(swap, SWAP_SUCCESS);
break;
@@ -1183,7 +1205,8 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
case SWAP_DEAD:
case SWAP_FAILED:
- (void) unit_acquire_invocation_id(UNIT(swap));
+ (void) unit_acquire_invocation_id(u);
+ swap_cycle_clear(swap);
swap_enter_active(swap, SWAP_SUCCESS);
break;
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 69bc447920..4185af63e1 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -18,6 +18,7 @@
#include "hostname-util.h"
#include "log.h"
#include "logs-show.h"
+#include "main-func.h"
#include "microhttpd-util.h"
#include "os-util.h"
#include "parse-util.h"
@@ -31,7 +32,11 @@
static char *arg_key_pem = NULL;
static char *arg_cert_pem = NULL;
static char *arg_trust_pem = NULL;
-static char *arg_directory = NULL;
+static const char *arg_directory = NULL;
+
+STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
typedef struct RequestMeta {
sd_journal *journal;
@@ -981,95 +986,85 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-int main(int argc, char *argv[]) {
- struct MHD_Daemon *d = NULL;
+static int run(int argc, char *argv[]) {
+ _cleanup_(MHD_stop_daemonp) struct MHD_Daemon *d = NULL;
+ struct MHD_OptionItem opts[] = {
+ { MHD_OPTION_NOTIFY_COMPLETED,
+ (intptr_t) request_meta_free, NULL },
+ { MHD_OPTION_EXTERNAL_LOGGER,
+ (intptr_t) microhttpd_logger, NULL },
+ { MHD_OPTION_END, 0, NULL },
+ { MHD_OPTION_END, 0, NULL },
+ { MHD_OPTION_END, 0, NULL },
+ { MHD_OPTION_END, 0, NULL },
+ { MHD_OPTION_END, 0, NULL },
+ };
+ int opts_pos = 2;
+
+ /* We force MHD_USE_ITC here, in order to make sure
+ * libmicrohttpd doesn't use shutdown() on our listening
+ * socket, which would break socket re-activation. See
+ *
+ * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
+ * https://github.com/systemd/systemd/pull/1286
+ */
+
+ int flags =
+ MHD_USE_DEBUG |
+ MHD_USE_DUAL_STACK |
+ MHD_USE_ITC |
+ MHD_USE_POLL_INTERNAL_THREAD |
+ MHD_USE_THREAD_PER_CONNECTION;
int r, n;
log_setup_service();
r = parse_argv(argc, argv);
- if (r < 0)
- return EXIT_FAILURE;
- if (r == 0)
- return EXIT_SUCCESS;
+ if (r <= 0)
+ return r;
sigbus_install();
r = setup_gnutls_logger(NULL);
if (r < 0)
- return EXIT_FAILURE;
+ return r;
n = sd_listen_fds(1);
- if (n < 0) {
- log_error_errno(n, "Failed to determine passed sockets: %m");
- goto finish;
- } else if (n > 1) {
- log_error("Can't listen on more than one socket.");
- goto finish;
- } else {
- struct MHD_OptionItem opts[] = {
- { MHD_OPTION_NOTIFY_COMPLETED,
- (intptr_t) request_meta_free, NULL },
- { MHD_OPTION_EXTERNAL_LOGGER,
- (intptr_t) microhttpd_logger, NULL },
- { MHD_OPTION_END, 0, NULL },
- { MHD_OPTION_END, 0, NULL },
- { MHD_OPTION_END, 0, NULL },
- { MHD_OPTION_END, 0, NULL },
- { MHD_OPTION_END, 0, NULL }};
- int opts_pos = 2;
-
- /* We force MHD_USE_ITC here, in order to make sure
- * libmicrohttpd doesn't use shutdown() on our listening
- * socket, which would break socket re-activation. See
- *
- * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
- * https://github.com/systemd/systemd/pull/1286
- */
-
- int flags =
- MHD_USE_DEBUG |
- MHD_USE_DUAL_STACK |
- MHD_USE_ITC |
- MHD_USE_POLL_INTERNAL_THREAD |
- MHD_USE_THREAD_PER_CONNECTION;
-
- if (n > 0)
- opts[opts_pos++] = (struct MHD_OptionItem)
- {MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START};
- if (arg_key_pem) {
- assert(arg_cert_pem);
- opts[opts_pos++] = (struct MHD_OptionItem)
- {MHD_OPTION_HTTPS_MEM_KEY, 0, arg_key_pem};
- opts[opts_pos++] = (struct MHD_OptionItem)
- {MHD_OPTION_HTTPS_MEM_CERT, 0, arg_cert_pem};
- flags |= MHD_USE_TLS;
- }
- if (arg_trust_pem) {
- assert(flags & MHD_USE_TLS);
- opts[opts_pos++] = (struct MHD_OptionItem)
- {MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem};
- }
-
- d = MHD_start_daemon(flags, 19531,
- NULL, NULL,
- request_handler, NULL,
- MHD_OPTION_ARRAY, opts,
- MHD_OPTION_END);
+ if (n < 0)
+ return log_error_errno(n, "Failed to determine passed sockets: %m");
+ if (n > 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Can't listen on more than one socket.");
+
+ if (n == 1)
+ opts[opts_pos++] = (struct MHD_OptionItem)
+ { MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START };
+
+ if (arg_key_pem) {
+ assert(arg_cert_pem);
+ opts[opts_pos++] = (struct MHD_OptionItem)
+ { MHD_OPTION_HTTPS_MEM_KEY, 0, arg_key_pem };
+ opts[opts_pos++] = (struct MHD_OptionItem)
+ { MHD_OPTION_HTTPS_MEM_CERT, 0, arg_cert_pem };
+ flags |= MHD_USE_TLS;
}
- if (!d) {
- log_error("Failed to start daemon!");
- goto finish;
+ if (arg_trust_pem) {
+ assert(flags & MHD_USE_TLS);
+ opts[opts_pos++] = (struct MHD_OptionItem)
+ { MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem };
}
- pause();
-
- r = EXIT_SUCCESS;
+ d = MHD_start_daemon(flags, 19531,
+ NULL, NULL,
+ request_handler, NULL,
+ MHD_OPTION_ARRAY, opts,
+ MHD_OPTION_END);
+ if (!d)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start daemon!");
-finish:
- if (d)
- MHD_stop_daemon(d);
+ pause();
- return r;
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index b82d4b4a1b..e1748cb46b 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -6,11 +6,13 @@
#include "sd-daemon.h"
#include "conf-parser.h"
+#include "daemon-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "journal-remote-write.h"
#include "journal-remote.h"
+#include "main-func.h"
#include "pretty-print.h"
#include "process-util.h"
#include "rlimit-util.h"
@@ -24,25 +26,30 @@
#define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
#define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
-static char* arg_url = NULL;
-static char* arg_getter = NULL;
-static char* arg_listen_raw = NULL;
-static char* arg_listen_http = NULL;
-static char* arg_listen_https = NULL;
-static char** arg_files = NULL;
+static const char* arg_url = NULL;
+static const char* arg_getter = NULL;
+static const char* arg_listen_raw = NULL;
+static const char* arg_listen_http = NULL;
+static const char* arg_listen_https = NULL;
+static char** arg_files = NULL; /* Do not free this. */
static int arg_compress = true;
static int arg_seal = false;
static int http_socket = -1, https_socket = -1;
static char** arg_gnutls_log = NULL;
static JournalWriteSplitMode arg_split_mode = _JOURNAL_WRITE_SPLIT_INVALID;
-static char* arg_output = NULL;
+static const char* arg_output = NULL;
static char *arg_key = NULL;
static char *arg_cert = NULL;
static char *arg_trust = NULL;
static bool arg_trust_all = false;
+STATIC_DESTRUCTOR_REGISTER(arg_gnutls_log, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_key, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_cert, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_trust, freep);
+
static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
[JOURNAL_WRITE_SPLIT_NONE] = "none",
[JOURNAL_WRITE_SPLIT_HOST] = "host",
@@ -615,8 +622,7 @@ static int create_remoteserver(
}
if (arg_url) {
- const char *url;
- char *hostname;
+ const char *url, *hostname;
if (!strstr(arg_url, "/entries")) {
if (endswith(arg_url, "/"))
@@ -637,7 +643,7 @@ static int create_remoteserver(
hostname = strndupa(hostname, strcspn(hostname, "/:"));
- r = journal_remote_add_source(s, fd, hostname, false);
+ r = journal_remote_add_source(s, fd, (char *) hostname, false);
if (r < 0)
return r;
}
@@ -1061,10 +1067,11 @@ static int load_certificates(char **key, char **cert, char **trust) {
return 0;
}
-int main(int argc, char **argv) {
- RemoteServer s = {};
- int r;
+static int run(int argc, char **argv) {
+ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
+ _cleanup_(journal_remote_server_destroy) RemoteServer s = {};
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
+ int r;
log_show_color(true);
log_parse_environment();
@@ -1074,63 +1081,61 @@ int main(int argc, char **argv) {
r = parse_config();
if (r < 0)
- return EXIT_FAILURE;
+ return r;
r = parse_argv(argc, argv);
if (r <= 0)
- return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ return r;
if (arg_listen_http || arg_listen_https) {
r = setup_gnutls_logger(arg_gnutls_log);
if (r < 0)
- return EXIT_FAILURE;
+ return r;
}
if (arg_listen_https || https_socket >= 0) {
- if (load_certificates(&key, &cert, &trust) < 0)
- return EXIT_FAILURE;
+ r = load_certificates(&key, &cert, &trust);
+ if (r < 0)
+ return r;
+
s.check_trust = !arg_trust_all;
}
- if (create_remoteserver(&s, key, cert, trust) < 0)
- return EXIT_FAILURE;
+ r = create_remoteserver(&s, key, cert, trust);
+ if (r < 0)
+ return r;
r = sd_event_set_watchdog(s.events, true);
if (r < 0)
- log_error_errno(r, "Failed to enable watchdog: %m");
- else
- log_debug("Watchdog is %sd.", enable_disable(r > 0));
+ return log_error_errno(r, "Failed to enable watchdog: %m");
+
+ log_debug("Watchdog is %sd.", enable_disable(r > 0));
log_debug("%s running as pid "PID_FMT,
program_invocation_short_name, getpid_cached());
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
+
+ notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
while (s.active) {
r = sd_event_get_state(s.events);
if (r < 0)
- break;
+ return r;
if (r == SD_EVENT_FINISHED)
break;
r = sd_event_run(s.events, -1);
- if (r < 0) {
- log_error_errno(r, "Failed to run event loop: %m");
- break;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
}
- sd_notifyf(false,
- "STOPPING=1\n"
- "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
- log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
-
- journal_remote_server_destroy(&s);
+ notify_message = NULL;
+ (void) sd_notifyf(false,
+ "STOPPING=1\n"
+ "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
- free(arg_key);
- free(arg_cert);
- free(arg_trust);
+ log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
- return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 1f3cdb932f..3c0916c438 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -346,7 +346,7 @@ static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
}
#endif
-RemoteServer* journal_remote_server_destroy(RemoteServer *s) {
+void journal_remote_server_destroy(RemoteServer *s) {
size_t i;
#if HAVE_MICROHTTPD
@@ -370,7 +370,6 @@ RemoteServer* journal_remote_server_destroy(RemoteServer *s) {
journal_remote_server_global = NULL;
/* fds that we're listening on remain open... */
- return NULL;
}
/**********************************************************************
diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h
index e083ea9c74..4c25d43abf 100644
--- a/src/journal-remote/journal-remote.h
+++ b/src/journal-remote/journal-remote.h
@@ -62,4 +62,4 @@ int journal_remote_handle_raw_source(
uint32_t revents,
RemoteServer *s);
-RemoteServer* journal_remote_server_destroy(RemoteServer *s);
+void journal_remote_server_destroy(RemoteServer *s);
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 7f08809c54..1e08fcc554 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "daemon-util.h"
#include "def.h"
#include "env-file.h"
#include "fd-util.h"
@@ -18,6 +19,7 @@
#include "glob-util.h"
#include "journal-upload.h"
#include "log.h"
+#include "main-func.h"
#include "mkdir.h"
#include "parse-util.h"
#include "pretty-print.h"
@@ -761,10 +763,11 @@ static int open_journal(sd_journal **j) {
return r;
}
-int main(int argc, char **argv) {
- Uploader u;
- int r;
+static int run(int argc, char **argv) {
+ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
+ _cleanup_(destroy_uploader) Uploader u = {};
bool use_journal;
+ int r;
log_show_color(true);
log_parse_environment();
@@ -774,23 +777,23 @@ int main(int argc, char **argv) {
r = parse_config();
if (r < 0)
- goto finish;
+ return r;
r = parse_argv(argc, argv);
if (r <= 0)
- goto finish;
+ return r;
sigbus_install();
r = setup_uploader(&u, arg_url, arg_save_state);
if (r < 0)
- goto cleanup;
+ return r;
sd_event_set_watchdog(u.events, true);
r = check_cursor_updating(&u);
if (r < 0)
- goto cleanup;
+ return r;
log_debug("%s running as pid "PID_FMT,
program_invocation_short_name, getpid_cached());
@@ -800,61 +803,51 @@ int main(int argc, char **argv) {
sd_journal *j;
r = open_journal(&j);
if (r < 0)
- goto finish;
+ return r;
r = open_journal_for_upload(&u, j,
arg_cursor ?: u.last_cursor,
arg_cursor ? arg_after_cursor : true,
!!arg_follow);
if (r < 0)
- goto finish;
+ return r;
}
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing input...");
+ notify_message = notify_start("READY=1\n"
+ "STATUS=Processing input...",
+ NOTIFY_STOPPING);
for (;;) {
r = sd_event_get_state(u.events);
if (r < 0)
- break;
+ return r;
if (r == SD_EVENT_FINISHED)
- break;
+ return 0;
if (use_journal) {
if (!u.journal)
- break;
+ return 0;
r = check_journal_input(&u);
} else if (u.input < 0 && !use_journal) {
if (optind >= argc)
- break;
+ return 0;
log_debug("Using %s as input.", argv[optind]);
r = open_file_for_upload(&u, argv[optind++]);
}
if (r < 0)
- goto cleanup;
+ return r;
if (u.uploading) {
r = perform_upload(&u);
if (r < 0)
- break;
+ return r;
}
r = sd_event_run(u.events, u.timeout);
- if (r < 0) {
- log_error_errno(r, "Failed to run event loop: %m");
- break;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
}
-
-cleanup:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
-
- destroy_uploader(&u);
-
-finish:
- return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index a50a2a75c7..364cd0f7cf 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -73,3 +73,5 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn
* interesting events without overwhelming detail.
*/
int setup_gnutls_logger(char **categories);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon);
diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c
index b982dcc07d..6935311b9a 100644
--- a/src/libsystemd-network/ndisc-router.c
+++ b/src/libsystemd-network/ndisc-router.c
@@ -676,7 +676,7 @@ _public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret)
_cleanup_free_ char *normalized = NULL;
e[n] = 0;
- r = dns_name_normalize(e, &normalized);
+ r = dns_name_normalize(e, 0, &normalized);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index d35e3e2ce1..b3b134d650 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -371,36 +371,6 @@ int config_parse_hwaddrs(const char *unit,
return 0;
}
-int config_parse_iaid(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- uint32_t iaid;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atou32(rvalue, &iaid);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Unable to read IAID, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- *((uint32_t *)data) = iaid;
-
- return 0;
-}
-
int config_parse_bridge_port_priority(
const char *unit,
const char *filename,
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 45020c2bcf..0c8da848c1 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -35,7 +35,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs);
CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
-CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 842aeaa6b1..3bdd584bb5 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -345,8 +345,9 @@ int sd_dhcp_client_set_client_id(
*/
static int dhcp_client_set_iaid_duid_internal(
sd_dhcp_client *client,
+ bool iaid_append,
+ bool iaid_set,
uint32_t iaid,
- bool append_iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len,
@@ -368,17 +369,17 @@ static int dhcp_client_set_iaid_duid_internal(
zero(client->client_id);
client->client_id.type = 255;
- if (append_iaid) {
- /* If IAID is not configured, generate it. */
- if (iaid == 0) {
+ if (iaid_append) {
+ if (iaid_set)
+ client->client_id.ns.iaid = htobe32(iaid);
+ else {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
true,
&client->client_id.ns.iaid);
if (r < 0)
return r;
- } else
- client->client_id.ns.iaid = htobe32(iaid);
+ }
}
if (duid != NULL) {
@@ -418,10 +419,10 @@ static int dhcp_client_set_iaid_duid_internal(
}
client->client_id_len = sizeof(client->client_id.type) + len +
- (append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
+ (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Configured %sDUID, restarting.", append_iaid ? "IAID+" : "");
+ log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
sd_dhcp_client_start(client);
}
@@ -431,18 +432,20 @@ static int dhcp_client_set_iaid_duid_internal(
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, iaid, true, duid_type, duid, duid_len, 0);
+ return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
}
int sd_dhcp_client_set_iaid_duid_llt(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, iaid, true, DUID_TYPE_LLT, NULL, 0, llt_time);
+ return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
}
int sd_dhcp_client_set_duid(
@@ -450,13 +453,13 @@ int sd_dhcp_client_set_duid(
uint16_t duid_type,
const void *duid,
size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, 0, false, duid_type, duid, duid_len, 0);
+ return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
}
int sd_dhcp_client_set_duid_llt(
sd_dhcp_client *client,
usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, 0, false, DUID_TYPE_LLT, NULL, 0, llt_time);
+ return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
}
int sd_dhcp_client_set_hostname(
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 8275d2f31a..13badbf0bf 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -355,7 +355,7 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}
- r = dns_name_normalize(name, &normalized);
+ r = dns_name_normalize(name, 0, &normalized);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 555ae5f5ec..8ff4585f63 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -56,7 +56,7 @@ struct sd_dhcp6_client {
struct sd_dhcp6_lease *lease;
int fd;
bool information_request;
- bool has_iaid;
+ bool iaid_set;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
@@ -268,7 +268,7 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
client->ia_na.ia_na.id = htobe32(iaid);
client->ia_pd.ia_pd.id = htobe32(iaid);
- client->has_iaid = true;
+ client->iaid_set = true;
return 0;
}
@@ -792,7 +792,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
assert(client);
- if (client->has_iaid)
+ if (client->iaid_set)
return 0;
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
@@ -801,7 +801,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
client->ia_na.ia_na.id = iaid;
client->ia_pd.ia_pd.id = iaid;
- client->has_iaid = true;
+ client->iaid_set = true;
return 0;
}
diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build
index 071691327b..f441bb6972 100644
--- a/src/libsystemd/meson.build
+++ b/src/libsystemd/meson.build
@@ -8,7 +8,7 @@ id128_sources = files('''
sd_daemon_c = files('sd-daemon/sd-daemon.c')
-sd_event_c = files('''
+sd_event_sources = files('''
sd-event/event-source.h
sd-event/event-util.c
sd-event/event-util.h
@@ -90,7 +90,7 @@ libsystemd_sources = files('''
sd-path/sd-path.c
sd-resolve/sd-resolve.c
sd-utf8/sd-utf8.c
-'''.split()) + id128_sources + sd_daemon_c + sd_event_c + sd_login_c
+'''.split()) + id128_sources + sd_daemon_c + sd_event_sources + sd_login_c
disable_mempool_c = files('disable-mempool.c')
diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c
index 0fcbe98c2a..f358524ebc 100644
--- a/src/login/logind-session-device.c
+++ b/src/login/logind-session-device.c
@@ -3,13 +3,9 @@
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
-#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
-/* Old drm.h may needs to be included after stdint.h and sys/types.h */
-#include <drm/drm.h>
-
#include "sd-device.h"
#include "alloc-util.h"
diff --git a/src/network/meson.build b/src/network/meson.build
index d4fa27a288..8fe4854424 100644
--- a/src/network/meson.build
+++ b/src/network/meson.build
@@ -64,6 +64,8 @@ sources = files('''
networkd-manager.h
networkd-ndisc.c
networkd-ndisc.h
+ networkd-neighbor.c
+ networkd-neighbor.h
networkd-radv.c
networkd-radv.h
networkd-network-bus.c
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 31dbea9420..980d49e4ff 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -670,10 +670,12 @@ int dhcp4_set_client_identifier(Link *link) {
if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
+ link->network->iaid_set,
link->network->iaid,
duid->llt_time);
else
r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid_set,
link->network->iaid,
duid->type,
duid->raw_data_len > 0 ? duid->raw_data : NULL,
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 4b5c4b8b4b..ed6b9df72b 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -655,9 +655,11 @@ int dhcp6_configure(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MAC address: %m");
- r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
- if (r < 0)
- return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m");
+ if (link->network->iaid_set) {
+ r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m");
+ }
duid = link_get_duid(link);
if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 86f2e6dca9..d73e85cf25 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -20,6 +20,7 @@
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
+#include "networkd-neighbor.h"
#include "networkd-radv.h"
#include "networkd-routing-policy-rule.h"
#include "set.h"
@@ -719,7 +720,7 @@ static void link_enter_configured(Link *link) {
assert(link);
assert(link->network);
- if (link->state != LINK_STATE_SETTING_ROUTES)
+ if (link->state != LINK_STATE_CONFIGURING)
return;
log_link_info(link, "Configured");
@@ -741,6 +742,12 @@ void link_check_ready(Link *link) {
if (!link->network)
return;
+ if (!link->addresses_configured)
+ return;
+
+ if (!link->neighbors_configured)
+ return;
+
if (!link->static_routes_configured)
return;
@@ -821,9 +828,8 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
assert(link);
assert(link->route_messages > 0);
- assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
- LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
- LINK_STATE_LINGER));
+ assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
+ LINK_STATE_FAILED, LINK_STATE_LINGER));
link->route_messages--;
@@ -843,7 +849,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return 1;
}
-static int link_enter_set_routes(Link *link) {
+static int link_request_set_routes(Link *link) {
enum {
PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
PHASE_GATEWAY, /* Second phase: Routes with a gateway */
@@ -854,11 +860,13 @@ static int link_enter_set_routes(Link *link) {
assert(link);
assert(link->network);
- assert(link->state == LINK_STATE_SETTING_ADDRESSES);
+ assert(link->addresses_configured);
+ assert(link->address_messages == 0);
+ assert(link->state != _LINK_STATE_INVALID);
- (void) link_set_routing_policy_rule(link);
+ link_set_state(link, LINK_STATE_CONFIGURING);
- link_set_state(link, LINK_STATE_SETTING_ROUTES);
+ (void) link_set_routing_policy_rule(link);
/* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
for (phase = 0; phase < _PHASE_MAX; phase++)
@@ -886,6 +894,34 @@ static int link_enter_set_routes(Link *link) {
return 0;
}
+static int link_request_set_neighbors(Link *link) {
+ Neighbor *neighbor;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(link->state != _LINK_STATE_INVALID);
+
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
+ r = neighbor_configure(neighbor, link, NULL);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set neighbor: %m");
+ link_enter_failed(link);
+ return r;
+ }
+ }
+
+ if (link->neighbor_messages == 0) {
+ link->neighbors_configured = true;
+ link_check_ready(link);
+ } else
+ log_link_debug(link, "Setting neighbors");
+
+ return 0;
+}
+
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -894,7 +930,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
assert(link);
assert(link->ifname);
assert(link->address_messages > 0);
- assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
+ assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
LINK_STATE_FAILED, LINK_STATE_LINGER));
link->address_messages--;
@@ -910,7 +946,8 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
if (link->address_messages == 0) {
log_link_debug(link, "Addresses set");
- link_enter_set_routes(link);
+ link->addresses_configured = true;
+ link_request_set_routes(link);
}
return 1;
@@ -1027,7 +1064,7 @@ static int link_set_bridge_fdb(Link *link) {
return 0;
}
-static int link_enter_set_addresses(Link *link) {
+static int link_request_set_addresses(Link *link) {
AddressLabel *label;
Address *ad;
int r;
@@ -1040,7 +1077,9 @@ static int link_enter_set_addresses(Link *link) {
if (r < 0)
return r;
- link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ link_request_set_neighbors(link);
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
r = address_configure(ad, link, address_handler, false);
@@ -1181,9 +1220,10 @@ static int link_enter_set_addresses(Link *link) {
log_link_debug(link, "Offering DHCPv4 leases");
}
- if (link->address_messages == 0)
- link_enter_set_routes(link);
- else
+ if (link->address_messages == 0) {
+ link->addresses_configured = true;
+ link_request_set_routes(link);
+ } else
log_link_debug(link, "Setting addresses");
return 0;
@@ -2269,7 +2309,7 @@ static int link_joined(Link *link) {
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
return 0;
- return link_enter_set_addresses(link);
+ return link_request_set_addresses(link);
}
static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@@ -2306,7 +2346,7 @@ static int link_enter_join_netdev(Link *link) {
assert(link->network);
assert(link->state == LINK_STATE_PENDING);
- link_set_state(link, LINK_STATE_ENSLAVING);
+ link_set_state(link, LINK_STATE_CONFIGURING);
link_dirty(link);
@@ -3419,7 +3459,7 @@ static int link_carrier_gained(Link *link) {
return r;
}
- r = link_enter_set_addresses(link);
+ r = link_request_set_addresses(link);
if (r < 0)
return r;
}
@@ -3502,7 +3542,7 @@ int link_update(Link *link, sd_netlink_message *m) {
if (link->state == LINK_STATE_LINGER) {
log_link_info(link, "Link readded");
- link_set_state(link, LINK_STATE_ENSLAVING);
+ link_set_state(link, LINK_STATE_CONFIGURING);
r = link_new_carrier_maps(link);
if (r < 0)
@@ -3597,10 +3637,12 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
- r = sd_dhcp6_client_set_iaid(link->dhcp6_client,
- link->network->iaid);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
+ if (link->network->iaid_set) {
+ r = sd_dhcp6_client_set_iaid(link->dhcp6_client,
+ link->network->iaid);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
+ }
r = sd_dhcp6_client_set_duid(link->dhcp6_client,
duid->type,
@@ -4030,9 +4072,7 @@ void link_clean(Link *link) {
static const char* const link_state_table[_LINK_STATE_MAX] = {
[LINK_STATE_PENDING] = "pending",
- [LINK_STATE_ENSLAVING] = "configuring",
- [LINK_STATE_SETTING_ADDRESSES] = "configuring",
- [LINK_STATE_SETTING_ROUTES] = "configuring",
+ [LINK_STATE_CONFIGURING] = "configuring",
[LINK_STATE_CONFIGURED] = "configured",
[LINK_STATE_UNMANAGED] = "unmanaged",
[LINK_STATE_FAILED] = "failed",
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 3fdfa55b25..00e68fdfaa 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -19,9 +19,7 @@
typedef enum LinkState {
LINK_STATE_PENDING,
- LINK_STATE_ENSLAVING,
- LINK_STATE_SETTING_ADDRESSES,
- LINK_STATE_SETTING_ROUTES,
+ LINK_STATE_CONFIGURING,
LINK_STATE_CONFIGURED,
LINK_STATE_UNMANAGED,
LINK_STATE_FAILED,
@@ -72,6 +70,7 @@ typedef struct Link {
unsigned address_messages;
unsigned address_label_messages;
+ unsigned neighbor_messages;
unsigned route_messages;
unsigned routing_policy_rule_messages;
unsigned routing_policy_rule_remove_messages;
@@ -82,6 +81,8 @@ typedef struct Link {
Set *routes;
Set *routes_foreign;
+ bool addresses_configured;
+
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
char *lease_file;
@@ -97,6 +98,8 @@ typedef struct Link {
bool ipv4ll_address:1;
bool ipv4ll_route:1;
+ bool neighbors_configured;
+
bool static_routes_configured;
bool routing_policy_rules_configured;
bool setting_mtu;
diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c
new file mode 100644
index 0000000000..254a60bdc3
--- /dev/null
+++ b/src/network/networkd-neighbor.c
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "hashmap.h"
+#include "in-addr-util.h"
+#include "netlink-util.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "networkd-neighbor.h"
+
+void neighbor_free(Neighbor *neighbor) {
+ if (!neighbor)
+ return;
+
+ if (neighbor->network) {
+ LIST_REMOVE(neighbors, neighbor->network->neighbors, neighbor);
+ assert(neighbor->network->n_neighbors > 0);
+ neighbor->network->n_neighbors--;
+
+ if (neighbor->section) {
+ hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
+ network_config_section_free(neighbor->section);
+ }
+ }
+
+ free(neighbor);
+}
+
+static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
+ _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
+ int r;
+
+ assert(network);
+ assert(ret);
+ assert(!!filename == (section_line > 0));
+
+ if (filename) {
+ r = network_config_section_new(filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ neighbor = hashmap_get(network->neighbors_by_section, n);
+ if (neighbor) {
+ *ret = TAKE_PTR(neighbor);
+
+ return 0;
+ }
+ }
+
+ neighbor = new(Neighbor, 1);
+ if (!neighbor)
+ return -ENOMEM;
+
+ *neighbor = (Neighbor) {
+ .network = network,
+ .family = AF_UNSPEC,
+ };
+
+ LIST_APPEND(neighbors, network->neighbors, neighbor);
+ network->n_neighbors++;
+
+ if (filename) {
+ neighbor->section = TAKE_PTR(n);
+
+ r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(neighbor);
+
+ return 0;
+}
+
+static int neighbor_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ int r;
+
+ assert(link);
+ assert(link->neighbor_messages > 0);
+
+ link->neighbor_messages--;
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_warning_errno(link, r, "Could not set neighbor: %m");
+
+ if (link->neighbor_messages == 0) {
+ log_link_debug(link, "Neighbors set");
+ link->neighbors_configured = true;
+ link_check_ready(link);
+ }
+
+ return 1;
+}
+
+int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ int r;
+
+ assert(neighbor);
+ assert(link);
+ assert(link->ifindex > 0);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ if (neighbor->family == AF_UNSPEC)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor without Address= configured");
+ if (!neighbor->mac_configured)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor without MACAddress= configured");
+
+ r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
+ link->ifindex, neighbor->family);
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_NEWNEIGH message: %m");
+
+ r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
+ if (r < 0)
+ return log_error_errno(r, "Could not set state: %m");
+
+ r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE);
+ if (r < 0)
+ return log_error_errno(r, "Could not set flags: %m");
+
+ r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, &neighbor->mac);
+ if (r < 0)
+ return log_error_errno(r, "Could not append NDA_LLADDR attribute: %m");
+
+ switch (neighbor->family) {
+ case AF_INET6:
+ r = sd_netlink_message_append_in6_addr(req, NDA_DST, &neighbor->in_addr.in6);
+ if (r < 0)
+ return log_error_errno(r, "Could not append NDA_DST attribute: %m");
+ break;
+ case AF_INET:
+ r = sd_netlink_message_append_in_addr(req, NDA_DST, &neighbor->in_addr.in);
+ if (r < 0)
+ return log_error_errno(r, "Could not append NDA_DST attribute: %m");
+ break;
+ default:
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor with invalid address family");
+ }
+
+ r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_handler,
+ link_netlink_destroy_callback, link);
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
+
+ link->neighbor_messages++;
+ link_ref(link);
+
+ return 0;
+}
+
+int config_parse_neighbor_address(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ _cleanup_(neighbor_freep) Neighbor *n = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = neighbor_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor Address is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(n);
+
+ return 0;
+}
+
+int config_parse_neighbor_hwaddr(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ _cleanup_(neighbor_freep) Neighbor *n = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = neighbor_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = ether_addr_from_string(rvalue, &n->mac);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor MACAddress is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ n->mac_configured = true;
+ TAKE_PTR(n);
+
+ return 0;
+}
diff --git a/src/network/networkd-neighbor.h b/src/network/networkd-neighbor.h
new file mode 100644
index 0000000000..094bf7977e
--- /dev/null
+++ b/src/network/networkd-neighbor.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-netlink.h"
+
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "in-addr-util.h"
+#include "list.h"
+#include "macro.h"
+
+typedef struct Neighbor Neighbor;
+
+#include "networkd-link.h"
+#include "networkd-network.h"
+
+struct Neighbor {
+ Network *network;
+ Link *link;
+ NetworkConfigSection *section;
+
+ int family;
+ union in_addr_union in_addr;
+ bool mac_configured;
+ struct ether_addr mac;
+
+ LIST_FIELDS(Neighbor, neighbors);
+};
+
+void neighbor_free(Neighbor *neighbor);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Neighbor*, neighbor_free);
+
+int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_hwaddr);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 945a3c5705..48d8ae52fa 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -93,6 +93,8 @@ Address.AutoJoin, config_parse_address_flags,
Address.Scope, config_parse_address_scope, 0, 0
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
+Neighbor.Address, config_parse_neighbor_address, 0, 0
+Neighbor.MACAddress, config_parse_neighbor_hwaddr, 0, 0
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule_tos, 0, 0
RoutingPolicyRule.Priority, config_parse_routing_policy_rule_priority, 0, 0
RoutingPolicyRule.Table, config_parse_routing_policy_rule_table, 0, 0
@@ -139,7 +141,7 @@ DHCP.DUIDRawData, config_parse_duid_rawdata,
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.RouteTable, config_parse_dhcp_route_table, 0, 0
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
-DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
+DHCP.IAID, config_parse_iaid, 0, 0
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 178cdff82b..62dc6a0bf7 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -210,6 +210,7 @@ int network_load_one(Manager *manager, const char *filename) {
"Link\0"
"Network\0"
"Address\0"
+ "Neighbor\0"
"IPv6AddressLabel\0"
"RoutingPolicyRule\0"
"Route\0"
@@ -300,6 +301,7 @@ void network_free(Network *network) {
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
RoutingPolicyRule *rule;
FdbEntry *fdb_entry;
+ Neighbor *neighbor;
AddressLabel *label;
Prefix *prefix;
Address *address;
@@ -350,6 +352,9 @@ void network_free(Network *network) {
while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
+ while ((neighbor = network->neighbors))
+ neighbor_free(neighbor);
+
while ((label = network->address_labels))
address_label_free(label);
@@ -362,6 +367,7 @@ void network_free(Network *network) {
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
hashmap_free(network->fdb_entries_by_section);
+ hashmap_free(network->neighbors_by_section);
hashmap_free(network->address_labels_by_section);
hashmap_free(network->prefixes_by_section);
hashmap_free(network->rules_by_section);
@@ -653,7 +659,7 @@ int config_parse_domains(
domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
} else {
- r = dns_name_normalize(domain, &normalized);
+ r = dns_name_normalize(domain, 0, &normalized);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
continue;
@@ -1467,3 +1473,35 @@ static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
+
+int config_parse_iaid(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Network *network = data;
+ uint32_t iaid;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(network);
+
+ r = safe_atou32(rvalue, &iaid);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Unable to read IAID, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ network->iaid = iaid;
+ network->iaid_set = true;
+
+ return 0;
+}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 3592b563c0..3a72c5bd9a 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -15,6 +15,7 @@
#include "networkd-fdb.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-lldp-tx.h"
+#include "networkd-neighbor.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
@@ -226,6 +227,8 @@ struct Network {
uint32_t iaid;
DUID duid;
+ bool iaid_set;
+
bool required_for_online; /* Is this network required to be considered online? */
LLDPMode lldp_mode; /* LLDP reception */
@@ -235,6 +238,7 @@ struct Network {
LIST_HEAD(Route, static_routes);
LIST_HEAD(FdbEntry, static_fdb_entries);
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
+ LIST_HEAD(Neighbor, neighbors);
LIST_HEAD(AddressLabel, address_labels);
LIST_HEAD(Prefix, static_prefixes);
LIST_HEAD(RoutingPolicyRule, rules);
@@ -243,6 +247,7 @@ struct Network {
unsigned n_static_routes;
unsigned n_static_fdb_entries;
unsigned n_ipv6_proxy_ndp_addresses;
+ unsigned n_neighbors;
unsigned n_address_labels;
unsigned n_static_prefixes;
unsigned n_rules;
@@ -250,6 +255,7 @@ struct Network {
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
+ Hashmap *neighbors_by_section;
Hashmap *address_labels_by_section;
Hashmap *prefixes_by_section;
Hashmap *rules_by_section;
@@ -302,6 +308,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_lldp_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_table);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
+CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
/* Legacy IPv4LL support */
CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);
diff --git a/src/network/networkd.c b/src/network/networkd.c
index 4fa5533c60..fcecafe083 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -4,13 +4,16 @@
#include "sd-event.h"
#include "capability-util.h"
+#include "daemon-util.h"
+#include "main-func.h"
#include "mkdir.h"
#include "networkd-conf.h"
#include "networkd-manager.h"
#include "signal-util.h"
#include "user-util.h"
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
const char *user = "systemd-network";
uid_t uid;
@@ -21,17 +24,12 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (argc != 1) {
- log_error("This program takes no arguments.");
- r = -EINVAL;
- goto out;
- }
+ if (argc != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
- if (r < 0) {
- log_error_errno(r, "Cannot resolve user name %s: %m", user);
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot resolve user name %s: %m", user);
/* Create runtime directory. This is not necessary when networkd is
* started with "RuntimeDirectory=systemd/netif", or after
@@ -49,7 +47,7 @@ int main(int argc, char *argv[]) {
(1ULL << CAP_NET_BROADCAST) |
(1ULL << CAP_NET_RAW));
if (r < 0)
- goto out;
+ return log_error_errno(r, "Failed to drop privileges: %m");
}
/* Always create the directories people can create inotify watches in.
@@ -70,72 +68,50 @@ int main(int argc, char *argv[]) {
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m);
- if (r < 0) {
- log_error_errno(r, "Could not create manager: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create manager: %m");
r = manager_connect_bus(m);
- if (r < 0) {
- log_error_errno(r, "Could not connect to bus: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not connect to bus: %m");
r = manager_parse_config_file(m);
if (r < 0)
log_warning_errno(r, "Failed to parse configuration file: %m");
r = manager_load_config(m);
- if (r < 0) {
- log_error_errno(r, "Could not load configuration files: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not load configuration files: %m");
r = manager_rtnl_enumerate_links(m);
- if (r < 0) {
- log_error_errno(r, "Could not enumerate links: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not enumerate links: %m");
r = manager_rtnl_enumerate_addresses(m);
- if (r < 0) {
- log_error_errno(r, "Could not enumerate addresses: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not enumerate addresses: %m");
r = manager_rtnl_enumerate_routes(m);
- if (r < 0) {
- log_error_errno(r, "Could not enumerate routes: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not enumerate routes: %m");
r = manager_rtnl_enumerate_rules(m);
- if (r < 0) {
- log_error_errno(r, "Could not enumerate rules: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not enumerate rules: %m");
r = manager_start(m);
- if (r < 0) {
- log_error_errno(r, "Could not start manager: %m");
- goto out;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not start manager: %m");
log_info("Enumeration completed");
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
+ notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
r = sd_event_loop(m->event);
- if (r < 0) {
- log_error_errno(r, "Event loop failed: %m");
- goto out;
- }
-out:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
+ if (r < 0)
+ return log_error_errno(r, "Event loop failed: %m");
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/network/wait-online/wait-online.c b/src/network/wait-online/wait-online.c
index 7f30862bbf..71b6cf6b87 100644
--- a/src/network/wait-online/wait-online.c
+++ b/src/network/wait-online/wait-online.c
@@ -4,6 +4,8 @@
#include "sd-daemon.h"
+#include "daemon-util.h"
+#include "main-func.h"
#include "manager.h"
#include "pretty-print.h"
#include "signal-util.h"
@@ -14,6 +16,9 @@ static usec_t arg_timeout = 120 * USEC_PER_SEC;
static char **arg_interfaces = NULL;
static char **arg_ignore = NULL;
+STATIC_DESTRUCTOR_REGISTER(arg_interfaces, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
+
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
@@ -105,7 +110,8 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -123,37 +129,24 @@ int main(int argc, char *argv[]) {
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_timeout);
- if (r < 0) {
- log_error_errno(r, "Could not create manager: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create manager: %m");
- if (manager_all_configured(m)) {
- r = 0;
- goto finish;
- }
+ if (manager_all_configured(m))
+ goto success;
- sd_notify(false,
- "READY=1\n"
- "STATUS=Waiting for network connections...");
+ notify_message = notify_start("READY=1\n"
+ "STATUS=Waiting for network connections...",
+ "STATUS=Failed to wait for network connectivity...");
r = sd_event_loop(m->event);
- if (r < 0) {
- log_error_errno(r, "Event loop failed: %m");
- goto finish;
- }
-
-finish:
- strv_free(arg_interfaces);
- strv_free(arg_ignore);
-
- if (r >= 0) {
- sd_notify(false, "STATUS=All interfaces configured...");
+ if (r < 0)
+ return log_error_errno(r, "Event loop failed: %m");
- return EXIT_SUCCESS;
- } else {
- sd_notify(false, "STATUS=Failed waiting for network connectivity...");
+success:
+ notify_message = "STATUS=All interfaces configured...";
- return EXIT_FAILURE;
- }
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index b9fd775526..fbe823da66 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -192,7 +192,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
/* The key names are not necessarily normalized, make sure that they are when we return them to our bus
* clients. */
- r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
if (r < 0)
goto finish;
@@ -405,7 +405,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
if (r == 0)
continue;
- r = dns_name_normalize(rr->ptr.name, &normalized);
+ r = dns_name_normalize(rr->ptr.name, 0, &normalized);
if (r < 0)
goto finish;
@@ -743,7 +743,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r < 0)
return r;
- r = dns_name_normalize(rr->srv.name, &normalized);
+ r = dns_name_normalize(rr->srv.name, 0, &normalized);
if (r < 0)
return r;
@@ -799,7 +799,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (canonical) {
normalized = mfree(normalized);
- r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
if (r < 0)
return r;
}
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 13da4e5991..d9633629e8 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -74,7 +74,7 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
return -ENOBUFS;
for (;;) {
- r = dns_label_unescape(&n, buffer, buffer_max);
+ r = dns_label_unescape(&n, buffer, buffer_max, 0);
if (r < 0)
return r;
if (r == 0)
@@ -1705,7 +1705,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
return 0;
n = dns_resource_key_name(rr->key);
- r = dns_label_unescape(&n, label, sizeof(label));
+ r = dns_label_unescape(&n, label, sizeof label, 0);
if (r <= 0)
return r;
if (r != 1 || label[0] != '*')
@@ -1827,13 +1827,13 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
return r;
if (r > 0) /* If the name we are interested in is a child of the NSEC RR, then append the asterisk to the NSEC
* RR's name. */
- r = dns_name_concat("*", dns_resource_key_name(rr->key), &wc);
+ r = dns_name_concat("*", dns_resource_key_name(rr->key), 0, &wc);
else {
r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
- r = dns_name_concat("*", common_suffix, &wc);
+ r = dns_name_concat("*", common_suffix, 0, &wc);
}
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 0ff444acd0..572271be95 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -535,7 +535,7 @@ int dns_packet_append_name(
}
}
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_label_unescape(&name, label, sizeof label, 0);
if (r < 0)
goto fail;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index b67c734e04..a1dffb08a3 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -77,7 +77,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
return 0;
}
- r = dns_name_concat(dns_resource_key_name(key), name, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), name, 0, &joined);
if (r < 0)
return r;
@@ -222,7 +222,7 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr,
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
if (r < 0)
return r;
@@ -254,7 +254,7 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c
index 368ec4da19..21c2442c51 100644
--- a/src/resolve/resolved-dns-search-domain.c
+++ b/src/resolve/resolved-dns-search-domain.c
@@ -19,7 +19,7 @@ int dns_search_domain_new(
assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
assert(name);
- r = dns_name_normalize(name, &normalized);
+ r = dns_name_normalize(name, 0, &normalized);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index e05ada29a8..3e69741b88 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -43,16 +43,18 @@ int dns_server_new(
return -E2BIG;
}
- s = new0(DnsServer, 1);
+ s = new(DnsServer, 1);
if (!s)
return -ENOMEM;
- s->n_ref = 1;
- s->manager = m;
- s->type = type;
- s->family = family;
- s->address = *in_addr;
- s->ifindex = ifindex;
+ *s = (DnsServer) {
+ .n_ref = 1,
+ .manager = m,
+ .type = type,
+ .family = family,
+ .address = *in_addr,
+ .ifindex = ifindex,
+ };
dns_server_reset_features(s);
@@ -101,7 +103,7 @@ int dns_server_new(
static DnsServer* dns_server_free(DnsServer *s) {
assert(s);
- dns_stream_unref(s->stream);
+ dns_server_unref_stream(s);
#if ENABLE_DNS_OVER_TLS
dnstls_server_free(s);
@@ -156,6 +158,9 @@ void dns_server_unlink(DnsServer *s) {
if (s->manager->current_dns_server == s)
manager_set_dns_server(s->manager, NULL);
+ /* No need to keep a default stream around anymore */
+ dns_server_unref_stream(s);
+
dns_server_unref(s);
}
@@ -824,6 +829,9 @@ void dns_server_reset_features(DnsServer *s) {
s->warned_downgrade = false;
dns_server_reset_counters(s);
+
+ /* Let's close the default stream, so that we reprobe with the new features */
+ dns_server_unref_stream(s);
}
void dns_server_reset_features_all(DnsServer *s) {
@@ -884,6 +892,20 @@ void dns_server_dump(DnsServer *s, FILE *f) {
yes_no(s->packet_rrsig_missing));
}
+void dns_server_unref_stream(DnsServer *s) {
+ DnsStream *ref;
+
+ assert(s);
+
+ /* Detaches the default stream of this server. Some special care needs to be taken here, as that stream and
+ * this server reference each other. First, take the stream out of the server. It's destructor will check if it
+ * is registered with us, hence let's invalidate this separatly, so that it is already unregistered. */
+ ref = TAKE_PTR(s->stream);
+
+ /* And then, unref it */
+ dns_stream_unref(ref);
+}
+
static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
[DNS_SERVER_SYSTEM] = "system",
[DNS_SERVER_FALLBACK] = "fallback",
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index fda1251049..6e73f32df4 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -54,6 +54,8 @@ struct DnsServer {
int ifindex; /* for IPv6 link-local DNS servers */
char *server_string;
+
+ /* The long-lived stream towards this server. */
DnsStream *stream;
#if ENABLE_DNS_OVER_TLS
@@ -149,3 +151,5 @@ void dns_server_reset_features(DnsServer *s);
void dns_server_reset_features_all(DnsServer *s);
void dns_server_dump(DnsServer *s, FILE *f);
+
+void dns_server_unref_stream(DnsServer *s);
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 26d4663d74..aee339a4c8 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -17,6 +17,9 @@ static void dns_stream_stop(DnsStream *s) {
s->io_event_source = sd_event_source_unref(s->io_event_source);
s->timeout_event_source = sd_event_source_unref(s->timeout_event_source);
s->fd = safe_close(s->fd);
+
+ /* Disconnect us from the server object if we are now not usable anymore */
+ dns_stream_detach(s);
}
static int dns_stream_update_io(DnsStream *s) {
@@ -46,6 +49,8 @@ static int dns_stream_update_io(DnsStream *s) {
}
static int dns_stream_complete(DnsStream *s, int error) {
+ _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */
+
assert(s);
#if ENABLE_DNS_OVER_TLS
@@ -59,6 +64,8 @@ static int dns_stream_complete(DnsStream *s, int error) {
#endif
dns_stream_stop(s);
+ dns_stream_detach(s);
+
if (s->complete)
s->complete(s, error);
else /* the default action if no completion function is set is to close the stream */
@@ -193,7 +200,7 @@ static int dns_stream_identify(DnsStream *s) {
}
ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags) {
- ssize_t r;
+ ssize_t m;
assert(s);
assert(iov);
@@ -203,13 +210,13 @@ ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt,
ssize_t ss;
size_t i;
- r = 0;
+ m = 0;
for (i = 0; i < iovcnt; i++) {
ss = dnstls_stream_write(s, iov[i].iov_base, iov[i].iov_len);
if (ss < 0)
return ss;
- r += ss;
+ m += ss;
if (ss != (ssize_t) iov[i].iov_len)
continue;
}
@@ -223,28 +230,28 @@ ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt,
.msg_namelen = s->tfo_salen
};
- r = sendmsg(s->fd, &hdr, MSG_FASTOPEN);
- if (r < 0) {
+ m = sendmsg(s->fd, &hdr, MSG_FASTOPEN);
+ if (m < 0) {
if (errno == EOPNOTSUPP) {
s->tfo_salen = 0;
- r = connect(s->fd, &s->tfo_address.sa, s->tfo_salen);
- if (r < 0)
+ if (connect(s->fd, &s->tfo_address.sa, s->tfo_salen) < 0)
return -errno;
- r = -EAGAIN;
- } else if (errno == EINPROGRESS)
- r = -EAGAIN;
- else
- r = -errno;
+ return -EAGAIN;
+ }
+ if (errno == EINPROGRESS)
+ return -EAGAIN;
+
+ return -errno;
} else
s->tfo_salen = 0; /* connection is made */
} else {
- r = writev(s->fd, iov, iovcnt);
- if (r < 0)
- r = -errno;
+ m = writev(s->fd, iov, iovcnt);
+ if (m < 0)
+ return -errno;
}
- return r;
+ return m;
}
static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
@@ -258,7 +265,7 @@ static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
{
ss = read(s->fd, buf, count);
if (ss < 0)
- ss = -errno;
+ return -errno;
}
return ss;
@@ -273,7 +280,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
}
static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- DnsStream *s = userdata;
+ _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
int r;
assert(s);
@@ -281,18 +288,16 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
#if ENABLE_DNS_OVER_TLS
if (s->encrypted) {
r = dnstls_stream_on_io(s, revents);
-
if (r == DNSTLS_STREAM_CLOSED)
return 0;
- else if (r == -EAGAIN)
+ if (r == -EAGAIN)
return dns_stream_update_io(s);
- else if (r < 0) {
+ if (r < 0)
return dns_stream_complete(s, -r);
- } else {
- r = dns_stream_update_io(s);
- if (r < 0)
- return r;
- }
+
+ r = dns_stream_update_io(s);
+ if (r < 0)
+ return r;
}
#endif
@@ -430,9 +435,6 @@ static DnsStream *dns_stream_free(DnsStream *s) {
dns_stream_stop(s);
- if (s->server && s->server->stream == s)
- s->server->stream = NULL;
-
if (s->manager) {
LIST_REMOVE(streams, s->manager->dns_streams, s);
s->manager->n_dns_streams--;
@@ -457,28 +459,37 @@ static DnsStream *dns_stream_free(DnsStream *s) {
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsStream, dns_stream, dns_stream_free);
-int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address) {
+int dns_stream_new(
+ Manager *m,
+ DnsStream **ret,
+ DnsProtocol protocol,
+ int fd,
+ const union sockaddr_union *tfo_address) {
+
_cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
int r;
assert(m);
+ assert(ret);
assert(fd >= 0);
if (m->n_dns_streams > DNS_STREAMS_MAX)
return -EBUSY;
- s = new0(DnsStream, 1);
+ s = new(DnsStream, 1);
if (!s)
return -ENOMEM;
+ *s = (DnsStream) {
+ .n_ref = 1,
+ .fd = -1,
+ .protocol = protocol,
+ };
+
r = ordered_set_ensure_allocated(&s->write_queue, &dns_packet_hash_ops);
if (r < 0)
return r;
- s->n_ref = 1;
- s->fd = -1;
- s->protocol = protocol;
-
r = sd_event_add_io(m->event, &s->io_event_source, fd, EPOLLIN, on_stream_io, s);
if (r < 0)
return r;
@@ -497,15 +508,16 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, co
(void) sd_event_source_set_description(s->timeout_event_source, "dns-stream-timeout");
LIST_PREPEND(streams, m->dns_streams, s);
+ m->n_dns_streams++;
s->manager = m;
+
s->fd = fd;
+
if (tfo_address) {
s->tfo_address = *tfo_address;
s->tfo_salen = tfo_address->sa.sa_family == AF_INET6 ? sizeof(tfo_address->in6) : sizeof(tfo_address->in);
}
- m->n_dns_streams++;
-
*ret = TAKE_PTR(s);
return 0;
@@ -515,6 +527,7 @@ int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
int r;
assert(s);
+ assert(p);
r = ordered_set_put(s->write_queue, p);
if (r < 0)
@@ -524,3 +537,31 @@ int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
return dns_stream_update_io(s);
}
+
+DnsPacket *dns_stream_take_read_packet(DnsStream *s) {
+ assert(s);
+
+ if (!s->read_packet)
+ return NULL;
+
+ if (s->n_read < sizeof(s->read_size))
+ return NULL;
+
+ if (s->n_read < sizeof(s->read_size) + be16toh(s->read_size))
+ return NULL;
+
+ s->n_read = 0;
+ return TAKE_PTR(s->read_packet);
+}
+
+void dns_stream_detach(DnsStream *s) {
+ assert(s);
+
+ if (!s->server)
+ return;
+
+ if (s->server->stream != s)
+ return;
+
+ dns_server_unref_stream(s->server);
+}
diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h
index 46d2704afe..f18fc919e7 100644
--- a/src/resolve/resolved-dns-stream.h
+++ b/src/resolve/resolved-dns-stream.h
@@ -53,13 +53,12 @@ struct DnsStream {
size_t n_written, n_read;
OrderedSet *write_queue;
- int (*on_connection)(DnsStream *s);
int (*on_packet)(DnsStream *s);
int (*complete)(DnsStream *s, int error);
LIST_HEAD(DnsTransaction, transactions); /* when used by the transaction logic */
DnsServer *server; /* when used by the transaction logic */
- DnsQuery *query; /* when used by the DNS stub logic */
+ DnsQuery *query; /* when used by the DNS stub logic */
/* used when DNS-over-TLS is enabled */
bool encrypted:1;
@@ -87,3 +86,7 @@ static inline bool DNS_STREAM_QUEUED(DnsStream *s) {
return !!s->write_packet;
}
+
+DnsPacket *dns_stream_take_read_packet(DnsStream *s);
+
+void dns_stream_detach(DnsStream *s);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 015aabaf9b..a00716cd85 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -437,13 +437,17 @@ static int manager_dns_stub_udp_fd(Manager *m) {
}
static int on_dns_stub_stream_packet(DnsStream *s) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+
assert(s);
- assert(s->read_packet);
- if (dns_packet_validate_query(s->read_packet) > 0) {
- log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
+ p = dns_stream_take_read_packet(s);
+ assert(p);
+
+ if (dns_packet_validate_query(p) > 0) {
+ log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(p));
- dns_stub_process_query(s->manager, s, s->read_packet);
+ dns_stub_process_query(s->manager, s, p);
} else
log_debug("Invalid DNS stub TCP packet, ignoring.");
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index ddab2850df..cc748ac95e 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -503,59 +503,54 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) {
}
static int on_stream_complete(DnsStream *s, int error) {
- _cleanup_(dns_stream_unrefp) DnsStream *p = NULL;
- DnsTransaction *t, *n;
- int r = 0;
-
- /* Do not let new transactions use this stream */
- if (s->server && s->server->stream == s)
- p = TAKE_PTR(s->server->stream);
+ assert(s);
if (ERRNO_IS_DISCONNECT(error) && s->protocol != DNS_PROTOCOL_LLMNR) {
- usec_t usec;
-
log_debug_errno(error, "Connection failure for DNS TCP stream: %m");
if (s->transactions) {
+ DnsTransaction *t;
+
t = s->transactions;
- assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level);
}
}
- LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions)
- if (error != 0)
+ if (error != 0) {
+ DnsTransaction *t, *n;
+
+ LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions)
on_transaction_stream_error(t, error);
- else if (DNS_PACKET_ID(s->read_packet) == t->id)
- /* As each transaction have a unique id the return code is only set once */
- r = dns_transaction_on_stream_packet(t, s->read_packet);
+ }
- return r;
+ return 0;
}
-static int dns_stream_on_packet(DnsStream *s) {
+static int on_stream_packet(DnsStream *s) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- int r = 0;
DnsTransaction *t;
+ assert(s);
+
/* Take ownership of packet to be able to receive new packets */
- p = TAKE_PTR(s->read_packet);
- s->n_read = 0;
+ p = dns_stream_take_read_packet(s);
+ assert(p);
t = hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
+ if (t)
+ return dns_transaction_on_stream_packet(t, p);
/* Ignore incorrect transaction id as transaction can have been canceled */
- if (t)
- r = dns_transaction_on_stream_packet(t, p);
- else {
- if (dns_packet_validate_reply(p) <= 0) {
- log_debug("Invalid TCP reply packet.");
- on_stream_complete(s, 0);
- }
- return 0;
+ if (dns_packet_validate_reply(p) <= 0) {
+ log_debug("Invalid TCP reply packet.");
+ on_stream_complete(s, 0);
}
- return r;
+ return 0;
+}
+
+static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
+ return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53;
}
static int dns_transaction_emit_tcp(DnsTransaction *t) {
@@ -585,7 +580,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted))
s = dns_stream_ref(t->server->stream);
else
- fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53, &sa);
+ fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
break;
@@ -629,7 +624,9 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
fd = -1;
#if ENABLE_DNS_OVER_TLS
- if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) {
+ if (t->scope->protocol == DNS_PROTOCOL_DNS &&
+ DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) {
+
assert(t->server);
r = dnstls_stream_connect_tls(s, t->server);
if (r < 0)
@@ -638,13 +635,13 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
#endif
if (t->server) {
- dns_stream_unref(t->server->stream);
+ dns_server_unref_stream(t->server);
t->server->stream = dns_stream_ref(s);
s->server = dns_server_ref(t->server);
}
s->complete = on_stream_complete;
- s->on_packet = dns_stream_on_packet;
+ s->on_packet = on_stream_packet;
/* The interface index is difficult to determine if we are
* connecting to the local host, hence fill this in right away
diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c
index ea96255dc1..2c28ec227a 100644
--- a/src/resolve/resolved-dnssd.c
+++ b/src/resolve/resolved-dnssd.c
@@ -228,10 +228,10 @@ int dnssd_update_rrs(DnssdService *s) {
if (r < 0)
return r;
- r = dns_name_concat(s->type, "local", &service_name);
+ r = dns_name_concat(s->type, "local", 0, &service_name);
if (r < 0)
return r;
- r = dns_name_concat(n, service_name, &full_name);
+ r = dns_name_concat(n, service_name, 0, &full_name);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c
index c5c180943d..01cde4acf7 100644
--- a/src/resolve/resolved-etc-hosts.c
+++ b/src/resolve/resolved-etc-hosts.c
@@ -46,19 +46,20 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
r = extract_first_word(&line, &address_str, NULL, EXTRACT_RELAX);
if (r < 0)
- return log_error_errno(r, "Couldn't extract address, in line /etc/hosts:%u.", nr);
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Premature end of line, in line /etc/hosts:%u.",
- nr);
+ return log_error_errno(r, "/etc/hosts:%u: failed to extract address: %m", nr);
+ assert(r > 0); /* We already checked that the line is not empty, so it should contain *something* */
r = in_addr_ifindex_from_string_auto(address_str, &address.family, &address.address, NULL);
- if (r < 0)
- return log_error_errno(r, "Address '%s' is invalid, in line /etc/hosts:%u.", address_str, nr);
+ if (r < 0) {
+ log_warning_errno(r, "/etc/hosts:%u: address '%s' is invalid, ignoring: %m", nr, address_str);
+ return 0;
+ }
r = in_addr_is_null(address.family, &address.address);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_warning_errno(r, "/etc/hosts:%u: address '%s' is invalid, ignoring: %m", nr, address_str);
+ return 0;
+ }
if (r > 0)
/* This is an 0.0.0.0 or :: item, which we assume means that we shall map the specified hostname to
* nothing. */
@@ -92,16 +93,18 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX);
if (r < 0)
- return log_error_errno(r, "Couldn't extract host name, in line /etc/hosts:%u.", nr);
+ return log_error_errno(r, "/etc/hosts:%u: couldn't extract host name: %m", nr);
if (r == 0)
break;
- r = dns_name_is_valid(name);
- if (r <= 0)
- return log_error_errno(r, "Hostname %s is not valid, ignoring, in line /etc/hosts:%u.", name, nr);
-
found = true;
+ r = dns_name_is_valid_ldh(name);
+ if (r <= 0) {
+ log_warning_errno(r, "/etc/hosts:%u: hostname \"%s\" is not valid, ignoring.", nr, name);
+ continue;
+ }
+
if (is_localhost(name))
/* Suppress the "localhost" line that is often seen */
continue;
@@ -152,9 +155,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
}
if (!found)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Line is missing any host names, in line /etc/hosts:%u.",
- nr);
+ log_warning("/etc/hosts:%u: line is missing any host names", nr);
return 0;
}
@@ -176,11 +177,13 @@ int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
nr++;
+ l = strchr(line, '#');
+ if (l)
+ *l = '\0';
+
l = strstrip(line);
if (isempty(l))
continue;
- if (l[0] == '#')
- continue;
r = parse_line(&t, nr, l);
if (r < 0)
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index 65f5ceecd0..dfa55c577c 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -260,18 +260,21 @@ int manager_llmnr_ipv6_udp_fd(Manager *m) {
}
static int on_llmnr_stream_packet(DnsStream *s) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsScope *scope;
assert(s);
- assert(s->read_packet);
- scope = manager_find_scope(s->manager, s->read_packet);
+ p = dns_stream_take_read_packet(s);
+ assert(p);
+
+ scope = manager_find_scope(s->manager, p);
if (!scope)
log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
- else if (dns_packet_validate_query(s->read_packet) > 0) {
- log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
+ else if (dns_packet_validate_query(p) > 0) {
+ log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(p));
- dns_scope_process_query(scope, s, s->read_packet);
+ dns_scope_process_query(scope, s, p);
} else
log_debug("Invalid LLMNR TCP packet, ignoring.");
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 23a7b87801..1f8c47ccbe 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -334,7 +334,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return log_debug_errno(r, "Can't determine system hostname: %m");
p = h;
- r = dns_label_unescape(&p, label, sizeof label);
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
return log_error_errno(r, "Failed to unescape host name: %m");
if (r == 0)
@@ -372,7 +372,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"System hostname is 'localhost', ignoring.");
- r = dns_name_concat(n, "local", mdns_hostname);
+ r = dns_name_concat(n, "local", 0, mdns_hostname);
if (r < 0)
return log_error_errno(r, "Failed to determine mDNS hostname: %m");
@@ -404,7 +404,7 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
assert(mdns_hostname);
p = fallback_hostname();
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
return log_error_errno(r, "Failed to unescape fallback host name: %m");
@@ -414,7 +414,7 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
if (r < 0)
return log_error_errno(r, "Failed to escape fallback hostname: %m");
- r = dns_name_concat(n, "local", &m);
+ r = dns_name_concat(n, "local", 0, &m);
if (r < 0)
return log_error_errno(r, "Failed to concatenate mDNS hostname: %m");
@@ -1148,7 +1148,7 @@ int manager_next_hostname(Manager *m) {
if (r < 0)
return r;
- r = dns_name_concat(h, "local", &k);
+ r = dns_name_concat(h, "local", 0, &k);
if (r < 0)
return r;
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 755477096d..f4efddf8e5 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -4,6 +4,8 @@
#include "sd-event.h"
#include "capability-util.h"
+#include "daemon-util.h"
+#include "main-func.h"
#include "mkdir.h"
#include "resolved-conf.h"
#include "resolved-manager.h"
@@ -12,7 +14,8 @@
#include "signal-util.h"
#include "user-util.h"
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
const char *user = "systemd-resolve";
uid_t uid;
@@ -21,32 +24,23 @@ int main(int argc, char *argv[]) {
log_setup_service();
- if (argc != 1) {
- log_error("This program takes no arguments.");
- r = -EINVAL;
- goto finish;
- }
+ if (argc != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
umask(0022);
r = mac_selinux_init();
- if (r < 0) {
- log_error_errno(r, "SELinux setup failed: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "SELinux setup failed: %m");
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
- if (r < 0) {
- log_error_errno(r, "Cannot resolve user name %s: %m", user);
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot resolve user name %s: %m", user);
/* Always create the directory where resolv.conf will live */
r = mkdir_safe_label("/run/systemd/resolve", 0755, uid, gid, MKDIR_WARN_MODE);
- if (r < 0) {
- log_error_errno(r, "Could not create runtime directory: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create runtime directory: %m");
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
* privileges are already dropped. */
@@ -58,22 +52,18 @@ int main(int argc, char *argv[]) {
(UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
(UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to drop privileges: %m");
}
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
r = manager_new(&m);
- if (r < 0) {
- log_error_errno(r, "Could not create manager: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create manager: %m");
r = manager_start(m);
- if (r < 0) {
- log_error_errno(r, "Failed to start manager: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to start manager: %m");
/* Write finish default resolv.conf to avoid a dangling symlink */
(void) manager_write_resolv_conf(m);
@@ -82,27 +72,18 @@ int main(int argc, char *argv[]) {
/* Let's drop the remaining caps now */
r = capability_bounding_set_drop(0, true);
- if (r < 0) {
- log_error_errno(r, "Failed to drop remaining caps: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to drop remaining caps: %m");
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
+ notify_stop = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
r = sd_event_loop(m->event);
- if (r < 0) {
- log_error_errno(r, "Event loop failed: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Event loop failed: %m");
- sd_event_get_exit_code(m->event, &r);
+ (void) sd_event_get_exit_code(m->event, &r);
-finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return r;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c
index 6130a036fd..dbff889e3e 100644
--- a/src/resolve/test-resolved-etc-hosts.c
+++ b/src/resolve/test-resolved-etc-hosts.c
@@ -1,14 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "log.h"
#include "resolved-etc-hosts.h"
+#include "strv.h"
#include "tmpfile-util.h"
static void test_parse_etc_hosts_system(void) {
_cleanup_fclose_ FILE *f = NULL;
+ log_info("/* %s */", __func__);
+
f = fopen("/etc/hosts", "re");
if (!f) {
assert_se(errno == ENOENT);
@@ -19,59 +27,98 @@ static void test_parse_etc_hosts_system(void) {
assert_se(etc_hosts_parse(&hosts, f) == 0);
}
-static void test_parse_etc_hosts(const char *fname) {
+#define address_equal_4(_addr, _address) \
+ ((_addr)->family == AF_INET && \
+ !memcmp(&(_addr)->address.in, &(struct in_addr) { .s_addr = (_address) }, 4))
+
+#define address_equal_6(_addr, ...) \
+ ((_addr)->family == AF_INET6 && \
+ !memcmp(&(_addr)->address.in6, &(struct in6_addr) { .s6_addr = __VA_ARGS__}, 16) )
+
+static void test_parse_etc_hosts(void) {
_cleanup_(unlink_tempfilep) char
t[] = "/tmp/test-resolved-etc-hosts.XXXXXX";
+ log_info("/* %s */", __func__);
+
int fd;
_cleanup_fclose_ FILE *f;
-
- if (fname) {
- f = fopen(fname, "re");
- assert_se(f);
- } else {
- fd = mkostemp_safe(t);
- assert_se(fd >= 0);
-
- f = fdopen(fd, "r+");
- assert_se(f);
- fputs("1.2.3.4 some.where\n", f);
- fputs("1.2.3.5 some.where\n", f);
- fputs("::0 some.where some.other\n", f);
- fputs("0.0.0.0 black.listed\n", f);
- fputs("::5 some.where some.other foobar.foo.foo\n", f);
- fputs(" \n", f);
- fflush(f);
- rewind(f);
- }
+ const char *s;
+
+ fd = mkostemp_safe(t);
+ assert_se(fd >= 0);
+
+ f = fdopen(fd, "r+");
+ assert_se(f);
+ fputs("1.2.3.4 some.where\n"
+ "1.2.3.5 some.where\n"
+ "1.2.3.6 dash dash-dash.where-dash\n"
+ "1.2.3.7 bad-dash- -bad-dash -bad-dash.bad-\n"
+ "1.2.3.8\n"
+ "1.2.3.9 before.comment # within.comment\n"
+ "1.2.3.10 before.comment#within.comment2\n"
+ "1.2.3.11 before.comment# within.comment3\n"
+ "1.2.3.12 before.comment#\n"
+ "1.2.3 short.address\n"
+ "1.2.3.4.5 long.address\n"
+ "1::2::3 multi.colon\n"
+
+ "::0 some.where some.other\n"
+ "0.0.0.0 black.listed\n"
+ "::5\t\t\t \tsome.where\tsome.other foobar.foo.foo\t\t\t\n"
+ " \n", f);
+ assert_se(fflush_and_check(f) >= 0);
+ rewind(f);
_cleanup_(etc_hosts_free) EtcHosts hosts = {};
assert_se(etc_hosts_parse(&hosts, f) == 0);
- if (fname)
- return;
-
EtcHostsItemByName *bn;
assert_se(bn = hashmap_get(hosts.by_name, "some.where"));
assert_se(bn->n_addresses == 3);
assert_se(bn->n_allocated >= 3);
+ assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.4")));
+ assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.5")));
+ assert_se(address_equal_6(bn->addresses[2], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
- assert_se(bn->addresses[0]->family == AF_INET);
- assert_se(memcmp(&bn->addresses[0]->address.in,
- &(struct in_addr) { .s_addr = htobe32(0x01020304) }, 4) == 0);
- assert_se(bn->addresses[1]->family == AF_INET);
- assert_se(memcmp(&bn->addresses[1]->address.in,
- &(struct in_addr) { .s_addr = htobe32(0x01020305) }, 4) == 0);
- assert_se(bn->addresses[2]->family == AF_INET6);
- assert_se(memcmp(&bn->addresses[2]->address.in6,
- &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+ assert_se(bn = hashmap_get(hosts.by_name, "dash"));
+ assert_se(bn->n_addresses == 1);
+ assert_se(bn->n_allocated >= 1);
+ assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
+
+ assert_se(bn = hashmap_get(hosts.by_name, "dash-dash.where-dash"));
+ assert_se(bn->n_addresses == 1);
+ assert_se(bn->n_allocated >= 1);
+ assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
+
+ /* See https://tools.ietf.org/html/rfc1035#section-2.3.1 */
+ FOREACH_STRING(s, "bad-dash-", "-bad-dash", "-bad-dash.bad-")
+ assert_se(!hashmap_get(hosts.by_name, s));
+
+ assert_se(bn = hashmap_get(hosts.by_name, "before.comment"));
+ assert_se(bn->n_addresses == 4);
+ assert_se(bn->n_allocated >= 4);
+ assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.9")));
+ assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.10")));
+ assert_se(address_equal_4(bn->addresses[2], inet_addr("1.2.3.11")));
+ assert_se(address_equal_4(bn->addresses[3], inet_addr("1.2.3.12")));
+
+ assert(!hashmap_get(hosts.by_name, "within.comment"));
+ assert(!hashmap_get(hosts.by_name, "within.comment2"));
+ assert(!hashmap_get(hosts.by_name, "within.comment3"));
+ assert(!hashmap_get(hosts.by_name, "#"));
+
+ assert(!hashmap_get(hosts.by_name, "short.address"));
+ assert(!hashmap_get(hosts.by_name, "long.address"));
+ assert(!hashmap_get(hosts.by_name, "multi.colon"));
+ assert_se(!set_contains(hosts.no_address, "short.address"));
+ assert_se(!set_contains(hosts.no_address, "long.address"));
+ assert_se(!set_contains(hosts.no_address, "multi.colon"));
assert_se(bn = hashmap_get(hosts.by_name, "some.other"));
assert_se(bn->n_addresses == 1);
assert_se(bn->n_allocated >= 1);
- assert_se(bn->addresses[0]->family == AF_INET6);
- assert_se(memcmp(&bn->addresses[0]->address.in6,
- &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+ assert_se(address_equal_6(bn->addresses[0], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
assert_se( set_contains(hosts.no_address, "some.where"));
assert_se( set_contains(hosts.no_address, "some.other"));
@@ -79,14 +126,26 @@ static void test_parse_etc_hosts(const char *fname) {
assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
}
+static void test_parse_file(const char *fname) {
+ _cleanup_(etc_hosts_free) EtcHosts hosts = {};
+ _cleanup_fclose_ FILE *f;
+
+ log_info("/* %s(\"%s\") */", __func__, fname);
+
+ assert_se(f = fopen(fname, "re"));
+ assert_se(etc_hosts_parse(&hosts, f) == 0);
+}
+
int main(int argc, char **argv) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
- if (argc == 1)
+ if (argc == 1) {
test_parse_etc_hosts_system();
- test_parse_etc_hosts(argv[1]);
+ test_parse_etc_hosts();
+ } else
+ test_parse_file(argv[1]);
return 0;
}
diff --git a/src/shared/daemon-util.h b/src/shared/daemon-util.h
new file mode 100644
index 0000000000..5e9eca1d9e
--- /dev/null
+++ b/src/shared/daemon-util.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "sd-daemon.h"
+
+#define NOTIFY_READY "READY=1\n" "STATUS=Processing requests..."
+#define NOTIFY_STOPPING "STOPPING=1\n" "STATUS=Shutting down..."
+
+static inline const char *notify_start(const char *start, const char *stop) {
+ if (start)
+ (void) sd_notify(false, start);
+
+ return stop;
+}
+
+/* This is intended to be used with _cleanup_ attribute. */
+static inline void notify_on_cleanup(const char **p) {
+ if (p)
+ (void) sd_notify(false, *p);
+}
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 5ff60fe191..4b31cb36ed 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -17,6 +17,7 @@
#include "dns-domain.h"
#include "hashmap.h"
#include "hexdecoct.h"
+#include "hostname-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "parse-util.h"
@@ -24,9 +25,9 @@
#include "strv.h"
#include "utf8.h"
-int dns_label_unescape(const char **name, char *dest, size_t sz) {
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags) {
const char *n;
- char *d;
+ char *d, last_char = 0;
int r = 0;
assert(name);
@@ -36,13 +37,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
d = dest;
for (;;) {
- if (*n == '.') {
- n++;
- break;
- }
+ if (*n == 0 || *n == '.') {
+ if (FLAGS_SET(flags, DNS_LABEL_LDH) && last_char == '-')
+ /* Trailing dash */
+ return -EINVAL;
- if (*n == 0)
+ if (*n == '.')
+ n++;
break;
+ }
if (r >= DNS_LABEL_MAX)
return -EINVAL;
@@ -52,6 +55,8 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
if (*n == '\\') {
/* Escaped character */
+ if (FLAGS_SET(flags, DNS_LABEL_NO_ESCAPES))
+ return -EINVAL;
n++;
@@ -62,6 +67,10 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
else if (IN_SET(*n, '\\', '.')) {
/* Escaped backslash or dot */
+ if (FLAGS_SET(flags, DNS_LABEL_LDH))
+ return -EINVAL;
+
+ last_char = *n;
if (d)
*(d++) = *n;
sz--;
@@ -90,6 +99,11 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
if (k > 255)
return -EINVAL;
+ if (FLAGS_SET(flags, DNS_LABEL_LDH) &&
+ !valid_ldh_char((char) k))
+ return -EINVAL;
+
+ last_char = (char) k;
if (d)
*(d++) = (char) k;
sz--;
@@ -103,6 +117,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
/* Normal character */
+ if (FLAGS_SET(flags, DNS_LABEL_LDH)) {
+ if (!valid_ldh_char(*n))
+ return -EINVAL;
+ if (r == 0 && *n == '-')
+ /* Leading dash */
+ return -EINVAL;
+ }
+
+ last_char = *n;
if (d)
*(d++) = *n;
sz--;
@@ -184,7 +207,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
terminal--;
}
- r = dns_label_unescape(&name, dest, sz);
+ r = dns_label_unescape(&name, dest, sz, 0);
if (r < 0)
return r;
@@ -378,7 +401,7 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
}
#endif
-int dns_name_concat(const char *a, const char *b, char **_ret) {
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
const char *p;
@@ -395,7 +418,7 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
for (;;) {
char label[DNS_LABEL_MAX];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, flags);
if (r < 0)
return r;
if (r == 0) {
@@ -468,7 +491,7 @@ void dns_name_hash_func(const char *p, struct siphash *state) {
for (;;) {
char label[DNS_LABEL_MAX+1];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
break;
if (r == 0)
@@ -521,11 +544,11 @@ int dns_name_equal(const char *x, const char *y) {
for (;;) {
char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
- r = dns_label_unescape(&x, la, sizeof(la));
+ r = dns_label_unescape(&x, la, sizeof la, 0);
if (r < 0)
return r;
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ q = dns_label_unescape(&y, lb, sizeof lb, 0);
if (q < 0)
return q;
@@ -552,14 +575,14 @@ int dns_name_endswith(const char *name, const char *suffix) {
for (;;) {
char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
- r = dns_label_unescape(&n, ln, sizeof(ln));
+ r = dns_label_unescape(&n, ln, sizeof ln, 0);
if (r < 0)
return r;
if (!saved_n)
saved_n = n;
- q = dns_label_unescape(&s, ls, sizeof(ls));
+ q = dns_label_unescape(&s, ls, sizeof ls, 0);
if (q < 0)
return q;
@@ -590,13 +613,13 @@ int dns_name_startswith(const char *name, const char *prefix) {
for (;;) {
char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
- r = dns_label_unescape(&p, lp, sizeof(lp));
+ r = dns_label_unescape(&p, lp, sizeof lp, 0);
if (r < 0)
return r;
if (r == 0)
return true;
- q = dns_label_unescape(&n, ln, sizeof(ln));
+ q = dns_label_unescape(&n, ln, sizeof ln, 0);
if (q < 0)
return q;
@@ -625,14 +648,14 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
if (!saved_before)
saved_before = n;
- r = dns_label_unescape(&n, ln, sizeof(ln));
+ r = dns_label_unescape(&n, ln, sizeof ln, 0);
if (r < 0)
return r;
if (!saved_after)
saved_after = n;
- q = dns_label_unescape(&s, ls, sizeof(ls));
+ q = dns_label_unescape(&s, ls, sizeof ls, 0);
if (q < 0)
return q;
@@ -655,7 +678,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
/* Found it! Now generate the new name */
prefix = strndupa(name, saved_before - name);
- r = dns_name_concat(prefix, new_suffix, ret);
+ r = dns_name_concat(prefix, new_suffix, 0, ret);
if (r < 0)
return r;
@@ -733,7 +756,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
for (i = 0; i < ELEMENTSOF(a); i++) {
char label[DNS_LABEL_MAX+1];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
return r;
if (r == 0)
@@ -770,7 +793,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
char label[DNS_LABEL_MAX+1];
int x, y;
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r <= 0)
return r;
if (r != 1)
@@ -779,7 +802,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
if (x < 0)
return -EINVAL;
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r <= 0)
return r;
if (r != 1)
@@ -847,7 +870,7 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
* dns_label_unescape() returns 0 when it hits the end
* of the domain name, which we rely on here to encode
* the trailing NUL byte. */
- r = dns_label_unescape(&domain, (char *) out, len);
+ r = dns_label_unescape(&domain, (char *) out, len, 0);
if (r < 0)
return r;
@@ -914,7 +937,7 @@ bool dns_srv_type_is_valid(const char *name) {
/* This more or less implements RFC 6335, Section 5.1 */
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_label_unescape(&name, label, sizeof label, 0);
if (r < 0)
return false;
if (r == 0)
@@ -974,7 +997,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
return -EINVAL;
if (!name)
- return dns_name_concat(type, domain, ret);
+ return dns_name_concat(type, domain, 0, ret);
if (!dns_service_name_is_valid(name))
return -EINVAL;
@@ -983,11 +1006,11 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
if (r < 0)
return r;
- r = dns_name_concat(type, domain, &n);
+ r = dns_name_concat(type, domain, 0, &n);
if (r < 0)
return r;
- return dns_name_concat(escaped, n, ret);
+ return dns_name_concat(escaped, n, 0, ret);
}
static bool dns_service_name_label_is_valid(const char *label, size_t n) {
@@ -1012,7 +1035,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
assert(joined);
/* Get first label from the full name */
- an = dns_label_unescape(&p, a, sizeof(a));
+ an = dns_label_unescape(&p, a, sizeof(a), 0);
if (an < 0)
return an;
@@ -1020,7 +1043,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
x++;
/* If there was a first label, try to get the second one */
- bn = dns_label_unescape(&p, b, sizeof(b));
+ bn = dns_label_unescape(&p, b, sizeof(b), 0);
if (bn < 0)
return bn;
@@ -1029,7 +1052,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
/* If there was a second label, try to get the third one */
q = p;
- cn = dns_label_unescape(&p, c, sizeof(c));
+ cn = dns_label_unescape(&p, c, sizeof(c), 0);
if (cn < 0)
return cn;
@@ -1079,7 +1102,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
d = joined;
finish:
- r = dns_name_normalize(d, &domain);
+ r = dns_name_normalize(d, 0, &domain);
if (r < 0)
return r;
@@ -1224,12 +1247,12 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
}
x = a_labels[n - 1 - k];
- r = dns_label_unescape(&x, la, sizeof(la));
+ r = dns_label_unescape(&x, la, sizeof la, 0);
if (r < 0)
return r;
y = b_labels[m - 1 - k];
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ q = dns_label_unescape(&y, lb, sizeof lb, 0);
if (q < 0)
return q;
@@ -1297,13 +1320,13 @@ int dns_name_apply_idna(const char *name, char **ret) {
for (;;) {
char label[DNS_LABEL_MAX];
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_label_unescape(&name, label, sizeof label, 0);
if (r < 0)
return r;
if (r == 0)
break;
- q = dns_label_apply_idna(label, r, label, sizeof(label));
+ q = dns_label_apply_idna(label, r, label, sizeof label);
if (q < 0)
return q;
if (q > 0)
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 42492ad7c0..6ed512c6b1 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -24,13 +24,18 @@
/* Maximum number of labels per valid hostname */
#define DNS_N_LABELS_MAX 127
-int dns_label_unescape(const char **name, char *dest, size_t sz);
+typedef enum DNSLabelFlags {
+ DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
+ DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */
+} DNSLabelFlags;
+
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
int dns_label_escape_new(const char *p, size_t l, char **ret);
static inline int dns_name_parent(const char **name) {
- return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
+ return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0);
}
#if HAVE_LIBIDN
@@ -38,18 +43,29 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
#endif
-int dns_name_concat(const char *a, const char *b, char **ret);
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret);
-static inline int dns_name_normalize(const char *s, char **ret) {
+static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) {
/* dns_name_concat() normalizes as a side-effect */
- return dns_name_concat(s, NULL, ret);
+ return dns_name_concat(s, NULL, flags, ret);
}
static inline int dns_name_is_valid(const char *s) {
int r;
/* dns_name_normalize() verifies as a side effect */
- r = dns_name_normalize(s, NULL);
+ r = dns_name_normalize(s, 0, NULL);
+ if (r == -EINVAL)
+ return 0;
+ if (r < 0)
+ return r;
+ return 1;
+}
+
+static inline int dns_name_is_valid_ldh(const char *s) {
+ int r;
+
+ r = dns_name_concat(s, NULL, DNS_LABEL_LDH|DNS_LABEL_NO_ESCAPES, NULL);
if (r == -EINVAL)
return 0;
if (r < 0)
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 5917d43ef9..ca2e05325e 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -41,6 +41,7 @@ shared_sources = files('''
cpu-set-util.h
crypt-util.c
crypt-util.h
+ daemon-util.h
dev-setup.c
dev-setup.h
dissect-image.c
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 19f49a5ae6..40fcb2cae3 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3090,6 +3090,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_(wait_context_free) WaitContext wait_context = {};
const char *method, *mode, *one_name, *suffix = NULL;
+ _cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
_cleanup_strv_free_ char **names = NULL;
int r, ret = EXIT_SUCCESS;
sd_bus *bus;
@@ -3186,6 +3187,12 @@ static int start_unit(int argc, char *argv[], void *userdata) {
r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
if (ret == EXIT_SUCCESS && r < 0)
ret = translate_bus_error_to_exit_status(r, &error);
+
+ if (r >= 0 && streq(method, "StopUnit")) {
+ r = strv_push(&stopped_units, *name);
+ if (r < 0)
+ return log_oom();
+ }
}
if (!arg_no_block) {
@@ -3210,8 +3217,8 @@ static int start_unit(int argc, char *argv[], void *userdata) {
/* When stopping units, warn if they can still be triggered by
* another active unit (socket, path, timer) */
- if (!arg_quiet && streq(method, "StopUnit"))
- STRV_FOREACH(name, names)
+ if (!arg_quiet)
+ STRV_FOREACH(name, stopped_units)
(void) check_triggering_units(bus, *name);
}
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index e388552064..bd0d429df6 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -23,6 +23,7 @@
#include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/types.h>
+#include <stdbool.h>
#include "sd-dhcp-lease.h"
#include "sd-event.h"
@@ -127,12 +128,14 @@ int sd_dhcp_client_set_client_id(
size_t data_len);
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len);
int sd_dhcp_client_set_iaid_duid_llt(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint64_t llt_time);
int sd_dhcp_client_set_duid(
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index cbfe5ef390..ead5311705 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -6,39 +6,65 @@
#include "string-util.h"
#include "tests.h"
-static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
+static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret, int ret_ldh) {
char buffer[buffer_sz];
int r;
+ const char *w = what;
- r = dns_label_unescape(&what, buffer, buffer_sz);
+ log_info("%s, %s, %zu, →%d/%d", what, expect, buffer_sz, ret, ret_ldh);
+
+ r = dns_label_unescape(&w, buffer, buffer_sz, 0);
assert_se(r == ret);
+ if (r >= 0)
+ assert_se(streq(buffer, expect));
- if (r < 0)
- return;
+ w = what;
+ r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_LDH);
+ assert_se(r == ret_ldh);
+ if (r >= 0)
+ assert_se(streq(buffer, expect));
- assert_se(streq(buffer, expect));
+ w = what;
+ r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_NO_ESCAPES);
+ const int ret_noe = strchr(what, '\\') ? -EINVAL : ret;
+ assert_se(r == ret_noe);
+ if (r >= 0)
+ assert_se(streq(buffer, expect));
}
static void test_dns_label_unescape(void) {
- test_dns_label_unescape_one("hallo", "hallo", 6, 5);
- test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS);
- test_dns_label_unescape_one("", "", 10, 0);
- test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12);
- test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5);
- test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL);
- test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL);
- test_dns_label_unescape_one("hallo\\032 ", "hallo ", 20, 7);
- test_dns_label_unescape_one(".", "", 20, 0);
- test_dns_label_unescape_one("..", "", 20, -EINVAL);
- test_dns_label_unescape_one(".foobar", "", 20, -EINVAL);
- test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
- test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL);
+ log_info("/* %s */", __func__);
+
+ test_dns_label_unescape_one("hallo", "hallo", 6, 5, 5);
+ test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS, -ENOBUFS);
+ test_dns_label_unescape_one("", "", 10, 0, 0);
+ test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12, -EINVAL);
+ test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5, 5);
+ test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_one("hallo\\032 ", "hallo ", 20, 7, -EINVAL);
+ test_dns_label_unescape_one(".", "", 20, 0, 0);
+ test_dns_label_unescape_one("..", "", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_one(".foobar", "", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_one("foobar.", "foobar", 20, 6, 6);
+ test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_one("foo-bar", "foo-bar", 20, 7, 7);
+ test_dns_label_unescape_one("foo-", "foo-", 20, 4, -EINVAL);
+ test_dns_label_unescape_one("-foo", "-foo", 20, 4, -EINVAL);
+ test_dns_label_unescape_one("-foo-", "-foo-", 20, 5, -EINVAL);
+ test_dns_label_unescape_one("foo-.", "foo-", 20, 4, -EINVAL);
+ test_dns_label_unescape_one("foo.-", "foo", 20, 3, 3);
+ test_dns_label_unescape_one("foo\\032", "foo ", 20, 4, -EINVAL);
+ test_dns_label_unescape_one("foo\\045", "foo-", 20, 4, -EINVAL);
+ test_dns_label_unescape_one("głąb", "głąb", 20, 6, -EINVAL);
}
static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
uint8_t buffer[buffer_sz];
int r;
+ log_info("%s, %s, %zu, →%d", what, expect, buffer_sz, ret);
+
r = dns_name_to_wire_format(what, buffer, buffer_sz, false);
assert_se(r == ret);
@@ -80,6 +106,8 @@ static void test_dns_name_to_wire_format(void) {
9, 'a', '1', '2', '3', '4', '5', '6', '7', '8',
3, 'a', '1', '2', 0 };
+ log_info("/* %s */", __func__);
+
test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0));
test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1));
@@ -100,6 +128,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp
const char *label;
int r;
+ log_info("%s, %s, %s, %zu, %d, %d", what, expect1, expect2, buffer_sz, ret1, ret2);
+
label = what + strlen(what);
r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
@@ -114,6 +144,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp
}
static void test_dns_label_unescape_suffix(void) {
+ log_info("/* %s */", __func__);
+
test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0);
test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS);
test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);
@@ -139,6 +171,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
_cleanup_free_ char *t = NULL;
int r;
+ log_info("%s, %zu, %s, →%d", what, l, expect, ret);
+
r = dns_label_escape_new(what, l, &t);
assert_se(r == ret);
@@ -149,6 +183,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
}
static void test_dns_label_escape(void) {
+ log_info("/* %s */", __func__);
+
test_dns_label_escape_one("", 0, NULL, -EINVAL);
test_dns_label_escape_one("hallo", 5, "hallo", 5);
test_dns_label_escape_one("hallo", 6, "hallo\\000", 9);
@@ -159,7 +195,7 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in
_cleanup_free_ char *t = NULL;
int r;
- r = dns_name_normalize(what, &t);
+ r = dns_name_normalize(what, 0, &t);
assert_se(r == ret);
if (r < 0)
@@ -320,7 +356,7 @@ static void test_dns_name_reverse(void) {
static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) {
_cleanup_free_ char *p = NULL;
- assert_se(dns_name_concat(a, b, &p) == r);
+ assert_se(dns_name_concat(a, b, 0, &p) == r);
assert_se(streq_ptr(p, result));
}
@@ -339,46 +375,68 @@ static void test_dns_name_concat(void) {
test_dns_name_concat_one(NULL, "foo", 0, "foo");
}
-static void test_dns_name_is_valid_one(const char *s, int ret) {
+static void test_dns_name_is_valid_one(const char *s, int ret, int ret_ldh) {
+ log_info("%s, →%d", s, ret);
+
assert_se(dns_name_is_valid(s) == ret);
+ assert_se(dns_name_is_valid_ldh(s) == ret_ldh);
}
static void test_dns_name_is_valid(void) {
- test_dns_name_is_valid_one("foo", 1);
- test_dns_name_is_valid_one("foo.", 1);
- test_dns_name_is_valid_one("foo..", 0);
- test_dns_name_is_valid_one("Foo", 1);
- test_dns_name_is_valid_one("foo.bar", 1);
- test_dns_name_is_valid_one("foo.bar.baz", 1);
- test_dns_name_is_valid_one("", 1);
- test_dns_name_is_valid_one("foo..bar", 0);
- test_dns_name_is_valid_one(".foo.bar", 0);
- test_dns_name_is_valid_one("foo.bar.", 1);
- test_dns_name_is_valid_one("foo.bar..", 0);
- test_dns_name_is_valid_one("\\zbar", 0);
- test_dns_name_is_valid_one("ä", 1);
- test_dns_name_is_valid_one("\n", 0);
+ log_info("/* %s */", __func__);
+
+ test_dns_name_is_valid_one("foo", 1, 1);
+ test_dns_name_is_valid_one("foo.", 1, 1);
+ test_dns_name_is_valid_one("foo..", 0, 0);
+ test_dns_name_is_valid_one("Foo", 1, 1);
+ test_dns_name_is_valid_one("foo.bar", 1, 1);
+ test_dns_name_is_valid_one("foo.bar.baz", 1, 1);
+ test_dns_name_is_valid_one("", 1, 1);
+ test_dns_name_is_valid_one("foo..bar", 0, 0);
+ test_dns_name_is_valid_one(".foo.bar", 0, 0);
+ test_dns_name_is_valid_one("foo.bar.", 1, 1);
+ test_dns_name_is_valid_one("foo.bar..", 0, 0);
+ test_dns_name_is_valid_one("\\zbar", 0, 0);
+ test_dns_name_is_valid_one("ä", 1, 0);
+ test_dns_name_is_valid_one("\n", 0, 0);
+
+ test_dns_name_is_valid_one("dash-", 1, 0);
+ test_dns_name_is_valid_one("-dash", 1, 0);
+ test_dns_name_is_valid_one("dash-dash", 1, 1);
+ test_dns_name_is_valid_one("foo.dash-", 1, 0);
+ test_dns_name_is_valid_one("foo.-dash", 1, 0);
+ test_dns_name_is_valid_one("foo.dash-dash", 1, 1);
+ test_dns_name_is_valid_one("foo.dash-.bar", 1, 0);
+ test_dns_name_is_valid_one("foo.-dash.bar", 1, 0);
+ test_dns_name_is_valid_one("foo.dash-dash.bar", 1, 1);
+ test_dns_name_is_valid_one("dash-.bar", 1, 0);
+ test_dns_name_is_valid_one("-dash.bar", 1, 0);
+ test_dns_name_is_valid_one("dash-dash.bar", 1, 1);
+ test_dns_name_is_valid_one("-.bar", 1, 0);
+ test_dns_name_is_valid_one("foo.-", 1, 0);
/* 256 characters */
- test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0);
+ test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0, 0);
/* 255 characters */
- test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0);
+ test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0, 0);
/* 254 characters */
- test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0);
+ test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0, 0);
/* 253 characters */
- test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1);
+ test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1, 1);
/* label of 64 chars length */
- test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0);
+ test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0, 0);
/* label of 63 chars length */
- test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1);
+ test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1, 1);
}
static void test_dns_service_name_is_valid(void) {
+ log_info("/* %s */", __func__);
+
assert_se(dns_service_name_is_valid("Lennart's Compüter"));
assert_se(dns_service_name_is_valid("piff.paff"));
@@ -390,6 +448,7 @@ static void test_dns_service_name_is_valid(void) {
}
static void test_dns_srv_type_is_valid(void) {
+ log_info("/* %s */", __func__);
assert_se(dns_srv_type_is_valid("_http._tcp"));
assert_se(dns_srv_type_is_valid("_foo-bar._tcp"));
@@ -413,6 +472,7 @@ static void test_dns_srv_type_is_valid(void) {
}
static void test_dnssd_srv_type_is_valid(void) {
+ log_info("/* %s */", __func__);
assert_se(dnssd_srv_type_is_valid("_http._tcp"));
assert_se(dnssd_srv_type_is_valid("_foo-bar._tcp"));
@@ -439,6 +499,8 @@ static void test_dnssd_srv_type_is_valid(void) {
static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) {
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
+ log_info("%s, %s, %s, →%d, %s", a, b, c, r, d);
+
assert_se(dns_service_join(a, b, c, &t) == r);
assert_se(streq_ptr(t, d));
@@ -452,6 +514,8 @@ static void test_dns_service_join_one(const char *a, const char *b, const char *
}
static void test_dns_service_join(void) {
+ log_info("/* %s */", __func__);
+
test_dns_service_join_one("", "", "", -EINVAL, NULL);
test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL);
test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL);
@@ -469,6 +533,8 @@ static void test_dns_service_join(void) {
static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) {
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL;
+ log_info("%s, %s, %s, %s, →%d", joined, a, b, c, r);
+
assert_se(dns_service_split(joined, &x, &y, &z) == r);
assert_se(streq_ptr(x, a));
assert_se(streq_ptr(y, b));
@@ -485,6 +551,8 @@ static void test_dns_service_split_one(const char *joined, const char *a, const
}
static void test_dns_service_split(void) {
+ log_info("/* %s */", __func__);
+
test_dns_service_split_one("", NULL, NULL, ".", 0);
test_dns_service_split_one("foo", NULL, NULL, "foo", 0);
test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0);
@@ -497,11 +565,15 @@ static void test_dns_service_split(void) {
static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) {
_cleanup_free_ char *s = NULL;
+ log_info("%s, %s, %s, →%s", name, old_suffix, new_suffix, result);
+
assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r);
assert_se(streq_ptr(s, result));
}
static void test_dns_name_change_suffix(void) {
+ log_info("/* %s */", __func__);
+
test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo");
test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff");
test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff");
@@ -516,11 +588,15 @@ static void test_dns_name_change_suffix(void) {
static void test_dns_name_suffix_one(const char *name, unsigned n_labels, const char *result, int ret) {
const char *p = NULL;
+ log_info("%s, %d, →%s, %d", name, n_labels, result, ret);
+
assert_se(ret == dns_name_suffix(name, n_labels, &p));
assert_se(streq_ptr(p, result));
}
static void test_dns_name_suffix(void) {
+ log_info("/* %s */", __func__);
+
test_dns_name_suffix_one("foo.bar", 2, "foo.bar", 0);
test_dns_name_suffix_one("foo.bar", 1, "bar", 1);
test_dns_name_suffix_one("foo.bar", 0, "", 2);
@@ -538,10 +614,14 @@ static void test_dns_name_suffix(void) {
}
static void test_dns_name_count_labels_one(const char *name, int n) {
+ log_info("%s, →%d", name, n);
+
assert_se(dns_name_count_labels(name) == n);
}
static void test_dns_name_count_labels(void) {
+ log_info("/* %s */", __func__);
+
test_dns_name_count_labels_one("foo.bar.quux.", 3);
test_dns_name_count_labels_one("foo.bar.quux", 3);
test_dns_name_count_labels_one("foo.bar.", 2);
@@ -554,10 +634,14 @@ static void test_dns_name_count_labels(void) {
}
static void test_dns_name_equal_skip_one(const char *a, unsigned n_labels, const char *b, int ret) {
+ log_info("%s, %u, %s, →%d", a, n_labels, b, ret);
+
assert_se(dns_name_equal_skip(a, n_labels, b) == ret);
}
static void test_dns_name_equal_skip(void) {
+ log_info("/* %s */", __func__);
+
test_dns_name_equal_skip_one("foo", 0, "bar", 0);
test_dns_name_equal_skip_one("foo", 0, "foo", 1);
test_dns_name_equal_skip_one("foo", 1, "foo", 0);
@@ -585,6 +669,8 @@ static void test_dns_name_equal_skip(void) {
}
static void test_dns_name_compare_func(void) {
+ log_info("/* %s */", __func__);
+
assert_se(dns_name_compare_func("", "") == 0);
assert_se(dns_name_compare_func("", ".") == 0);
assert_se(dns_name_compare_func(".", "") == 0);
@@ -600,11 +686,15 @@ static void test_dns_name_compare_func(void) {
static void test_dns_name_common_suffix_one(const char *a, const char *b, const char *result) {
const char *c;
+ log_info("%s, %s, →%s", a, b, result);
+
assert_se(dns_name_common_suffix(a, b, &c) >= 0);
assert_se(streq(c, result));
}
static void test_dns_name_common_suffix(void) {
+ log_info("/* %s */", __func__);
+
test_dns_name_common_suffix_one("", "", "");
test_dns_name_common_suffix_one("foo", "", "");
test_dns_name_common_suffix_one("", "foo", "");
@@ -639,6 +729,7 @@ static void test_dns_name_apply_idna(void) {
#else
const int ret = 0;
#endif
+ log_info("/* %s */", __func__);
/* IDNA2008 forbids names with hyphens in third and fourth positions
* (https://tools.ietf.org/html/rfc5891#section-4.2.3.1).
@@ -676,6 +767,8 @@ static void test_dns_name_apply_idna(void) {
}
static void test_dns_name_is_valid_or_address(void) {
+ log_info("/* %s */", __func__);
+
assert_se(dns_name_is_valid_or_address(NULL) == 0);
assert_se(dns_name_is_valid_or_address("") == 0);
assert_se(dns_name_is_valid_or_address("foobar") > 0);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 75466a1f1c..b3a4b1749c 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -248,11 +248,11 @@ static void test_chase_symlinks(void) {
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chown(q, 0, 0) >= 0);
- assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
+ assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(rmdir(q) >= 0);
assert_se(symlink("/etc/passwd", q) >= 0);
- assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
+ assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(chown(p, 0, 0) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c
index 8ba47d316b..4126a24ceb 100644
--- a/src/test/test-hostname-util.c
+++ b/src/test/test-hostname-util.c
@@ -53,6 +53,12 @@ static void test_hostname_cleanup(void) {
assert_se(streq(hostname_cleanup(s), "foobar.com"));
s = strdupa("foobar.com.");
assert_se(streq(hostname_cleanup(s), "foobar.com"));
+ s = strdupa("foo-bar.-com-.");
+ assert_se(streq(hostname_cleanup(s), "foo-bar.com"));
+ s = strdupa("foo-bar-.-com-.");
+ assert_se(streq(hostname_cleanup(s), "foo-bar--com"));
+ s = strdupa("--foo-bar.-com");
+ assert_se(streq(hostname_cleanup(s), "foo-bar.com"));
s = strdupa("fooBAR");
assert_se(streq(hostname_cleanup(s), "fooBAR"));
s = strdupa("fooBAR.com");
@@ -79,6 +85,8 @@ static void test_hostname_cleanup(void) {
assert_se(streq(hostname_cleanup(s), "foo.bar"));
s = strdupa("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
+ s = strdupa("xxxx........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
}
static void test_read_etc_hostname(void) {
diff --git a/src/test/test-systemd-tmpfiles.py b/src/test/test-systemd-tmpfiles.py
index 28dadd0c5b..83a66e8772 100755
--- a/src/test/test-systemd-tmpfiles.py
+++ b/src/test/test-systemd-tmpfiles.py
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
-# SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1+
#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
import os
import sys
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 4055295555..70774d757b 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -5,8 +5,10 @@
#include "capability-util.h"
#include "clock-util.h"
+#include "daemon-util.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "main-func.h"
#include "mkdir.h"
#include "network-util.h"
#include "process-util.h"
@@ -83,7 +85,8 @@ settime:
return 0;
}
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
+ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
const char *user = "systemd-timesync";
uid_t uid, uid_current;
@@ -95,48 +98,39 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (argc != 1) {
- log_error("This program does not take arguments.");
- r = -EINVAL;
- goto finish;
- }
+ if (argc != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program does not take arguments.");
uid = uid_current = geteuid();
gid = getegid();
if (uid_current == 0) {
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
- if (r < 0) {
- log_error_errno(r, "Cannot resolve user name %s: %m", user);
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot resolve user name %s: %m", user);
}
r = load_clock_timestamp(uid, gid);
if (r < 0)
- goto finish;
+ return r;
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
* privileges are already dropped. */
if (uid_current == 0) {
r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to drop privileges: %m");
}
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m);
- if (r < 0) {
- log_error_errno(r, "Failed to allocate manager: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate manager: %m");
r = manager_connect_bus(m);
- if (r < 0) {
- log_error_errno(r, "Could not connect to bus: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not connect to bus: %m");
if (clock_is_localtime(NULL) > 0) {
log_info("The system is configured to read the RTC time in the local time zone. "
@@ -149,27 +143,24 @@ int main(int argc, char *argv[]) {
log_warning_errno(r, "Failed to parse configuration file: %m");
r = manager_parse_fallback_string(m, NTP_SERVERS);
- if (r < 0) {
- log_error_errno(r, "Failed to parse fallback server strings: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse fallback server strings: %m");
log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
- sd_notify(false,
- "READY=1\n"
- "STATUS=Daemon is running");
+
+ notify_message = notify_start("READY=1\n"
+ "STATUS=Daemon is running",
+ NOTIFY_STOPPING);
if (network_is_online()) {
r = manager_connect(m);
if (r < 0)
- goto finish;
+ return r;
}
r = sd_event_loop(m->event);
- if (r < 0) {
- log_error_errno(r, "Failed to run event loop: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
/* if we got an authoritative time, store it in the file system */
if (m->sync) {
@@ -178,12 +169,9 @@ int main(int argc, char *argv[]) {
log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE);
}
- sd_event_get_exit_code(m->event, &r);
-
-finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
+ (void) sd_event_get_exit_code(m->event, &r);
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return r;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 9cd317e97b..08c57a3fb1 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -855,10 +855,8 @@ static int path_open_parent_safe(const char *path) {
if (!dn)
return log_oom();
- fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
- if (fd == -EPERM)
- return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
- if (fd < 0)
+ fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_WARN, NULL);
+ if (fd < 0 && fd != -ENOLINK)
return log_error_errno(fd, "Failed to validate path %s: %m", path);
return fd;
@@ -878,10 +876,8 @@ static int path_open_safe(const char *path) {
"Failed to open invalid path '%s'.",
path);
- fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_NOFOLLOW, NULL);
- if (fd == -EPERM)
- return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
- if (fd < 0)
+ fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL);
+ if (fd < 0 && fd != -ENOLINK)
return log_error_errno(fd, "Failed to validate path %s: %m", path);
return fd;
@@ -2259,11 +2255,12 @@ static int process_item(Item *i, OperationMask operation) {
i->done |= operation;
- r = chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL);
+ r = chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS|CHASE_WARN, NULL);
if (r == -EREMOTE) {
- log_debug_errno(r, "Item '%s' is below autofs, skipping.", i->path);
+ log_notice_errno(r, "Skipping %s", i->path);
return 0;
- } else if (r < 0)
+ }
+ if (r < 0)
log_debug_errno(r, "Failed to determine whether '%s' is below autofs, ignoring: %m", i->path);
r = FLAGS_SET(operation, OPERATION_CREATE) ? create_item(i) : 0;