summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-03-03 12:28:49 +0100
committerThomas Haller <thaller@redhat.com>2015-03-03 12:37:17 +0100
commit4e07f6117391ee4d112f8035039ef237c160e828 (patch)
tree8b4b5a304dc7adb0b6d491402134d7f4d38cfb18
parent5599a82d0dc7b69497cb29f67bb0fb8cd618d32c (diff)
parent117cb022b13cedf4035e2a778b8d61528075a8b4 (diff)
downloadNetworkManager-4e07f6117391ee4d112f8035039ef237c160e828.tar.gz
dhcp: merge branch 'th/systemd-dhcp-integration' (bgo #742719)
Update internal dhcp library with new code from upstream systemd. HEAD=117cb022b13cedf4035e2a778b8d61528075a8b4 MERGE=$(git rev-list --merges -n1 $HEAD) # how did we modify the systemd code? git diffs $MERGE^1 $HEAD -- :/src/dhcp-manager/systemd-dhcp/ # what changed in systemd since last merge: git diffs $MERGE^2 $HEAD -- :/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/ https://bugzilla.gnome.org/show_bug.cgi?id=742719
-rw-r--r--src/Makefile.am6
-rw-r--r--src/dhcp-manager/nm-dhcp-systemd.c6
-rw-r--r--src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h50
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c111
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h65
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h2
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c4
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c8
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h3
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c99
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h14
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c108
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c34
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c244
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c32
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c235
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/fileio.c6
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c54
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h6
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/list.h20
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/log.h214
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/macro.h68
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/path-util.c694
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/path-util.h75
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h1
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/strv.c99
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/strv.h18
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/time-util.c11
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/time-util.h4
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/utf8.c141
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/utf8.h21
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/util.c1625
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/shared/util.h216
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h6
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h13
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h6
37 files changed, 3496 insertions, 825 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index eb8984f538..ead105de4a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,6 +65,9 @@ SYSTEMD_DHCP_CFLAGS = \
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp
libsystemd_dhcp_la_SOURCES = \
+ dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c \
+ dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c \
+ dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h \
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c \
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c \
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h \
@@ -96,8 +99,11 @@ libsystemd_dhcp_la_SOURCES = \
dhcp-manager/systemd-dhcp/src/shared/util.h \
dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h \
dhcp-manager/systemd-dhcp/src/shared/list.h \
+ dhcp-manager/systemd-dhcp/src/shared/log.h \
dhcp-manager/systemd-dhcp/src/shared/fileio.h \
dhcp-manager/systemd-dhcp/src/shared/fileio.c \
+ dhcp-manager/systemd-dhcp/src/shared/path-util.c \
+ dhcp-manager/systemd-dhcp/src/shared/path-util.h \
dhcp-manager/systemd-dhcp/src/shared/strv.h \
dhcp-manager/systemd-dhcp/src/shared/strv.c \
dhcp-manager/systemd-dhcp/src/shared/unaligned.h \
diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c
index 1ea836e586..de5bf2a9be 100644
--- a/src/dhcp-manager/nm-dhcp-systemd.c
+++ b/src/dhcp-manager/nm-dhcp-systemd.c
@@ -746,12 +746,6 @@ ip6_start (NMDhcpClient *client,
goto error;
}
- r = sd_dhcp6_client_set_ifname (priv->client6, iface);
- if (r < 0) {
- nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP ifname (%d)", iface, r);
- goto error;
- }
-
r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client);
if (r < 0) {
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP callback (%d)", iface, r);
diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
index a95f5bfb42..06ebcd1b23 100644
--- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
+++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
@@ -36,14 +36,20 @@
#include <unistd.h>
#include <sys/syscall.h>
+#include <net/if_arp.h>
+#include <sys/resource.h>
+
#include "nm-logging.h"
-static inline guint32
+/*****************************************************************************/
+
+static inline NMLogLevel
_slog_level_to_nm (int slevel)
{
switch (slevel) {
case LOG_DEBUG: return LOGL_DEBUG;
case LOG_WARNING: return LOGL_WARN;
+ case LOG_CRIT:
case LOG_ERR: return LOGL_ERR;
case LOG_INFO:
case LOG_NOTICE:
@@ -51,39 +57,37 @@ _slog_level_to_nm (int slevel)
}
}
-#define log_meta(level, file, line, func, format, ...) \
-G_STMT_START { \
- guint32 _l = _slog_level_to_nm ((level)); \
- if (nm_logging_enabled (_l, LOGD_DHCP)) { \
- const char *_location = strrchr (file "", '/'); \
+#define log_internal(level, error, file, line, func, format, ...) \
+({ \
+ int _nm_e = (error); \
+ NMLogLevel _nm_l = _slog_level_to_nm ((level)); \
+ if (nm_logging_enabled (_nm_l, LOGD_DHCP)) { \
+ const char *_nm_location = strrchr ((""file), '/'); \
\
- _nm_log (_location ? _location + 1 : file, line, func, _l, LOGD_DHCP, 0, format, ## __VA_ARGS__); \
+ _nm_log (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, ("%s"format), "sd-dhcp: ", ## __VA_ARGS__); \
} \
-} G_STMT_END
+ (_nm_e > 0 ? -_nm_e : _nm_e); \
+})
-#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
-#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
-#define log_full(level, ...) log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__);
+#define log_full_errno(level, error, ...) \
+({ \
+ log_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+})
-#define log_dhcp_client(client, fmt, ...) \
- log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
-
-#define log_assert_failed(e, file, line, func) \
+#define log_assert_failed(text, file, line, func) \
G_STMT_START { \
- nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assertion failed: " # e); \
- g_assert (FALSE); \
+ log_internal (LOG_CRIT, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.", text, file, line, func); \
+ g_assert_not_reached (); \
} G_STMT_END
-#define log_assert_failed_unreachable(t, file, line, func) \
+#define log_assert_failed_return(text, file, line, func) \
G_STMT_START { \
- nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert unreachable: " # t); \
- g_assert_not_reached (); \
+ log_internal (LOG_DEBUG, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", text, file, line, func); \
+ g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, text); \
} G_STMT_END
-#define log_assert_failed_return(e, file, line, func) \
- nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert return: " # e); \
-#define log_oom nm_log_err(LOGD_CORE, "%s:%s/%s: OOM", __FILE__, __LINE__, __func__)
+/*****************************************************************************/
/* Can't include both net/if.h and linux/if.h; so have to define this here */
#ifndef IFNAMSIZ
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c
new file mode 100644
index 0000000000..c33761bc13
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c
@@ -0,0 +1,111 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2015 Tom Gundersen <teg@jklmen>
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#include "sd-id128.h"
+#if 0 /* NM_IGNORED a*/
+#include "libudev.h"
+#include "udev-util.h"
+
+#include "virt.h"
+#include "sparse-endian.h"
+#else /* NM_IGNORED */
+#include <net/if.h>
+#endif /* NM_IGNORED */
+#include "siphash24.h"
+
+#include "dhcp6-protocol.h"
+#include "dhcp-identifier.h"
+#include "network-internal.h"
+
+#define SYSTEMD_PEN 43793
+#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
+
+int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
+ sd_id128_t machine_id;
+ int r;
+
+ assert(duid);
+ assert(len);
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return r;
+
+ duid->type = htobe16(DHCP6_DUID_EN);
+ duid->en.pen = htobe32(SYSTEMD_PEN);
+ *len = sizeof(duid->type) + sizeof(duid->en);
+
+ /* a bit of snake-oil perhaps, but no need to expose the machine-id
+ directly */
+ siphash24(duid->en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
+
+ return 0;
+}
+
+
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id) {
+#if 0 /* NM_IGNORED */
+ /* name is a pointer to memory in the udev_device struct, so must
+ have the same scope */
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+#else /* NM_IGNORED */
+ char name_buf[IF_NAMESIZE];
+#endif /* NM_IGNORED */
+ const char *name = NULL;
+ uint64_t id;
+
+#if 0 /* NM_IGNORED */
+ if (detect_container(NULL) <= 0) {
+ /* not in a container, udev will be around */
+ _cleanup_udev_unref_ struct udev *udev;
+ char ifindex_str[2 + DECIMAL_STR_MAX(int)];
+
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+
+ sprintf(ifindex_str, "n%d", ifindex);
+ device = udev_device_new_from_device_id(udev, ifindex_str);
+ if (device) {
+ if (udev_device_get_is_initialized(device) <= 0)
+ /* not yet ready */
+ return -EBUSY;
+
+ name = net_get_name(device);
+ }
+ }
+#else /* NM_IGNORED */
+ name = if_indextoname(ifindex, name_buf);
+#endif /* NM_IGNORED */
+
+ if (name)
+ siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
+ else
+ /* fall back to MAC address if no predictable name available */
+ siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes);
+
+ /* fold into 32 bits */
+ *_id = (id & 0xffffffff) ^ (id >> 32);
+
+ return 0;
+}
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h
new file mode 100644
index 0000000000..5d4da21cb0
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h
@@ -0,0 +1,65 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2015 Tom Gundersen <teg@jklmen>
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#include "macro.h"
+#include "sparse-endian.h"
+#include "sd-id128.h"
+
+/* RFC 3315 section 9.1:
+ * A DUID can be no more than 128 octets long (not including the type code).
+ */
+#define MAX_DUID_LEN 128
+
+struct duid {
+ uint16_t type;
+ union {
+ struct {
+ /* DHCP6_DUID_LLT */
+ uint16_t htype;
+ uint32_t time;
+ uint8_t haddr[0];
+ } _packed_ llt;
+ struct {
+ /* DHCP6_DUID_EN */
+ uint32_t pen;
+ uint8_t id[8];
+ } _packed_ en;
+ struct {
+ /* DHCP6_DUID_LL */
+ int16_t htype;
+ uint8_t haddr[0];
+ } _packed_ ll;
+ struct {
+ /* DHCP6_DUID_UUID */
+ sd_id128_t uuid;
+ } _packed_ uuid;
+ struct {
+ uint8_t data[MAX_DUID_LEN];
+ } _packed_ raw;
+ };
+} _packed_;
+
+int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h
index 28c0e63454..b94c43f3b8 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h
@@ -73,4 +73,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
#define DHCP_CLIENT_DONT_DESTROY(client) \
_cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
-#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
+#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c
index 26e6e9f3df..0b63028b46 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c
@@ -20,7 +20,6 @@
#include "nm-sd-adapt.h"
#include <errno.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/if_packet.h>
@@ -28,7 +27,6 @@
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <stdio.h>
-#include <unistd.h>
#include <linux/filter.h>
#include "socket-util.h"
@@ -65,7 +63,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- mac address length */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c
index e6ebf86ae1..bb9bd90491 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c
@@ -20,22 +20,14 @@
#include "nm-sd-adapt.h"
-#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <stdio.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
-#include <sys/param.h>
-#include "util.h"
-#include "list.h"
#include "dhcp-protocol.h"
-#include "dhcp-lease-internal.h"
#include "dhcp-internal.h"
-#include "sd-dhcp-lease.h"
-#include "sd-dhcp-client.h"
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h
index e29e2f0ee0..ee4014faab 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h
@@ -58,7 +58,7 @@ struct DHCP6IA {
typedef struct DHCP6IA DHCP6IA;
-#define log_dhcp6_client(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
int dhcp_network_icmp6_bind_router_solicitation(int index);
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h
index e46470d20e..6598d86074 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h
@@ -53,6 +53,8 @@ enum {
DHCP6_PORT_CLIENT = 546,
};
+#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC
+#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
@@ -73,6 +75,7 @@ enum {
enum DHCP6State {
DHCP6_STATE_STOPPED = 0,
+ DHCP6_STATE_INFORMATION_REQUEST = 1,
DHCP6_STATE_SOLICITATION = 2,
DHCP6_STATE_REQUEST = 3,
DHCP6_STATE_BOUND = 4,
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c
index 8251269a0a..bc691abf26 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c
@@ -24,12 +24,10 @@
#include <netinet/ether.h>
#include <linux/if.h>
#include <arpa/inet.h>
-#include <fnmatch.h>
#if 0 /* NM_IGNORED */
#include "strv.h"
#include "siphash24.h"
-#include "libudev-private.h"
#endif /* NM_IGNORED */
#include "dhcp-lease-internal.h"
#if 0 /* NM_IGNORED */
@@ -92,10 +90,10 @@ int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8
}
bool net_match_config(const struct ether_addr *match_mac,
- const char *match_path,
- const char *match_driver,
- const char *match_type,
- const char *match_name,
+ char * const *match_paths,
+ char * const *match_drivers,
+ char * const *match_types,
+ char * const *match_names,
Condition *match_host,
Condition *match_virt,
Condition *match_kernel,
@@ -108,37 +106,37 @@ bool net_match_config(const struct ether_addr *match_mac,
const char *dev_name) {
if (match_host && !condition_test(match_host))
- return 0;
+ return false;
if (match_virt && !condition_test(match_virt))
- return 0;
+ return false;
if (match_kernel && !condition_test(match_kernel))
- return 0;
+ return false;
if (match_arch && !condition_test(match_arch))
- return 0;
+ return false;
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
- return 0;
+ return false;
- if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
- return 0;
+ if (!strv_isempty(match_paths) &&
+ (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
+ return false;
- if (match_driver) {
- if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
- return 0;
- else if (!streq_ptr(match_driver, dev_driver))
- return 0;
- }
+ if (!strv_isempty(match_drivers) &&
+ (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
+ return false;
- if (match_type && !streq_ptr(match_type, dev_type))
- return 0;
+ if (!strv_isempty(match_types) &&
+ (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
+ return false;
- if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
- return 0;
+ if (!strv_isempty(match_names) &&
+ (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
+ return false;
- return 1;
+ return true;
}
int config_parse_net_condition(const char *unit,
@@ -221,6 +219,49 @@ int config_parse_ifname(const char *unit,
return 0;
}
+int config_parse_ifnames(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) {
+
+ char ***sv = data;
+ const char *word, *state;
+ size_t l;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ FOREACH_WORD(word, l, rvalue, state) {
+ char *n;
+
+ n = strndup(word, l);
+ if (!n)
+ return log_oom();
+
+ if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ free(n);
+ return 0;
+ }
+
+ r = strv_consume(sv, n);
+ if (r < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
+
int config_parse_ifalias(const char *unit,
const char *filename,
unsigned line,
@@ -233,7 +274,7 @@ int config_parse_ifalias(const char *unit,
void *userdata) {
char **s = data;
- char *n;
+ _cleanup_free_ char *n = NULL;
assert(filename);
assert(lvalue);
@@ -247,17 +288,15 @@ int config_parse_ifalias(const char *unit,
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(n);
return 0;
}
free(*s);
- if (*n)
+ if (*n) {
*s = n;
- else {
- free(n);
+ n = NULL;
+ } else
*s = NULL;
- }
return 0;
}
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h
index 7a482f2043..f94099f57a 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h
@@ -23,8 +23,6 @@
#include "nm-sd-adapt.h"
-#include <netinet/ether.h>
-#include <netinet/in.h>
#include <stdbool.h>
#if 0 /* NM_IGNORED */
@@ -32,10 +30,10 @@
#include "condition.h"
bool net_match_config(const struct ether_addr *match_mac,
- const char *match_path,
- const char *match_driver,
- const char *match_type,
- const char *match_name,
+ char * const *match_path,
+ char * const *match_driver,
+ char * const *match_type,
+ char * const *match_name,
Condition *match_host,
Condition *match_virt,
Condition *match_kernel,
@@ -59,6 +57,10 @@ int config_parse_ifname(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);
+int config_parse_ifnames(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);
+
int config_parse_ifalias(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);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
index d5ada92375..d3cc1b8cd4 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
@@ -26,21 +26,19 @@
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <linux/if_infiniband.h>
-#include <netinet/ether.h>
-#include <sys/param.h>
#include <sys/ioctl.h>
#include "util.h"
-#include "list.h"
#include "refcnt.h"
#include "async.h"
#include "dhcp-protocol.h"
#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
+#include "dhcp-identifier.h"
#include "sd-dhcp-client.h"
-#define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */
+#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
struct sd_dhcp_client {
@@ -62,29 +60,31 @@ struct sd_dhcp_client {
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
- union {
- struct {
- uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ gen;
- struct {
- uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */
- uint8_t haddr[ETH_ALEN];
- } _packed_ eth;
- struct {
- uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */
- uint8_t haddr[0];
- } _packed_ ll;
- struct {
- uint8_t type; /* 255: Node-specific (RFC 4361) */
- uint8_t iaid[4];
- uint8_t duid[MAX_CLIENT_ID_LEN - 4];
- } _packed_ ns;
- struct {
- uint8_t type;
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ raw;
- } client_id;
+ struct {
+ uint8_t type;
+ union {
+ struct {
+ /* 0: Generic (non-LL) (RFC 2132) */
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ gen;
+ struct {
+ /* 1: Ethernet Link-Layer (RFC 2132) */
+ uint8_t haddr[ETH_ALEN];
+ } _packed_ eth;
+ struct {
+ /* 2 - 254: ARP/Link-Layer (RFC 2132) */
+ uint8_t haddr[0];
+ } _packed_ ll;
+ struct {
+ /* 255: Node-specific (RFC 4361) */
+ uint32_t iaid;
+ struct duid duid;
+ } _packed_ ns;
+ struct {
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ raw;
+ };
+ } _packed_ client_id;
size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
@@ -241,10 +241,9 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
*data = NULL;
*data_len = 0;
if (client->client_id_len) {
- *type = client->client_id.raw.type;
+ *type = client->client_id.type;
*data = client->client_id.raw.data;
- *data_len = client->client_id_len -
- sizeof (client->client_id.raw.type);
+ *data_len = client->client_id_len - sizeof(client->client_id.type);
}
return 0;
@@ -272,8 +271,8 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
break;
}
- if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) &&
- client->client_id.raw.type == type &&
+ if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
+ client->client_id.type == type &&
memcmp(&client->client_id.raw.data, data, data_len) == 0)
return 0;
@@ -284,9 +283,9 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
client_stop(client, DHCP_EVENT_STOP);
}
- client->client_id.raw.type = type;
+ client->client_id.type = type;
memcpy(&client->client_id.raw.data, data, data_len);
- client->client_id_len = data_len + sizeof (client->client_id.raw.type);
+ client->client_id_len = data_len + sizeof (client->client_id.type);
if (need_restart && client->state != DHCP_STATE_STOPPED)
sd_dhcp_client_start(client);
@@ -402,7 +401,7 @@ static void client_stop(sd_dhcp_client *client, int error) {
static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
uint8_t type, size_t *_optlen, size_t *_optoffset) {
- _cleanup_free_ DHCPPacket *packet = NULL;
+ _cleanup_free_ DHCPPacket *packet;
size_t optlen, optoffset, size;
be16_t max_size;
usec_t time_now;
@@ -416,8 +415,6 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
assert(_optoffset);
assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
- /* See RFC2131 section 4.4.1 */
-
optlen = DHCP_MIN_OPTIONS_SIZE;
size = sizeof(DHCPPacket) + optlen;
@@ -465,12 +462,21 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
if (client->arp_type == ARPHRD_ETHER)
memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
- /* If no client identifier exists, construct one from an ethernet
- address if present */
- if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) {
- client->client_id.eth.type = ARPHRD_ETHER;
- memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN);
- client->client_id_len = sizeof (client->client_id.eth);
+ /* If no client identifier exists, construct an RFC 4361-compliant one */
+ if (client->client_id_len == 0) {
+ size_t duid_len;
+
+ client->client_id.type = 255;
+
+ r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
+ if (r < 0)
+ return r;
+
+ r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
+ if (r < 0)
+ return r;
+
+ client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
}
/* Some DHCP servers will refuse to issue an DHCP lease if the Client
@@ -479,7 +485,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
DHCP_OPTION_CLIENT_IDENTIFIER,
client->client_id_len,
- &client->client_id.raw);
+ &client->client_id);
if (r < 0)
return r;
}
@@ -504,7 +510,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
than the defined default size unless the Maximum Messge Size option
- is explicitely set
+ is explicitly set
RFC3442 "Requirements to Avoid Sizing Constraints":
Because a full routing table can be quite large, the standard 576
@@ -1035,7 +1041,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
if (client->client_id_len) {
r = dhcp_lease_set_client_id(lease,
- (uint8_t *) &client->client_id.raw,
+ (uint8_t *) &client->client_id,
client->client_id_len);
if (r < 0)
return r;
@@ -1102,7 +1108,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
if (client->client_id_len) {
r = dhcp_lease_set_client_id(lease,
- (uint8_t *) &client->client_id.raw,
+ (uint8_t *) &client->client_id,
client->client_id_len);
if (r < 0)
return r;
@@ -1386,8 +1392,10 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
client->last_addr = client->lease->address;
r = client_set_lease_timeouts(client);
- if (r < 0)
+ if (r < 0) {
+ log_dhcp_client(client, "could not set lease timeouts");
goto error;
+ }
r = dhcp_network_bind_udp_socket(client->lease->address,
DHCP_PORT_CLIENT);
@@ -1615,7 +1623,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
r = client_start(client);
if (r >= 0)
- log_dhcp_client(client, "STARTED on ifindex %u", client->index);
+ log_dhcp_client(client, "STARTED on ifindex %i", client->index);
return r;
}
@@ -1674,7 +1682,7 @@ sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
}
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
- if (client && REFCNT_DEC(client->n_ref) <= 0) {
+ if (client && REFCNT_DEC(client->n_ref) == 0) {
log_dhcp_client(client, "FREE");
client_initialize(client);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
index 6a28f9b01f..14658742c7 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
@@ -24,24 +24,15 @@
#include <errno.h>
#include <string.h>
#include <stdio.h>
-#include <net/ethernet.h>
#include <arpa/inet.h>
-#include <sys/param.h>
-#include "util.h"
-#include "list.h"
-#if 0 /* NM_IGNORED */
-#include "mkdir.h"
-#endif /* NM_IGNORED */
#include "fileio.h"
#include "unaligned.h"
#include "in-addr-util.h"
#include "dhcp-protocol.h"
-#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "sd-dhcp-lease.h"
-#include "sd-dhcp-client.h"
#include "network-internal.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -55,7 +46,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
assert_return(lease, -EINVAL);
- assert_return(lease, -EINVAL);
+ assert_return(lifetime, -EINVAL);
*lifetime = lease->lifetime;
@@ -197,7 +188,7 @@ sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
}
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
- if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
+ if (lease && REFCNT_DEC(lease->n_ref) == 0) {
free(lease->hostname);
free(lease->domainname);
free(lease->dns);
@@ -501,11 +492,20 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
case DHCP_OPTION_DOMAIN_NAME:
{
_cleanup_free_ char *domainname = NULL;
+ char *e;
r = lease_parse_string(option, len, &domainname);
if (r < 0)
return r;
+ /* Chop off trailing dot of domain name that some DHCP
+ * servers send us back. Internally we want to store
+ * host names without trailing dots and
+ * host_name_is_valid() doesn't accept them. */
+ e = endswith(domainname, ".");
+ if (e)
+ *e = 0;
+
if (!hostname_is_valid(domainname) || is_localhost(domainname))
break;
@@ -518,11 +518,16 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
case DHCP_OPTION_HOST_NAME:
{
_cleanup_free_ char *hostname = NULL;
+ char *e;
r = lease_parse_string(option, len, &hostname);
if (r < 0)
return r;
+ e = endswith(hostname, ".");
+ if (e)
+ *e = 0;
+
if (!hostname_is_valid(hostname) || is_localhost(hostname))
break;
@@ -667,7 +672,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
if (r >= 0) {
- _cleanup_free_ char *client_id_hex = NULL;
+ _cleanup_free_ char *client_id_hex;
client_id_hex = hexmem (client_id, client_id_len);
if (!client_id_hex) {
@@ -689,7 +694,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
finish:
if (r < 0)
- log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
+ log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
return r;
}
@@ -729,8 +734,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (r == -ENOENT)
return 0;
- log_error("Failed to read %s: %s", lease_file, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to read %s: %m", lease_file);
}
r = inet_pton(AF_INET, address, &addr);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
index 792e46d57a..3687abcbef 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
@@ -29,9 +29,7 @@
#if 0 /* NM_IGNORED */
#include "udev.h"
#include "udev-util.h"
-#include "virt.h"
#endif /* NM_IGNORED */
-#include "siphash24.h"
#include "util.h"
#include "refcnt.h"
@@ -40,14 +38,7 @@
#include "dhcp6-protocol.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
-
-#define SYSTEMD_PEN 43793
-#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
-
-/* RFC 3315 section 9.1:
- * A DUID can be no more than 128 octets long (not including the type code).
- */
-#define MAX_DUID_LEN 128
+#include "dhcp-identifier.h"
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
@@ -61,12 +52,12 @@ struct sd_dhcp6_client {
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
- char ifname[IFNAMSIZ];
DHCP6IA ia_na;
be32_t transaction_id;
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
int fd;
+ bool information_request;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
@@ -77,32 +68,7 @@ struct sd_dhcp6_client {
sd_event_source *timeout_resend_expire;
sd_dhcp6_client_cb_t cb;
void *userdata;
- union {
- struct {
- uint16_t type; /* DHCP6_DUID_LLT */
- uint16_t htype;
- uint32_t time;
- uint8_t haddr[0];
- } _packed_ llt;
- struct {
- uint16_t type; /* DHCP6_DUID_EN */
- uint32_t pen;
- uint8_t id[8];
- } _packed_ en;
- struct {
- uint16_t type; /* DHCP6_DUID_LL */
- uint16_t htype;
- uint8_t haddr[0];
- } _packed_ ll;
- struct {
- uint16_t type; /* DHCP6_DUID_UUID */
- sd_id128_t uuid;
- } _packed_ uuid;
- struct {
- uint16_t type;
- uint8_t data[MAX_DUID_LEN];
- } _packed_ raw;
- } duid;
+ struct duid duid;
size_t duid_len;
};
@@ -205,19 +171,19 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
switch (type) {
case DHCP6_DUID_LLT:
- if (duid_len <= sizeof(client->duid.llt) - 2)
+ if (duid_len <= sizeof(client->duid.llt))
return -EINVAL;
break;
case DHCP6_DUID_EN:
- if (duid_len != sizeof(client->duid.en) - 2)
+ if (duid_len != sizeof(client->duid.en))
return -EINVAL;
break;
case DHCP6_DUID_LL:
- if (duid_len <= sizeof(client->duid.ll) - 2)
+ if (duid_len <= sizeof(client->duid.ll))
return -EINVAL;
break;
case DHCP6_DUID_UUID:
- if (duid_len != sizeof(client->duid.uuid) - 2)
+ if (duid_len != sizeof(client->duid.uuid))
return -EINVAL;
break;
default:
@@ -225,9 +191,28 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
break;
}
- client->duid.raw.type = htobe16(type);
+ client->duid.type = htobe16(type);
memcpy(&client->duid.raw.data, duid, duid_len);
- client->duid_len = duid_len + 2; /* +2 for sizeof(type) */
+ client->duid_len = duid_len + sizeof(client->duid.type);
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
+ bool enabled) {
+ assert_return(client, -EINVAL);
+
+ client->information_request = enabled;
+
+ return 0;
+}
+
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
+ bool *enabled) {
+ assert_return(client, -EINVAL);
+ assert_return(enabled, -EINVAL);
+
+ *enabled = client->information_request;
return 0;
}
@@ -338,6 +323,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
message->transaction_id = client->transaction_id;
switch(client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ message->type = DHCP6_INFORMATION_REQUEST;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
message->type = DHCP6_SOLICIT;
@@ -499,6 +489,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ init_retransmit_time = DHCP6_INF_TIMEOUT;
+ max_retransmit_time = DHCP6_INF_MAX_RT;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
if (client->retransmit_count && client->lease) {
@@ -631,24 +627,16 @@ error:
}
static int client_ensure_iaid(sd_dhcp6_client *client) {
- const char *name;
- uint64_t id;
+ int r;
assert(client);
if (client->ia_na.id)
return 0;
- name = client->ifname;
- if (name)
- siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
- else
- /* fall back to mac address if no predictable name available */
- siphash24((uint8_t*)&id, &client->mac_addr,
- client->mac_addr_len, HASH_KEY.bytes);
-
- /* fold into 32 bits */
- client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
+ r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
+ if (r < 0)
+ return r;
return 0;
}
@@ -726,6 +714,12 @@ static int client_parse_message(sd_dhcp6_client *client,
break;
case DHCP6_OPTION_IA_NA:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ log_dhcp6_client(client, "Information request ignoring IA NA option");
+
+ break;
+ }
+
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
&lease->ia);
if (r < 0 && r != -ENOMSG)
@@ -752,16 +746,21 @@ static int client_parse_message(sd_dhcp6_client *client,
}
}
- if ((r < 0 && r != -ENOMSG) || !clientid) {
+ if (r == -ENOMSG)
+ r = 0;
+
+ if (r < 0 || !clientid) {
log_dhcp6_client(client, "%s has incomplete options",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
- r = dhcp6_lease_get_serverid(lease, &id, &id_len);
- if (r < 0)
- log_dhcp6_client(client, "%s has no server id",
- dhcp6_message_type_to_string(message->type));
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ r = dhcp6_lease_get_serverid(lease, &id, &id_len);
+ if (r < 0)
+ log_dhcp6_client(client, "%s has no server id",
+ dhcp6_message_type_to_string(message->type));
+ }
return r;
}
@@ -793,12 +792,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
return 0;
}
- if (client->lease)
+ if (client->lease) {
dhcp6_lease_clear_timers(&client->lease->ia);
+ client->lease = sd_dhcp6_lease_unref(client->lease);
+ }
- client->lease = sd_dhcp6_lease_unref(client->lease);
- client->lease = lease;
- lease = NULL;
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ client->lease = lease;
+ lease = NULL;
+ }
return DHCP6_STATE_BOUND;
}
@@ -825,7 +827,8 @@ static int client_receive_advertise(sd_dhcp6_client *client,
return r;
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
- if (!client->lease || r < 0 || pref_advertise > pref_lease) {
+
+ if (r < 0 || pref_advertise > pref_lease) {
sd_dhcp6_lease_unref(client->lease);
client->lease = lease;
lease = NULL;
@@ -842,7 +845,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
- _cleanup_free_ DHCP6Message *message = NULL;
+ _cleanup_free_ DHCP6Message *message;
int r, buflen, len;
assert(s);
@@ -892,6 +895,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ r = client_receive_reply(client, message, len);
+ if (r < 0)
+ return 0;
+
+ client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
+
+ client_start(client, DHCP6_STATE_STOPPED);
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
@@ -967,37 +981,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
switch (state) {
case DHCP6_STATE_STOPPED:
- case DHCP6_STATE_SOLICITATION:
-
- r = client_ensure_iaid(client);
- if (r < 0)
- return r;
-
- r = dhcp6_network_bind_udp_socket(client->index, NULL);
- if (r < 0)
- return r;
-
- client->fd = r;
-
- r = sd_event_add_io(client->event, &client->receive_message,
- client->fd, EPOLLIN, client_receive_message,
- client);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->receive_message,
- client->event_priority);
- if (r < 0)
- return r;
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ client->state = DHCP6_STATE_STOPPED;
- r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message");
- if (r < 0)
- return r;
+ return 0;
+ }
+ /* fall through */
+ case DHCP6_STATE_SOLICITATION:
client->state = DHCP6_STATE_SOLICITATION;
break;
+ case DHCP6_STATE_INFORMATION_REQUEST:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
@@ -1102,6 +1098,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client)
int sd_dhcp6_client_start(sd_dhcp6_client *client)
{
int r = 0;
+ enum DHCP6State state = DHCP6_STATE_SOLICITATION;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
@@ -1111,7 +1108,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
if (r < 0)
return r;
- return client_start(client, DHCP6_STATE_SOLICITATION);
+ r = client_ensure_iaid(client);
+ if (r < 0)
+ return r;
+
+ r = dhcp6_network_bind_udp_socket(client->index, NULL);
+ if (r < 0)
+ return r;
+
+ client->fd = r;
+
+ r = sd_event_add_io(client->event, &client->receive_message,
+ client->fd, EPOLLIN, client_receive_message,
+ client);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_priority(client->receive_message,
+ client->event_priority);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_description(client->receive_message,
+ "dhcp6-receive-message");
+ if (r < 0)
+ goto error;
+
+ if (client->information_request)
+ state = DHCP6_STATE_INFORMATION_REQUEST;
+
+ log_dhcp6_client(client, "Started in %s mode",
+ client->information_request? "Information request":
+ "Managed");
+
+ return client_start(client, state);
+
+error:
+ client_reset(client);
+ return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
@@ -1158,7 +1192,7 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
}
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
- if (client && REFCNT_DEC(client->n_ref) <= 0) {
+ if (client && REFCNT_DEC(client->n_ref) == 0) {
client_reset(client);
sd_dhcp6_client_detach_event(client);
@@ -1176,7 +1210,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
{
_cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
#if 0 /* NM_IGNORED */
- sd_id128_t machine_id;
int r;
#endif /* NM_IGNORED */
size_t t;
@@ -1197,17 +1230,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
#if 0 /* NM_IGNORED */
/* initialize DUID */
- client->duid.en.type = htobe16(DHCP6_DUID_EN);
- client->duid.en.pen = htobe32(SYSTEMD_PEN);
- client->duid_len = sizeof(client->duid.en);
-
- r = sd_id128_get_machine(&machine_id);
+ r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
if (r < 0)
return r;
-
- /* a bit of snake-oil perhaps, but no need to expose the machine-id
- directly */
- siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
#endif /* NM_IGNORED */
client->req_opts_len = ELEMENTSOF(default_req_opts);
@@ -1225,16 +1250,3 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
return 0;
}
-/*******************************************/
-/* NetworkManager additions */
-
-int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname)
-{
- assert_return(client, -EINVAL);
- assert_return(ifname, -EINVAL);
- assert_return(strlen (ifname) < sizeof (client->ifname), -EINVAL);
-
- strcpy(client->ifname, ifname);
- return 0;
-}
-
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c
index 6a1cb22daa..8ac18a7566 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c
@@ -112,9 +112,11 @@ int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
}
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
- assert_return(lease, -EINVAL);
assert_return(preference, -EINVAL);
+ if (!lease)
+ return -EINVAL;
+
*preference = lease->preference;
return 0;
@@ -146,10 +148,9 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
return 0;
}
-int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
- struct in6_addr *addr,
- uint32_t *lifetime_preferred,
- uint32_t *lifetime_valid) {
+int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
+ uint32_t *lifetime_preferred,
+ uint32_t *lifetime_valid) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
assert_return(lifetime_preferred, -EINVAL);
@@ -169,22 +170,9 @@ int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
return 0;
}
-int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
- struct in6_addr *addr,
- uint32_t *lifetime_preferred,
- uint32_t *lifetime_valid) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(lifetime_preferred, -EINVAL);
- assert_return(lifetime_valid, -EINVAL);
-
- if (!lease->ia.addresses)
- return -ENOMSG;
-
- lease->addr_iter = lease->ia.addresses;
-
- return sd_dhcp6_lease_get_next_address(lease, addr, lifetime_preferred,
- lifetime_valid);
+void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
+ if (lease)
+ lease->addr_iter = lease->ia.addresses;
}
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
@@ -195,7 +183,7 @@ sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
}
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
- if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
+ if (lease && REFCNT_DEC(lease->n_ref) == 0) {
free(lease->serverid);
dhcp6_lease_free_ia(&lease->ia);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c
new file mode 100644
index 0000000000..850461651a
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c
@@ -0,0 +1,235 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "macro.h"
+#include "sd-id128.h"
+
+#if 0 /* NM_IGNORED */
+_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
+ unsigned n;
+
+ assert_return(s, NULL);
+
+ for (n = 0; n < 16; n++) {
+ s[n*2] = hexchar(id.bytes[n] >> 4);
+ s[n*2+1] = hexchar(id.bytes[n] & 0xF);
+ }
+
+ s[32] = 0;
+
+ return s;
+}
+
+_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
+ unsigned n, i;
+ sd_id128_t t;
+ bool is_guid = false;
+
+ assert_return(s, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ for (n = 0, i = 0; n < 16;) {
+ int a, b;
+
+ if (s[i] == '-') {
+ /* Is this a GUID? Then be nice, and skip over
+ * the dashes */
+
+ if (i == 8)
+ is_guid = true;
+ else if (i == 13 || i == 18 || i == 23) {
+ if (!is_guid)
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ i++;
+ continue;
+ }
+
+ a = unhexchar(s[i++]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unhexchar(s[i++]);
+ if (b < 0)
+ return -EINVAL;
+
+ t.bytes[n++] = (a << 4) | b;
+ }
+
+ if (i != (is_guid ? 36 : 32))
+ return -EINVAL;
+
+ if (s[i] != 0)
+ return -EINVAL;
+
+ *ret = t;
+ return 0;
+}
+
+static sd_id128_t make_v4_uuid(sd_id128_t id) {
+ /* Stolen from generate_random_uuid() of drivers/char/random.c
+ * in the kernel sources */
+
+ /* Set UUID version to 4 --- truly random generation */
+ id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
+
+ /* Set the UUID variant to DCE */
+ id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
+
+ return id;
+}
+#endif
+
+_public_ int sd_id128_get_machine(sd_id128_t *ret) {
+ static thread_local sd_id128_t saved_machine_id;
+ static thread_local bool saved_machine_id_valid = false;
+ _cleanup_close_ int fd = -1;
+ char buf[33];
+ ssize_t k;
+ unsigned j;
+ sd_id128_t t;
+
+ assert_return(ret, -EINVAL);
+
+ if (saved_machine_id_valid) {
+ *ret = saved_machine_id;
+ return 0;
+ }
+
+ fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ k = loop_read(fd, buf, 33, false);
+ if (k < 0)
+ return (int) k;
+
+ if (k != 33)
+ return -EIO;
+
+ if (buf[32] !='\n')
+ return -EIO;
+
+ for (j = 0; j < 16; j++) {
+ int a, b;
+
+ a = unhexchar(buf[j*2]);
+ b = unhexchar(buf[j*2+1]);
+
+ if (a < 0 || b < 0)
+ return -EIO;
+
+ t.bytes[j] = a << 4 | b;
+ }
+
+ saved_machine_id = t;
+ saved_machine_id_valid = true;
+
+ *ret = t;
+ return 0;
+}
+
+#if 0 /* NM_IGNORED */
+_public_ int sd_id128_get_boot(sd_id128_t *ret) {
+ static thread_local sd_id128_t saved_boot_id;
+ static thread_local bool saved_boot_id_valid = false;
+ _cleanup_close_ int fd = -1;
+ char buf[36];
+ ssize_t k;
+ unsigned j;
+ sd_id128_t t;
+ char *p;
+
+ assert_return(ret, -EINVAL);
+
+ if (saved_boot_id_valid) {
+ *ret = saved_boot_id;
+ return 0;
+ }
+
+ fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ k = loop_read(fd, buf, 36, false);
+ if (k < 0)
+ return (int) k;
+
+ if (k != 36)
+ return -EIO;
+
+ for (j = 0, p = buf; j < 16; j++) {
+ int a, b;
+
+ if (p >= buf + k - 1)
+ return -EIO;
+
+ if (*p == '-') {
+ p++;
+ if (p >= buf + k - 1)
+ return -EIO;
+ }
+
+ a = unhexchar(p[0]);
+ b = unhexchar(p[1]);
+
+ if (a < 0 || b < 0)
+ return -EIO;
+
+ t.bytes[j] = a << 4 | b;
+
+ p += 2;
+ }
+
+ saved_boot_id = t;
+ saved_boot_id_valid = true;
+
+ *ret = t;
+ return 0;
+}
+
+_public_ int sd_id128_randomize(sd_id128_t *ret) {
+ sd_id128_t t;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = dev_urandom(&t, sizeof(t));
+ if (r < 0)
+ return r;
+
+ /* Turn this into a valid v4 UUID, to be nice. Note that we
+ * only guarantee this for newly generated UUIDs, not for
+ * pre-existing ones. */
+
+ *ret = make_v4_uuid(t);
+ return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c
index 84fd50495f..88b15fb4af 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c
@@ -510,15 +510,17 @@ static int parse_env_file_push(
va_list aq, *ap = userdata;
if (!utf8_is_valid(key)) {
- _cleanup_free_ char *p = utf8_escape_invalid(key);
+ _cleanup_free_ char *p;
+ p = utf8_escape_invalid(key);
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
return -EINVAL;
}
if (value && !utf8_is_valid(value)) {
- _cleanup_free_ char *p = utf8_escape_invalid(value);
+ _cleanup_free_ char *p;
+ p = utf8_escape_invalid(value);
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
return -EINVAL;
}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
index 530be45e14..488f6d1ebd 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
@@ -245,12 +245,25 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
return -EINVAL;
}
-unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
+unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
return 32 - u32ctz(be32toh(addr->s_addr));
}
+struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
+ assert(addr);
+ assert(prefixlen <= 32);
+
+ /* Shifting beyond 32 is not defined, handle this specially. */
+ if (prefixlen == 0)
+ addr->s_addr = 0;
+ else
+ addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
+
+ return addr;
+}
+
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
uint8_t msb_octet = *(uint8_t*) addr;
@@ -286,9 +299,42 @@ int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask
if (r < 0)
return r;
- assert(prefixlen > 0 && prefixlen < 32);
+ in_addr_prefixlen_to_netmask(mask, prefixlen);
+ return 0;
+}
+
+int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
+ assert(addr);
- mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
+ if (family == AF_INET) {
+ struct in_addr mask;
- return 0;
+ if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
+ return -EINVAL;
+
+ addr->in.s_addr &= mask.s_addr;
+ return 0;
+ }
+
+ if (family == AF_INET6) {
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ uint8_t mask;
+
+ if (prefixlen >= 8) {
+ mask = 0xFF;
+ prefixlen -= 8;
+ } else {
+ mask = 0xFF << (8 - prefixlen);
+ prefixlen = 0;
+ }
+
+ addr->in6.s6_addr[i] &= mask;
+ }
+
+ return 0;
+ }
+
+ return -EAFNOSUPPORT;
}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
index 36afee2c42..715ded330f 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
@@ -41,11 +41,15 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
-unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr);
+unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
+struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
assert(family == AF_INET || family == AF_INET6);
return family == AF_INET6 ? 16 : 4;
}
+
+#define IN_ADDR_NULL ((union in_addr_union) {})
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/list.h b/src/dhcp-manager/systemd-dhcp/src/shared/list.h
index dcb3e0d94c..af121d7009 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/list.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/list.h
@@ -57,6 +57,14 @@
*_head = _item; \
} while(false)
+/* Append an item to the list */
+#define LIST_APPEND(name,head,item) \
+ do { \
+ typeof(*(head)) *_tail; \
+ LIST_FIND_TAIL(name,head,_tail); \
+ LIST_INSERT_AFTER(name,head,_tail,item); \
+ } while(false)
+
/* Remove an item from the list */
#define LIST_REMOVE(name,head,item) \
do { \
@@ -132,6 +140,18 @@
#define LIST_FOREACH_AFTER(name,i,p) \
for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
+/* Iterate through all the members of the list p is included in, but skip over p */
+#define LIST_FOREACH_OTHERS(name,i,p) \
+ for (({ \
+ (i) = (p); \
+ while ((i) && (i)->name##_prev) \
+ (i) = (i)->name##_prev; \
+ if ((i) == (p)) \
+ (i) = (p)->name##_next; \
+ }); \
+ (i); \
+ (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next)
+
/* Loop starting from p->next until p->prev.
p can be adjusted meanwhile. */
#define LIST_LOOP_BUT_ONE(name,i,head,p) \
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/log.h b/src/dhcp-manager/systemd-dhcp/src/shared/log.h
new file mode 100644
index 0000000000..ee276922a2
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/log.h
@@ -0,0 +1,214 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <sys/signalfd.h>
+#include <errno.h>
+
+#include "macro.h"
+#include "sd-id128.h"
+
+typedef enum LogTarget{
+ LOG_TARGET_CONSOLE,
+ LOG_TARGET_CONSOLE_PREFIXED,
+ LOG_TARGET_KMSG,
+ LOG_TARGET_JOURNAL,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_SYSLOG,
+ LOG_TARGET_SYSLOG_OR_KMSG,
+ LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */
+ LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */
+ LOG_TARGET_NULL,
+ _LOG_TARGET_MAX,
+ _LOG_TARGET_INVALID = -1
+} LogTarget;
+
+void log_set_target(LogTarget target);
+void log_set_max_level(int level);
+void log_set_facility(int facility);
+
+int log_set_target_from_string(const char *e);
+int log_set_max_level_from_string(const char *e);
+
+void log_show_color(bool b);
+bool log_get_show_color(void) _pure_;
+void log_show_location(bool b);
+bool log_get_show_location(void) _pure_;
+
+int log_show_color_from_string(const char *e);
+int log_show_location_from_string(const char *e);
+
+LogTarget log_get_target(void) _pure_;
+int log_get_max_level(void) _pure_;
+
+int log_open(void);
+void log_close(void);
+void log_forget_fds(void);
+
+void log_close_syslog(void);
+void log_close_journal(void);
+void log_close_kmsg(void);
+void log_close_console(void);
+
+void log_parse_environment(void);
+
+#if 0 /* NM_IGNORED */
+int log_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format, ...) _printf_(6,7);
+
+int log_internalv(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format,
+ va_list ap) _printf_(6,0);
+
+int log_object_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *format, ...) _printf_(8,9);
+
+int log_object_internalv(
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *format,
+ va_list ap) _printf_(8,0);
+
+int log_struct_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format, ...) _printf_(6,0) _sentinel_;
+
+int log_oom_internal(
+ const char *file,
+ int line,
+ const char *func);
+
+/* This modifies the buffer passed! */
+int log_dump_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ char *buffer);
+
+/* Logging for various assertions */
+noreturn void log_assert_failed(
+ const char *text,
+ const char *file,
+ int line,
+ const char *func);
+
+noreturn void log_assert_failed_unreachable(
+ const char *text,
+ const char *file,
+ int line,
+ const char *func);
+
+void log_assert_failed_return(
+ const char *text,
+ const char *file,
+ int line,
+ const char *func);
+
+/* Logging with level */
+#define log_full_errno(level, error, ...) \
+ ({ \
+ int _level = (level), _e = (error); \
+ (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
+ : -abs(_e); \
+ })
+#endif /* NM_IGNORED */
+
+#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__)
+
+/* Normal logging */
+#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
+#define log_info(...) log_full(LOG_INFO, __VA_ARGS__)
+#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
+#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
+#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+
+/* Logging triggered by an errno-like error */
+#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
+#define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__)
+#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
+#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
+#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
+
+#ifdef LOG_TRACE
+# define log_trace(...) log_debug(__VA_ARGS__)
+#else
+# define log_trace(...) do {} while(0)
+#endif
+
+/* Structured logging */
+#define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/* This modifies the buffer passed! */
+#define log_dump(level, buffer) log_dump_internal(level, 0, __FILE__, __LINE__, __func__, buffer)
+
+#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__)
+
+bool log_on_console(void) _pure_;
+
+const char *log_target_to_string(LogTarget target) _const_;
+LogTarget log_target_from_string(const char *s) _pure_;
+
+/* Helpers to prepare various fields for structured logging */
+#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
+#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
+#define LOG_ERRNO(error) "ERRNO=%i", abs(error)
+
+void log_received_signal(int level, const struct signalfd_siginfo *si);
+
+void log_set_upgrade_syslog_to_journal(bool b);
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/macro.h b/src/dhcp-manager/systemd-dhcp/src/shared/macro.h
index 82469d81f0..d5cb240b3b 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/macro.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/macro.h
@@ -69,6 +69,10 @@
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wshadow\"")
+#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
+
#define REENABLE_WARNING \
_Pragma("GCC diagnostic pop")
@@ -97,15 +101,15 @@
#error "Wut? Pointers are neither 4 nor 8 bytes long?"
#endif
-#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p))
-#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p))
-#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p))
+#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p)))
+#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
+#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}
-#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali))
+#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
static inline unsigned long ALIGN_POWER2(unsigned long u) {
@@ -199,6 +203,17 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
UNIQ_T(X,xq); \
})
+/* [(x + y - 1) / y] suffers from an integer overflow, even though the
+ * computation should be possible in the given type. Therefore, we use
+ * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
+ * quotient and the remainder, so both should be equally fast. */
+#define DIV_ROUND_UP(_x, _y) \
+ __extension__ ({ \
+ const typeof(_x) __x = (_x); \
+ const typeof(_y) __y = (_y); \
+ (__x / __y + !!(__x % __y)); \
+ })
+
#define assert_se(expr) \
do { \
if (_unlikely_(!(expr))) \
@@ -229,7 +244,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#else
#define assert_cc(expr) \
DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
- struct CONCATENATE(_assert_struct_, __LINE__) { \
+ struct CONCATENATE(_assert_struct_, __COUNTER__) { \
char x[(expr) ? 0 : -1]; \
}; \
REENABLE_WARNING
@@ -266,6 +281,14 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+/* The following macros add 1 when converting things, since UID 0 is a
+ * valid UID, while the pointer NULL is special */
+#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
+#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
+#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
#define memzero(x,l) (memset((x), 0, (l)))
#define zero(x) (memzero(&(x), sizeof(x)))
@@ -362,7 +385,8 @@ do { \
/* Returns the number of chars needed to format variables of the
* specified type as a decimal string. Adds in extra space for a
- * negative '-' prefix. */
+ * negative '-' prefix (hence works correctly on signed
+ * types). Includes space for the trailing NUL. */
#define DECIMAL_STR_MAX(type) \
(2+(sizeof(type) <= 1 ? 3 : \
sizeof(type) <= 2 ? 5 : \
@@ -386,7 +410,21 @@ do { \
_found; \
})
-#if 0 /* NM_IGNORED */
+/* Return a nulstr for a standard cascade of configuration directories,
+ * suitable to pass to conf_files_list_nulstr or config_parse_many. */
+#define CONF_DIRS_NULSTR(n) \
+ "/etc/" n ".d\0" \
+ "/run/" n ".d\0" \
+ "/usr/local/lib/" n ".d\0" \
+ "/usr/lib/" n ".d\0" \
+ CONF_DIR_SPLIT_USR(n)
+
+#ifdef HAVE_SPLIT_USR
+#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
+#else
+#define CONF_DIR_SPLIT_USR(n)
+#endif
+
/* Define C11 thread_local attribute even on older gcc compiler
* version */
#ifndef thread_local
@@ -394,13 +432,14 @@ do { \
* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
* see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
*/
-#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
#define thread_local _Thread_local
#else
#define thread_local __thread
#endif
#endif
+#if 0 /* NM_IGNORED */
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef noreturn
@@ -411,5 +450,16 @@ do { \
#endif
#endif
-#include "log.h"
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+#define MODE_INVALID ((mode_t) -1)
#endif /* NM_IGNORED */
+
+#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
+ static inline void func##p(type *p) { \
+ if (*p) \
+ func(*p); \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+#include "log.h"
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/path-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/path-util.c
new file mode 100644
index 0000000000..003a790db3
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/path-util.c
@@ -0,0 +1,694 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2012 Lennart Poettering
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#if 0 /* NM_IGNORED */
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/statvfs.h>
+
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+#include "strv.h"
+#endif /* NM_IGNORED */
+#include "path-util.h"
+#if 0 /* NM_IGNORED */
+#include "missing.h"
+
+bool path_is_absolute(const char *p) {
+ return p[0] == '/';
+}
+
+bool is_path(const char *p) {
+ return !!strchr(p, '/');
+}
+
+int path_get_parent(const char *path, char **_r) {
+ const char *e, *a = NULL, *b = NULL, *p;
+ char *r;
+ bool slash = false;
+
+ assert(path);
+ assert(_r);
+
+ if (!*path)
+ return -EINVAL;
+
+ for (e = path; *e; e++) {
+
+ if (!slash && *e == '/') {
+ a = b;
+ b = e;
+ slash = true;
+ } else if (slash && *e != '/')
+ slash = false;
+ }
+
+ if (*(e-1) == '/')
+ p = a;
+ else
+ p = b;
+
+ if (!p)
+ return -EINVAL;
+
+ if (p == path)
+ r = strdup("/");
+ else
+ r = strndup(path, p-path);
+
+ if (!r)
+ return -ENOMEM;
+
+ *_r = r;
+ return 0;
+}
+
+char **path_split_and_make_absolute(const char *p) {
+ char **l;
+ assert(p);
+
+ l = strv_split(p, ":");
+ if (!l)
+ return NULL;
+
+ if (!path_strv_make_absolute_cwd(l)) {
+ strv_free(l);
+ return NULL;
+ }
+
+ return l;
+}
+
+char *path_make_absolute(const char *p, const char *prefix) {
+ assert(p);
+
+ /* Makes every item in the list an absolute path by prepending
+ * the prefix, if specified and necessary */
+
+ if (path_is_absolute(p) || !prefix)
+ return strdup(p);
+
+ return strjoin(prefix, "/", p, NULL);
+}
+
+char *path_make_absolute_cwd(const char *p) {
+ _cleanup_free_ char *cwd = NULL;
+
+ assert(p);
+
+ /* Similar to path_make_absolute(), but prefixes with the
+ * current working directory. */
+
+ if (path_is_absolute(p))
+ return strdup(p);
+
+ cwd = get_current_dir_name();
+ if (!cwd)
+ return NULL;
+
+ return strjoin(cwd, "/", p, NULL);
+}
+
+int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
+ char *r, *p;
+ unsigned n_parents;
+
+ assert(from_dir);
+ assert(to_path);
+ assert(_r);
+
+ /* Strips the common part, and adds ".." elements as necessary. */
+
+ if (!path_is_absolute(from_dir))
+ return -EINVAL;
+
+ if (!path_is_absolute(to_path))
+ return -EINVAL;
+
+ /* Skip the common part. */
+ for (;;) {
+ size_t a;
+ size_t b;
+
+ from_dir += strspn(from_dir, "/");
+ to_path += strspn(to_path, "/");
+
+ if (!*from_dir) {
+ if (!*to_path)
+ /* from_dir equals to_path. */
+ r = strdup(".");
+ else
+ /* from_dir is a parent directory of to_path. */
+ r = strdup(to_path);
+
+ if (!r)
+ return -ENOMEM;
+
+ path_kill_slashes(r);
+
+ *_r = r;
+ return 0;
+ }
+
+ if (!*to_path)
+ break;
+
+ a = strcspn(from_dir, "/");
+ b = strcspn(to_path, "/");
+
+ if (a != b)
+ break;
+
+ if (memcmp(from_dir, to_path, a) != 0)
+ break;
+
+ from_dir += a;
+ to_path += b;
+ }
+
+ /* If we're here, then "from_dir" has one or more elements that need to
+ * be replaced with "..". */
+
+ /* Count the number of necessary ".." elements. */
+ for (n_parents = 0;;) {
+ from_dir += strspn(from_dir, "/");
+
+ if (!*from_dir)
+ break;
+
+ from_dir += strcspn(from_dir, "/");
+ n_parents++;
+ }
+
+ r = malloc(n_parents * 3 + strlen(to_path) + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (p = r; n_parents > 0; n_parents--, p += 3)
+ memcpy(p, "../", 3);
+
+ strcpy(p, to_path);
+ path_kill_slashes(r);
+
+ *_r = r;
+ return 0;
+}
+
+char **path_strv_make_absolute_cwd(char **l) {
+ char **s;
+
+ /* Goes through every item in the string list and makes it
+ * absolute. This works in place and won't rollback any
+ * changes on failure. */
+
+ STRV_FOREACH(s, l) {
+ char *t;
+
+ t = path_make_absolute_cwd(*s);
+ if (!t)
+ return NULL;
+
+ free(*s);
+ *s = t;
+ }
+
+ return l;
+}
+
+char **path_strv_resolve(char **l, const char *prefix) {
+ char **s;
+ unsigned k = 0;
+ bool enomem = false;
+
+ if (strv_isempty(l))
+ return l;
+
+ /* Goes through every item in the string list and canonicalize
+ * the path. This works in place and won't rollback any
+ * changes on failure. */
+
+ STRV_FOREACH(s, l) {
+ char *t, *u;
+ _cleanup_free_ char *orig = NULL;
+
+ if (!path_is_absolute(*s)) {
+ free(*s);
+ continue;
+ }
+
+ if (prefix) {
+ orig = *s;
+ t = strappend(prefix, orig);
+ if (!t) {
+ enomem = true;
+ continue;
+ }
+ } else
+ t = *s;
+
+ errno = 0;
+ u = canonicalize_file_name(t);
+ if (!u) {
+ if (errno == ENOENT) {
+ if (prefix) {
+ u = orig;
+ orig = NULL;
+ free(t);
+ } else
+ u = t;
+ } else {
+ free(t);
+ if (errno == ENOMEM || errno == 0)
+ enomem = true;
+
+ continue;
+ }
+ } else if (prefix) {
+ char *x;
+
+ free(t);
+ x = path_startswith(u, prefix);
+ if (x) {
+ /* restore the slash if it was lost */
+ if (!startswith(x, "/"))
+ *(--x) = '/';
+
+ t = strdup(x);
+ free(u);
+ if (!t) {
+ enomem = true;
+ continue;
+ }
+ u = t;
+ } else {
+ /* canonicalized path goes outside of
+ * prefix, keep the original path instead */
+ free(u);
+ u = orig;
+ orig = NULL;
+ }
+ } else
+ free(t);
+
+ l[k++] = u;
+ }
+
+ l[k] = NULL;
+
+ if (enomem)
+ return NULL;
+
+ return l;
+}
+
+char **path_strv_resolve_uniq(char **l, const char *prefix) {
+
+ if (strv_isempty(l))
+ return l;
+
+ if (!path_strv_resolve(l, prefix))
+ return NULL;
+
+ return strv_uniq(l);
+}
+#endif /* NM_IGNORED */
+
+char *path_kill_slashes(char *path) {
+ char *f, *t;
+ bool slash = false;
+
+ /* Removes redundant inner and trailing slashes. Modifies the
+ * passed string in-place.
+ *
+ * ///foo///bar/ becomes /foo/bar
+ */
+
+ for (f = path, t = path; *f; f++) {
+
+ if (*f == '/') {
+ slash = true;
+ continue;
+ }
+
+ if (slash) {
+ slash = false;
+ *(t++) = '/';
+ }
+
+ *(t++) = *f;
+ }
+
+ /* Special rule, if we are talking of the root directory, a
+ trailing slash is good */
+
+ if (t == path && slash)
+ *(t++) = '/';
+
+ *t = 0;
+ return path;
+}
+
+#if 0 /* NM_IGNORED */
+char* path_startswith(const char *path, const char *prefix) {
+ assert(path);
+ assert(prefix);
+
+ if ((path[0] == '/') != (prefix[0] == '/'))
+ return NULL;
+
+ for (;;) {
+ size_t a, b;
+
+ path += strspn(path, "/");
+ prefix += strspn(prefix, "/");
+
+ if (*prefix == 0)
+ return (char*) path;
+
+ if (*path == 0)
+ return NULL;
+
+ a = strcspn(path, "/");
+ b = strcspn(prefix, "/");
+
+ if (a != b)
+ return NULL;
+
+ if (memcmp(path, prefix, a) != 0)
+ return NULL;
+
+ path += a;
+ prefix += b;
+ }
+}
+
+bool path_equal(const char *a, const char *b) {
+ assert(a);
+ assert(b);
+
+ if ((a[0] == '/') != (b[0] == '/'))
+ return false;
+
+ for (;;) {
+ size_t j, k;
+
+ a += strspn(a, "/");
+ b += strspn(b, "/");
+
+ if (*a == 0 && *b == 0)
+ return true;
+
+ if (*a == 0 || *b == 0)
+ return false;
+
+ j = strcspn(a, "/");
+ k = strcspn(b, "/");
+
+ if (j != k)
+ return false;
+
+ if (memcmp(a, b, j) != 0)
+ return false;
+
+ a += j;
+ b += k;
+ }
+}
+
+bool path_equal_or_files_same(const char *a, const char *b) {
+ return path_equal(a, b) || files_same(a, b) > 0;
+}
+
+char* path_join(const char *root, const char *path, const char *rest) {
+ assert(path);
+
+ if (!isempty(root))
+ return strjoin(root, endswith(root, "/") ? "" : "/",
+ path[0] == '/' ? path+1 : path,
+ rest ? (endswith(path, "/") ? "" : "/") : NULL,
+ rest && rest[0] == '/' ? rest+1 : rest,
+ NULL);
+ else
+ return strjoin(path,
+ rest ? (endswith(path, "/") ? "" : "/") : NULL,
+ rest && rest[0] == '/' ? rest+1 : rest,
+ NULL);
+}
+
+int path_is_mount_point(const char *t, bool allow_symlink) {
+
+ union file_handle_union h = FILE_HANDLE_INIT;
+ int mount_id = -1, mount_id_parent = -1;
+ _cleanup_free_ char *parent = NULL;
+ struct stat a, b;
+ int r;
+ bool nosupp = false;
+
+ /* We are not actually interested in the file handles, but
+ * name_to_handle_at() also passes us the mount ID, hence use
+ * it but throw the handle away */
+
+ if (path_equal(t, "/"))
+ return 1;
+
+ r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0);
+ if (r < 0) {
+ if (errno == ENOSYS)
+ /* This kernel does not support name_to_handle_at()
+ * fall back to the traditional stat() logic. */
+ goto fallback;
+ else if (errno == EOPNOTSUPP)
+ /* This kernel or file system does not support
+ * name_to_handle_at(), hence fallback to the
+ * traditional stat() logic */
+ nosupp = true;
+ else if (errno == ENOENT)
+ return 0;
+ else
+ return -errno;
+ }
+
+ r = path_get_parent(t, &parent);
+ if (r < 0)
+ return r;
+
+ h.handle.handle_bytes = MAX_HANDLE_SZ;
+ r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW);
+ if (r < 0)
+ if (errno == EOPNOTSUPP)
+ if (nosupp)
+ /* Neither parent nor child do name_to_handle_at()?
+ We have no choice but to fall back. */
+ goto fallback;
+ else
+ /* The parent can't do name_to_handle_at() but
+ * the directory we are interested in can?
+ * Or the other way around?
+ * If so, it must be a mount point. */
+ return 1;
+ else
+ return -errno;
+ else
+ return mount_id != mount_id_parent;
+
+fallback:
+ if (allow_symlink)
+ r = stat(t, &a);
+ else
+ r = lstat(t, &a);
+
+ if (r < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ return -errno;
+ }
+
+ free(parent);
+ parent = NULL;
+
+ r = path_get_parent(t, &parent);
+ if (r < 0)
+ return r;
+
+ r = stat(parent, &b);
+ if (r < 0)
+ return -errno;
+
+ return a.st_dev != b.st_dev;
+}
+
+int path_is_read_only_fs(const char *path) {
+ struct statvfs st;
+
+ assert(path);
+
+ if (statvfs(path, &st) < 0)
+ return -errno;
+
+ if (st.f_flag & ST_RDONLY)
+ return true;
+
+ /* On NFS, statvfs() might not reflect whether we can actually
+ * write to the remote share. Let's try again with
+ * access(W_OK) which is more reliable, at least sometimes. */
+ if (access(path, W_OK) < 0 && errno == EROFS)
+ return true;
+
+ return false;
+}
+
+int path_is_os_tree(const char *path) {
+ char *p;
+ int r;
+
+ /* We use /usr/lib/os-release as flag file if something is an OS */
+ p = strjoina(path, "/usr/lib/os-release");
+ r = access(p, F_OK);
+
+ if (r >= 0)
+ return 1;
+
+ /* Also check for the old location in /etc, just in case. */
+ p = strjoina(path, "/etc/os-release");
+ r = access(p, F_OK);
+
+ return r >= 0;
+}
+
+int find_binary(const char *name, bool local, char **filename) {
+ assert(name);
+
+ if (is_path(name)) {
+ if (local && access(name, X_OK) < 0)
+ return -errno;
+
+ if (filename) {
+ char *p;
+
+ p = path_make_absolute_cwd(name);
+ if (!p)
+ return -ENOMEM;
+
+ *filename = p;
+ }
+
+ return 0;
+ } else {
+ const char *path;
+ const char *word, *state;
+ size_t l;
+
+ /**
+ * Plain getenv, not secure_getenv, because we want
+ * to actually allow the user to pick the binary.
+ */
+ path = getenv("PATH");
+ if (!path)
+ path = DEFAULT_PATH;
+
+ FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
+ _cleanup_free_ char *p = NULL;
+
+ if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
+ return -ENOMEM;
+
+ if (access(p, X_OK) < 0)
+ continue;
+
+ if (filename) {
+ *filename = path_kill_slashes(p);
+ p = NULL;
+ }
+
+ return 0;
+ }
+
+ return -ENOENT;
+ }
+}
+
+bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
+ bool changed = false;
+ const char* const* i;
+
+ assert(timestamp);
+
+ if (paths == NULL)
+ return false;
+
+ STRV_FOREACH(i, paths) {
+ struct stat stats;
+ usec_t u;
+
+ if (stat(*i, &stats) < 0)
+ continue;
+
+ u = timespec_load(&stats.st_mtim);
+
+ /* first check */
+ if (*timestamp >= u)
+ continue;
+
+ log_debug("timestamp of '%s' changed", *i);
+
+ /* update timestamp */
+ if (update) {
+ *timestamp = u;
+ changed = true;
+ } else
+ return true;
+ }
+
+ return changed;
+}
+
+int fsck_exists(const char *fstype) {
+ _cleanup_free_ char *p = NULL, *d = NULL;
+ const char *checker;
+ int r;
+
+ checker = strjoina("fsck.", fstype);
+
+ r = find_binary(checker, true, &p);
+ if (r < 0)
+ return r;
+
+ /* An fsck that is linked to /bin/true is a non-existent
+ * fsck */
+
+ r = readlink_malloc(p, &d);
+ if (r >= 0 &&
+ (path_equal(d, "/bin/true") ||
+ path_equal(d, "/usr/bin/true") ||
+ path_equal(d, "/dev/null")))
+ return -ENOENT;
+
+ return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/path-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/path-util.h
new file mode 100644
index 0000000000..c754c60b7f
--- /dev/null
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/path-util.h
@@ -0,0 +1,75 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2012 Lennart Poettering
+
+ 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 distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "nm-sd-adapt.h"
+
+#include <stdbool.h>
+
+#include "macro.h"
+#include "time-util.h"
+
+#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
+#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin"
+
+#ifdef HAVE_SPLIT_USR
+# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
+#else
+# define DEFAULT_PATH DEFAULT_PATH_NORMAL
+#endif
+
+bool is_path(const char *p) _pure_;
+char** path_split_and_make_absolute(const char *p);
+int path_get_parent(const char *path, char **parent);
+bool path_is_absolute(const char *p) _pure_;
+char* path_make_absolute(const char *p, const char *prefix);
+char* path_make_absolute_cwd(const char *p);
+int path_make_relative(const char *from_dir, const char *to_path, char **_r);
+char* path_kill_slashes(char *path);
+char* path_startswith(const char *path, const char *prefix) _pure_;
+bool path_equal(const char *a, const char *b) _pure_;
+bool path_equal_or_files_same(const char *a, const char *b);
+char* path_join(const char *root, const char *path, const char *rest);
+
+char** path_strv_make_absolute_cwd(char **l);
+char** path_strv_resolve(char **l, const char *prefix);
+char** path_strv_resolve_uniq(char **l, const char *prefix);
+
+int path_is_mount_point(const char *path, bool allow_symlink);
+int path_is_read_only_fs(const char *path);
+int path_is_os_tree(const char *path);
+
+int find_binary(const char *name, bool local, char **filename);
+
+bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
+
+int fsck_exists(const char *fstype);
+
+/* Iterates through the path prefixes of the specified path, going up
+ * the tree, to root. Also returns "" (and not "/"!) for the root
+ * directory. Excludes the specified directory itself */
+#define PATH_FOREACH_PREFIX(prefix, path) \
+ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+
+/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
+#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
+ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
index 550ed9853b..84d57ab5e6 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
@@ -27,7 +27,6 @@
#include <netinet/in.h>
#include <netinet/ether.h>
#include <sys/un.h>
-#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/if_packet.h>
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c b/src/dhcp-manager/systemd-dhcp/src/shared/strv.c
index 74a080ff16..bd68f3fc5e 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/strv.c
@@ -21,7 +21,6 @@
#include "nm-sd-adapt.h"
-#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
@@ -71,7 +70,7 @@ char *strv_find_startswith(char **l, const char *name) {
return NULL;
}
-void strv_free(char **l) {
+void strv_clear(char **l) {
char **k;
if (!l)
@@ -80,6 +79,11 @@ void strv_free(char **l) {
for (k = l; *k; k++)
free(*k);
+ *l = NULL;
+}
+
+void strv_free(char **l) {
+ strv_clear(l);
free(l);
}
@@ -392,7 +396,7 @@ int strv_push(char ***l, char *value) {
n = strv_length(*l);
- /* increase and check for overflow */
+ /* Increase and check for overflow */
m = n + 2;
if (m < n)
return -ENOMEM;
@@ -408,6 +412,34 @@ int strv_push(char ***l, char *value) {
return 0;
}
+int strv_push_pair(char ***l, char *a, char *b) {
+ char **c;
+ unsigned n, m;
+
+ if (!a && !b)
+ return 0;
+
+ n = strv_length(*l);
+
+ /* increase and check for overflow */
+ m = n + !!a + !!b + 1;
+ if (m < n)
+ return -ENOMEM;
+
+ c = realloc_multiply(*l, sizeof(char*), m);
+ if (!c)
+ return -ENOMEM;
+
+ if (a)
+ c[n++] = a;
+ if (b)
+ c[n++] = b;
+ c[n] = NULL;
+
+ *l = c;
+ return 0;
+}
+
int strv_push_prepend(char ***l, char *value) {
char **c;
unsigned n, m, i;
@@ -448,6 +480,18 @@ int strv_consume(char ***l, char *value) {
return r;
}
+int strv_consume_pair(char ***l, char *a, char *b) {
+ int r;
+
+ r = strv_push_pair(l, a, b);
+ if (r < 0) {
+ free(a);
+ free(b);
+ }
+
+ return r;
+}
+
int strv_consume_prepend(char ***l, char *value) {
int r;
@@ -483,6 +527,16 @@ char **strv_uniq(char **l) {
return l;
}
+bool strv_is_uniq(char **l) {
+ char **i;
+
+ STRV_FOREACH(i, l)
+ if (strv_find(i+1, *i))
+ return false;
+
+ return true;
+}
+
char **strv_remove(char **l, const char *s) {
char **f, **t;
@@ -591,6 +645,17 @@ char **strv_sort(char **l) {
return l;
}
+bool strv_equal(char **a, char **b) {
+ if (!a || !b)
+ return a == b;
+
+ for ( ; *a || *b; ++a, ++b)
+ if (!streq_ptr(*a, *b))
+ return false;
+
+ return true;
+}
+
void strv_print(char **l) {
char **s;
@@ -612,3 +677,31 @@ int strv_extendf(char ***l, const char *format, ...) {
return strv_consume(l, x);
}
+
+char **strv_reverse(char **l) {
+ unsigned n, i;
+
+ n = strv_length(l);
+ if (n <= 1)
+ return l;
+
+ for (i = 0; i < n / 2; i++) {
+ char *t;
+
+ t = l[i];
+ l[i] = l[n-1-i];
+ l[n-1-i] = t;
+ }
+
+ return l;
+}
+
+bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
+ char* const* p;
+
+ STRV_FOREACH(p, patterns)
+ if (fnmatch(*p, s, 0) == 0)
+ return true;
+
+ return false;
+}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h b/src/dhcp-manager/systemd-dhcp/src/shared/strv.h
index 15ef0f1740..13c0e3bc89 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/strv.h
@@ -25,6 +25,7 @@
#include <stdarg.h>
#include <stdbool.h>
+#include <fnmatch.h>
#include "util.h"
@@ -36,6 +37,8 @@ void strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
+void strv_clear(char **l);
+
char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_;
@@ -44,12 +47,17 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_push(char ***l, char *value);
+int strv_push_pair(char ***l, char *a, char *b);
int strv_push_prepend(char ***l, char *value);
int strv_consume(char ***l, char *value);
+int strv_consume_pair(char ***l, char *a, char *b);
int strv_consume_prepend(char ***l, char *value);
char **strv_remove(char **l, const char *s);
char **strv_uniq(char **l);
+bool strv_is_uniq(char **l);
+
+bool strv_equal(char **a, char **b);
#define strv_contains(l, s) (!!strv_find((l), (s)))
@@ -137,3 +145,13 @@ void strv_print(char **l);
_l ++; \
_l[0]; \
}))
+
+char **strv_reverse(char **l);
+
+bool strv_fnmatch(char* const* patterns, const char *s, int flags);
+
+static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
+ assert(s);
+ return strv_isempty(patterns) ||
+ strv_fnmatch(patterns, s, flags);
+}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
index 5d79f15dc0..f1e56b6e47 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
@@ -507,8 +507,9 @@ int parse_timestamp(const char *t, usec_t *usec) {
return parse_sec(t + 1, usec);
else if (endswith(t, " ago")) {
- _cleanup_free_ char *z = strndup(t, strlen(t) - 4);
+ _cleanup_free_ char *z;
+ z = strndup(t, strlen(t) - 4);
if (!z)
return -ENOMEM;
@@ -518,8 +519,9 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto finish;
} else if (endswith(t, " left")) {
- _cleanup_free_ char *z = strndup(t, strlen(t) - 4);
+ _cleanup_free_ char *z;
+ z = strndup(t, strlen(t) - 4);
if (!z)
return -ENOMEM;
@@ -791,7 +793,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
s = startswith(p, "infinity");
if (s) {
s += strspn(s, WHITESPACE);
- if (!*s != 0)
+ if (*s != 0)
return -EINVAL;
*nsec = NSEC_INFINITY;
@@ -970,7 +972,7 @@ bool timezone_is_valid(const char *name) {
if (slash)
return false;
- t = strappenda("/usr/share/zoneinfo/", name);
+ t = strjoina("/usr/share/zoneinfo/", name);
if (stat(t, &st) < 0)
return false;
@@ -998,4 +1000,3 @@ clockid_t clock_boottime_or_monotonic(void) {
return clock;
}
-
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
index e3e84acbae..5d5aa10db4 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
@@ -69,7 +69,7 @@ typedef struct dual_timestamp {
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
-#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0, 0 })
+#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
usec_t now(clockid_t clock);
@@ -109,3 +109,5 @@ int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
clockid_t clock_boottime_or_monotonic(void);
+
+#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
index 261f39db84..7433f9b059 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
@@ -144,19 +144,19 @@ int utf8_encoded_to_unichar(const char *str) {
}
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
- const uint8_t *p;
+ const char *p;
assert(str);
- for (p = (const uint8_t*) str; length;) {
+ for (p = str; length;) {
int encoded_len, val;
- encoded_len = utf8_encoded_valid_unichar((const char *) p);
+ encoded_len = utf8_encoded_valid_unichar(p);
if (encoded_len < 0 ||
(size_t) encoded_len > length)
return false;
- val = utf8_encoded_to_unichar((const char*) p);
+ val = utf8_encoded_to_unichar(p);
if (val < 0 ||
is_unicode_control(val) ||
(!newline && val == '\n'))
@@ -204,7 +204,46 @@ char *utf8_escape_invalid(const char *str) {
s = mempcpy(s, str, len);
str += len;
} else {
- s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
+ s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
+ str += 1;
+ }
+ }
+
+ *s = '\0';
+
+ return p;
+}
+
+char *utf8_escape_non_printable(const char *str) {
+ char *p, *s;
+
+ assert(str);
+
+ p = s = malloc(strlen(str) * 4 + 1);
+ if (!p)
+ return NULL;
+
+ while (*str) {
+ int len;
+
+ len = utf8_encoded_valid_unichar(str);
+ if (len > 0) {
+ if (utf8_is_printable(str, len)) {
+ s = mempcpy(s, str, len);
+ str += len;
+ } else {
+ while (len > 0) {
+ *(s++) = '\\';
+ *(s++) = 'x';
+ *(s++) = hexchar((int) *str >> 4);
+ *(s++) = hexchar((int) *str);
+
+ str += 1;
+ len --;
+ }
+ }
+ } else {
+ s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
str += 1;
}
}
@@ -226,39 +265,91 @@ char *ascii_is_valid(const char *str) {
return (char*) str;
}
+/**
+ * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
+ * @out_utf8: output buffer of at least 4 bytes or NULL
+ * @g: UCS-4 character to encode
+ *
+ * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
+ * The length of the character is returned. It is not zero-terminated! If the
+ * output buffer is NULL, only the length is returned.
+ *
+ * Returns: The length in bytes that the UTF-8 representation does or would
+ * occupy.
+ */
+size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
+ if (g < (1 << 7)) {
+ if (out_utf8)
+ out_utf8[0] = g & 0x7f;
+ return 1;
+ } else if (g < (1 << 11)) {
+ if (out_utf8) {
+ out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
+ out_utf8[1] = 0x80 | (g & 0x3f);
+ }
+ return 2;
+ } else if (g < (1 << 16)) {
+ if (out_utf8) {
+ out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
+ out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
+ out_utf8[2] = 0x80 | (g & 0x3f);
+ }
+ return 3;
+ } else if (g < (1 << 21)) {
+ if (out_utf8) {
+ out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
+ out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
+ out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
+ out_utf8[3] = 0x80 | (g & 0x3f);
+ }
+ return 4;
+ } else {
+ return 0;
+ }
+}
+
char *utf16_to_utf8(const void *s, size_t length) {
- char *r;
const uint8_t *f;
- uint8_t *t;
+ char *r, *t;
- r = new(char, (length*3+1)/2 + 1);
+ r = new(char, (length * 4 + 1) / 2 + 1);
if (!r)
return NULL;
- t = (uint8_t*) r;
+ f = s;
+ t = r;
- for (f = s; f < (const uint8_t*) s + length; f += 2) {
- uint16_t c;
+ while (f < (const uint8_t*) s + length) {
+ uint16_t w1, w2;
- c = (f[1] << 8) | f[0];
+ /* see RFC 2781 section 2.2 */
- if (c == 0) {
- *t = 0;
- return r;
- } else if (c < 0x80) {
- *(t++) = (uint8_t) c;
- } else if (c < 0x800) {
- *(t++) = (uint8_t) (0xc0 | (c >> 6));
- *(t++) = (uint8_t) (0x80 | (c & 0x3f));
- } else {
- *(t++) = (uint8_t) (0xe0 | (c >> 12));
- *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
- *(t++) = (uint8_t) (0x80 | (c & 0x3f));
+ w1 = f[1] << 8 | f[0];
+ f += 2;
+
+ if (!utf16_is_surrogate(w1)) {
+ t += utf8_encode_unichar(t, w1);
+
+ continue;
}
+
+ if (utf16_is_trailing_surrogate(w1))
+ continue;
+ else if (f >= (const uint8_t*) s + length)
+ break;
+
+ w2 = f[1] << 8 | f[0];
+ f += 2;
+
+ if (!utf16_is_trailing_surrogate(w2)) {
+ f -= 2;
+ continue;
+ }
+
+ t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
}
*t = 0;
-
return r;
}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
index d7728a162f..1fb132041e 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
@@ -31,14 +31,27 @@
const char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
-char *utf8_escape_invalid(const char *s);
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
-_pure_ static inline bool utf8_is_printable(const char* str, size_t length) {
- return utf8_is_printable_newline(str, length, true);
-}
+#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
+char *utf8_escape_invalid(const char *s);
+char *utf8_escape_non_printable(const char *str);
+
+size_t utf8_encode_unichar(char *out_utf8, uint32_t g);
char *utf16_to_utf8(const void *s, size_t length);
int utf8_encoded_valid_unichar(const char *str);
int utf8_encoded_to_unichar(const char *str);
+
+static inline bool utf16_is_surrogate(uint16_t c) {
+ return (0xd800 <= c && c <= 0xdfff);
+}
+
+static inline bool utf16_is_trailing_surrogate(uint16_t c) {
+ return (0xdc00 <= c && c <= 0xdfff);
+}
+
+static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) {
+ return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
+}
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.c b/src/dhcp-manager/systemd-dhcp/src/shared/util.c
index 010243b219..d1dc229689 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/util.c
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/util.c
@@ -21,12 +21,13 @@
#include "nm-sd-adapt.h"
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
+#include <libintl.h>
+#include <locale.h>
#include <stdio.h>
#include <syslog.h>
#include <sched.h>
@@ -41,15 +42,13 @@
#include <linux/tiocl.h>
#include <termios.h>
#include <stdarg.h>
-#include <sys/inotify.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <ctype.h>
#include <sys/prctl.h>
#include <sys/utsname.h>
#include <pwd.h>
#include <netinet/ip.h>
#include <linux/kd.h>
-#include <dlfcn.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <glob.h>
@@ -62,6 +61,14 @@
#include <langinfo.h>
#include <locale.h>
#include <sys/personality.h>
+#include <sys/xattr.h>
+#include <sys/statvfs.h>
+#include <sys/file.h>
+#include <linux/fs.h>
+
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the XDG
+ * version which is really broken. */
#include <libgen.h>
#undef basename
@@ -69,6 +76,7 @@
#include <sys/auxv.h>
#endif
+#include "config.h"
#include "macro.h"
#include "util.h"
#if 0 /* NM_IGNORED */
@@ -76,9 +84,10 @@
#include "missing.h"
#include "log.h"
#include "strv.h"
-#include "label.h"
#include "mkdir.h"
+#endif /* NM_IGNORED */
#include "path-util.h"
+#if 0 /* NM_IGNORED */
#include "exit-status.h"
#include "hashmap.h"
#include "env-util.h"
@@ -88,6 +97,7 @@
#include "gunicode.h"
#include "virt.h"
#include "def.h"
+#include "sparse-endian.h"
#endif /* NM_IGNORED */
#if 0 /* NM_IGNORED */
@@ -180,6 +190,69 @@ char* first_word(const char *s, const char *word) {
return (char*) p;
}
+static size_t cescape_char(char c, char *buf) {
+ char * buf_old = buf;
+
+ switch (c) {
+
+ case '\a':
+ *(buf++) = '\\';
+ *(buf++) = 'a';
+ break;
+ case '\b':
+ *(buf++) = '\\';
+ *(buf++) = 'b';
+ break;
+ case '\f':
+ *(buf++) = '\\';
+ *(buf++) = 'f';
+ break;
+ case '\n':
+ *(buf++) = '\\';
+ *(buf++) = 'n';
+ break;
+ case '\r':
+ *(buf++) = '\\';
+ *(buf++) = 'r';
+ break;
+ case '\t':
+ *(buf++) = '\\';
+ *(buf++) = 't';
+ break;
+ case '\v':
+ *(buf++) = '\\';
+ *(buf++) = 'v';
+ break;
+ case '\\':
+ *(buf++) = '\\';
+ *(buf++) = '\\';
+ break;
+ case '"':
+ *(buf++) = '\\';
+ *(buf++) = '"';
+ break;
+ case '\'':
+ *(buf++) = '\\';
+ *(buf++) = '\'';
+ break;
+
+ default:
+ /* For special chars we prefer octal over
+ * hexadecimal encoding, simply because glib's
+ * g_strescape() does the same */
+ if ((c < ' ') || (c >= 127)) {
+ *(buf++) = '\\';
+ *(buf++) = octchar((unsigned char) c >> 6);
+ *(buf++) = octchar((unsigned char) c >> 3);
+ *(buf++) = octchar((unsigned char) c);
+ } else
+ *(buf++) = c;
+ break;
+ }
+
+ return buf - buf_old;
+}
+
int close_nointr(int fd) {
assert(fd >= 0);
@@ -298,7 +371,7 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if ((unsigned long) uid != ul)
return -ERANGE;
- /* Some libc APIs use (uid_t) -1 as special placeholder */
+ /* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return -ENXIO;
@@ -449,18 +522,24 @@ int safe_atolli(const char *s, long long int *ret_lli) {
int safe_atod(const char *s, double *ret_d) {
char *x = NULL;
double d = 0;
+ locale_t loc;
assert(s);
assert(ret_d);
- RUN_WITH_LOCALE(LC_NUMERIC_MASK, "C") {
- errno = 0;
- d = strtod(s, &x);
- }
+ loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
+ if (loc == (locale_t) 0)
+ return -errno;
- if (!x || x == s || *x || errno)
+ errno = 0;
+ d = strtod_l(s, &x, loc);
+
+ if (!x || x == s || *x || errno) {
+ freelocale(loc);
return errno ? -errno : -EINVAL;
+ }
+ freelocale(loc);
*ret_d = (double) d;
return 0;
}
@@ -468,7 +547,7 @@ int safe_atod(const char *s, double *ret_d) {
static size_t strcspn_escaped(const char *s, const char *reject) {
bool escaped = false;
- size_t n;
+ int n;
for (n=0; s[n]; n++) {
if (escaped)
@@ -478,6 +557,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
else if (strchr(reject, s[n]))
break;
}
+
/* if s ends in \, return index of previous char */
return n - escaped;
}
@@ -505,7 +585,7 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
*l = strcspn_escaped(current + 1, quotechars);
if (current[*l + 1] == '\0' ||
(current[*l + 2] && !strchr(separator, current[*l + 2]))) {
- /* right quote missing or garbage at the end*/
+ /* right quote missing or garbage at the end */
*state = current;
return NULL;
}
@@ -513,6 +593,11 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
*state = current++ + *l + 2;
} else if (quoted) {
*l = strcspn_escaped(current, separator);
+ if (current[*l] && !strchr(separator, current[*l])) {
+ /* unfinished escape */
+ *state = current;
+ return NULL;
+ }
*state = current + *l;
} else {
*l = strcspn(current, separator);
@@ -565,56 +650,6 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
return 0;
}
-
-int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
- int r;
- _cleanup_free_ char *line = NULL;
- const char *p;
-
- assert(pid >= 0);
- assert(st);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- /* Let's skip the pid and comm fields. The latter is enclosed
- * in () but does not escape any () in its value, so let's
- * skip over it manually */
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%*d " /* ppid */
- "%*d " /* pgrp */
- "%*d " /* session */
- "%*d " /* tty_nr */
- "%*d " /* tpgid */
- "%*u " /* flags */
- "%*u " /* minflt */
- "%*u " /* cminflt */
- "%*u " /* majflt */
- "%*u " /* cmajflt */
- "%*u " /* utime */
- "%*u " /* stime */
- "%*d " /* cutime */
- "%*d " /* cstime */
- "%*d " /* priority */
- "%*d " /* nice */
- "%*d " /* num_threads */
- "%*d " /* itrealvalue */
- "%llu " /* starttime */,
- st) != 1)
- return -EIO;
-
- return 0;
-}
#endif /* NM_IGNORED */
int fchmod_umask(int fd, mode_t m) {
@@ -810,19 +845,30 @@ int get_process_capeff(pid_t pid, char **capeff) {
return get_status_field(p, "\nCapEff:", capeff);
}
+static int get_process_link_contents(const char *proc_file, char **name) {
+ int r;
+
+ assert(proc_file);
+ assert(name);
+
+ r = readlink_malloc(proc_file, name);
+ if (r < 0)
+ return r == -ENOENT ? -ESRCH : r;
+
+ return 0;
+}
+
int get_process_exe(pid_t pid, char **name) {
const char *p;
char *d;
int r;
assert(pid >= 0);
- assert(name);
p = procfs_file_alloca(pid, "exe");
-
- r = readlink_malloc(p, name);
+ r = get_process_link_contents(p, name);
if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
+ return r;
d = endswith(*name, " (deleted)");
if (d)
@@ -873,6 +919,59 @@ int get_process_gid(pid_t pid, gid_t *gid) {
assert_cc(sizeof(uid_t) == sizeof(gid_t));
return get_process_id(pid, "Gid:", gid);
}
+
+int get_process_cwd(pid_t pid, char **cwd) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cwd");
+
+ return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "root");
+
+ return get_process_link_contents(p, root);
+}
+
+int get_process_environ(pid_t pid, char **env) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *outcome = NULL;
+ int c;
+ const char *p;
+ size_t allocated = 0, sz = 0;
+
+ assert(pid >= 0);
+ assert(env);
+
+ p = procfs_file_alloca(pid, "environ");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+ return -ENOMEM;
+
+ if (c == '\0')
+ outcome[sz++] = '\n';
+ else
+ sz += cescape_char(c, outcome + sz);
+ }
+
+ outcome[sz] = '\0';
+ *env = outcome;
+ outcome = NULL;
+
+ return 0;
+}
#endif /* NM_IGNORED */
char *strnappend(const char *s, const char *suffix, size_t b) {
@@ -1085,7 +1184,7 @@ char *delete_chars(char *s, const char *bad) {
}
char *file_in_same_dir(const char *path, const char *filename) {
- char *e, *r;
+ char *e, *ret;
size_t k;
assert(path);
@@ -1098,17 +1197,17 @@ char *file_in_same_dir(const char *path, const char *filename) {
if (path_is_absolute(filename))
return strdup(filename);
- if (!(e = strrchr(path, '/')))
+ e = strrchr(path, '/');
+ if (!e)
return strdup(filename);
k = strlen(filename);
- if (!(r = new(char, e-path+1+k+1)))
+ ret = new(char, (e + 1 - path) + k + 1);
+ if (!ret)
return NULL;
- memcpy(r, path, e-path+1);
- memcpy(r+(e-path)+1, filename, k+1);
-
- return r;
+ memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
+ return ret;
}
int rmdir_parents(const char *path, const char *stop) {
@@ -1258,63 +1357,7 @@ char *cescape(const char *s) {
return NULL;
for (f = s, t = r; *f; f++)
-
- switch (*f) {
-
- case '\a':
- *(t++) = '\\';
- *(t++) = 'a';
- break;
- case '\b':
- *(t++) = '\\';
- *(t++) = 'b';
- break;
- case '\f':
- *(t++) = '\\';
- *(t++) = 'f';
- break;
- case '\n':
- *(t++) = '\\';
- *(t++) = 'n';
- break;
- case '\r':
- *(t++) = '\\';
- *(t++) = 'r';
- break;
- case '\t':
- *(t++) = '\\';
- *(t++) = 't';
- break;
- case '\v':
- *(t++) = '\\';
- *(t++) = 'v';
- break;
- case '\\':
- *(t++) = '\\';
- *(t++) = '\\';
- break;
- case '"':
- *(t++) = '\\';
- *(t++) = '"';
- break;
- case '\'':
- *(t++) = '\\';
- *(t++) = '\'';
- break;
-
- default:
- /* For special chars we prefer octal over
- * hexadecimal encoding, simply because glib's
- * g_strescape() does the same */
- if ((*f < ' ') || (*f >= 127)) {
- *(t++) = '\\';
- *(t++) = octchar((unsigned char) *f >> 6);
- *(t++) = octchar((unsigned char) *f >> 3);
- *(t++) = octchar((unsigned char) *f);
- } else
- *(t++) = *f;
- break;
- }
+ t += cescape_char(*f, t);
*t = 0;
@@ -1340,12 +1383,19 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
memcpy(r, prefix, pl);
for (f = s, t = r + pl; f < s + length; f++) {
+ size_t remaining = s + length - f;
+ assert(remaining > 0);
- if (*f != '\\') {
+ if (*f != '\\') { /* a literal literal */
*(t++) = *f;
continue;
}
+ if (--remaining == 0) { /* copy trailing backslash verbatim */
+ *(t++) = *f;
+ break;
+ }
+
f++;
switch (*f) {
@@ -1388,10 +1438,12 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
case 'x': {
/* hexadecimal encoding */
- int a, b;
+ int a = -1, b = -1;
- a = unhexchar(f[1]);
- b = unhexchar(f[2]);
+ if (remaining >= 2) {
+ a = unhexchar(f[1]);
+ b = unhexchar(f[2]);
+ }
if (a < 0 || b < 0 || (a == 0 && b == 0)) {
/* Invalid escape code, let's take it literal then */
@@ -1414,11 +1466,13 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
case '6':
case '7': {
/* octal encoding */
- int a, b, c;
+ int a = -1, b = -1, c = -1;
- a = unoctchar(f[0]);
- b = unoctchar(f[1]);
- c = unoctchar(f[2]);
+ if (remaining >= 3) {
+ a = unoctchar(f[0]);
+ b = unoctchar(f[1]);
+ c = unoctchar(f[2]);
+ }
if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) {
/* Invalid escape code, let's take it literal then */
@@ -1432,11 +1486,6 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
break;
}
- case 0:
- /* premature end of string.*/
- *(t++) = '\\';
- goto finish;
-
default:
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
@@ -1445,7 +1494,6 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
}
}
-finish:
*t = 0;
return r;
}
@@ -1502,7 +1550,7 @@ char *ascii_strlower(char *t) {
return t;
}
-_pure_ static bool ignore_file_allow_backup(const char *filename) {
+_pure_ static bool hidden_file_allow_backup(const char *filename) {
assert(filename);
return
@@ -1516,16 +1564,20 @@ _pure_ static bool ignore_file_allow_backup(const char *filename) {
endswith(filename, ".dpkg-old") ||
endswith(filename, ".dpkg-new") ||
endswith(filename, ".dpkg-tmp") ||
+ endswith(filename, ".dpkg-dist") ||
+ endswith(filename, ".dpkg-bak") ||
+ endswith(filename, ".dpkg-backup") ||
+ endswith(filename, ".dpkg-remove") ||
endswith(filename, ".swp");
}
-bool ignore_file(const char *filename) {
+bool hidden_file(const char *filename) {
assert(filename);
if (endswith(filename, "~"))
return true;
- return ignore_file_allow_backup(filename);
+ return hidden_file_allow_backup(filename);
}
int fd_nonblock(int fd, bool nonblock) {
@@ -1619,7 +1671,7 @@ int close_all_fds(const int except[], unsigned n_except) {
while ((de = readdir(d))) {
int fd = -1;
- if (ignore_file(de->d_name))
+ if (hidden_file(de->d_name))
continue;
if (safe_atoi(de->d_name, &fd) < 0)
@@ -1660,6 +1712,7 @@ bool chars_intersect(const char *a, const char *b) {
#if 0 /* NM_IGNORED */
bool fstype_is_network(const char *fstype) {
static const char table[] =
+ "afs\0"
"cifs\0"
"smbfs\0"
"sshfs\0"
@@ -1681,7 +1734,7 @@ bool fstype_is_network(const char *fstype) {
}
int chvt(int vt) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd;
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
@@ -2100,9 +2153,9 @@ int acquire_terminal(
assert(notify >= 0);
for (;;) {
- uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
- ssize_t l;
+ union inotify_event_buffer buffer;
struct inotify_event *e;
+ ssize_t l;
if (timeout != USEC_INFINITY) {
usec_t n;
@@ -2123,9 +2176,8 @@ int acquire_terminal(
}
}
- l = read(notify, inotify_buffer, sizeof(inotify_buffer));
+ l = read(notify, &buffer, sizeof(buffer));
if (l < 0) {
-
if (errno == EINTR || errno == EAGAIN)
continue;
@@ -2133,21 +2185,11 @@ int acquire_terminal(
goto fail;
}
- e = (struct inotify_event*) inotify_buffer;
-
- while (l > 0) {
- size_t step;
-
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
if (e->wd != wd || !(e->mask & IN_CLOSE)) {
r = -EIO;
goto fail;
}
-
- step = sizeof(struct inotify_event) + e->len;
- assert(step <= (size_t) l);
-
- e = (struct inotify_event*) ((uint8_t*) e + step);
- l -= step;
}
break;
@@ -2164,7 +2206,7 @@ int acquire_terminal(
r = reset_terminal_fd(fd, true);
if (r < 0)
- log_warning("Failed to reset terminal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to reset terminal: %m");
return fd;
@@ -2280,21 +2322,25 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
ssize_t k;
k = read(fd, p, nbytes);
- if (k < 0 && errno == EINTR)
- continue;
+ if (k < 0) {
+ if (errno == EINTR)
+ continue;
- if (k < 0 && errno == EAGAIN && do_poll) {
+ if (errno == EAGAIN && do_poll) {
- /* We knowingly ignore any return value here,
- * and expect that any error/EOF is reported
- * via read() */
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via read() */
- fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
- continue;
+ fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+ continue;
+ }
+
+ return n > 0 ? n : -errno;
}
- if (k <= 0)
- return n > 0 ? n : (k < 0 ? -errno : 0);
+ if (k == 0)
+ return n;
p += k;
nbytes -= k;
@@ -2305,39 +2351,42 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
}
#if 0 /* NM_IGNORED */
-ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
const uint8_t *p = buf;
- ssize_t n = 0;
assert(fd >= 0);
assert(buf);
+ errno = 0;
+
while (nbytes > 0) {
ssize_t k;
k = write(fd, p, nbytes);
- if (k < 0 && errno == EINTR)
- continue;
+ if (k < 0) {
+ if (errno == EINTR)
+ continue;
- if (k < 0 && errno == EAGAIN && do_poll) {
+ if (errno == EAGAIN && do_poll) {
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via write() */
- /* We knowingly ignore any return value here,
- * and expect that any error/EOF is reported
- * via write() */
+ fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
+ continue;
+ }
- fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
- continue;
+ return -errno;
}
- if (k <= 0)
- return n > 0 ? n : (k < 0 ? -errno : 0);
+ if (k == 0) /* Can't really happen */
+ return -EIO;
p += k;
nbytes -= k;
- n += k;
}
- return n;
+ return 0;
}
int parse_size(const char *t, off_t base, off_t *size) {
@@ -2474,9 +2523,9 @@ int make_stdio(int fd) {
assert(fd >= 0);
- r = dup3(fd, STDIN_FILENO, 0);
- s = dup3(fd, STDOUT_FILENO, 0);
- t = dup3(fd, STDERR_FILENO, 0);
+ r = dup2(fd, STDIN_FILENO);
+ s = dup2(fd, STDOUT_FILENO);
+ t = dup2(fd, STDERR_FILENO);
if (fd >= 3)
safe_close(fd);
@@ -2484,7 +2533,11 @@ int make_stdio(int fd) {
if (r < 0 || s < 0 || t < 0)
return -errno;
- /* We rely here that the new fd has O_CLOEXEC not set */
+ /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
+ * dup2() was a NOP and the bit hence possibly set. */
+ fd_cloexec(STDIN_FILENO, false);
+ fd_cloexec(STDOUT_FILENO, false);
+ fd_cloexec(STDERR_FILENO, false);
return 0;
}
@@ -2527,7 +2580,7 @@ int dir_is_empty(const char *path) {
if (!de)
return 1;
- if (!ignore_file(de->d_name))
+ if (!hidden_file(de->d_name))
return 0;
}
}
@@ -2788,23 +2841,36 @@ char *getusername_malloc(void) {
return lookup_uid(getuid());
}
-int getttyname_malloc(int fd, char **r) {
- char path[PATH_MAX], *c;
- int k;
+int getttyname_malloc(int fd, char **ret) {
+ size_t l = 100;
+ int r;
- assert(r);
+ assert(fd >= 0);
+ assert(ret);
- k = ttyname_r(fd, path, sizeof(path));
- if (k > 0)
- return -k;
+ for (;;) {
+ char path[l];
- char_array_0(path);
+ r = ttyname_r(fd, path, sizeof(path));
+ if (r == 0) {
+ const char *p;
+ char *c;
- c = strdup(startswith(path, "/dev/") ? path + 5 : path);
- if (!c)
- return -ENOMEM;
+ p = startswith(path, "/dev/");
+ c = strdup(p ?: path);
+ if (!c)
+ return -ENOMEM;
+
+ *ret = c;
+ return 0;
+ }
+
+ if (r != ERANGE)
+ return -r;
+
+ l *= 2;
+ }
- *r = c;
return 0;
}
@@ -3011,6 +3077,15 @@ _pure_ static int is_temporary_fs(struct statfs *s) {
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
+int is_fd_on_temporary_fs(int fd) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_temporary_fs(&s);
+}
+
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
struct statfs s;
@@ -3063,7 +3138,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
- if (errno != ENOTDIR)
+ if (errno != ENOTDIR && errno != ELOOP)
return -errno;
if (!dangerous) {
@@ -3126,11 +3201,11 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
if (chmod(path, mode) < 0)
return -errno;
- if (uid != (uid_t) -1 || gid != (gid_t) -1)
+ if (uid != UID_INVALID || gid != GID_INVALID)
if (chown(path, uid, gid) < 0)
return -errno;
@@ -3144,11 +3219,11 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
if (fchmod(fd, mode) < 0)
return -errno;
- if (uid != (uid_t) -1 || gid != (gid_t) -1)
+ if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0)
return -errno;
@@ -3436,7 +3511,7 @@ unsigned columns(void) {
c = 80;
cached_columns = c;
- return c;
+ return cached_columns;
}
int fd_lines(int fd) {
@@ -3453,7 +3528,7 @@ int fd_lines(int fd) {
unsigned lines(void) {
const char *e;
- unsigned l;
+ int l;
if (_likely_(cached_lines > 0))
return cached_lines;
@@ -3461,7 +3536,7 @@ unsigned lines(void) {
l = 0;
e = getenv("LINES");
if (e)
- (void) safe_atou(e, &l);
+ (void) safe_atoi(e, &l);
if (l <= 0)
l = fd_lines(STDOUT_FILENO);
@@ -3621,7 +3696,7 @@ char *ellipsize(const char *s, size_t length, unsigned percent) {
}
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd;
int r;
assert(path);
@@ -3639,7 +3714,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
return -errno;
}
- if (uid != (uid_t) -1 || gid != (gid_t) -1) {
+ if (uid != UID_INVALID || gid != GID_INVALID) {
r = fchown(fd, uid, gid);
if (r < 0)
return -errno;
@@ -3660,7 +3735,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
}
int touch(const char *path) {
- return touch_file(path, false, USEC_INFINITY, (uid_t) -1, (gid_t) -1, 0);
+ return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
}
char *unquote(const char *s, const char* quotes) {
@@ -3670,7 +3745,7 @@ char *unquote(const char *s, const char* quotes) {
/* This is rather stupid, simply removes the heading and
* trailing quotes if there is one. Doesn't care about
* escaping or anything. We should make this smarter one
- * day...*/
+ * day... */
l = strlen(s);
if (l < 2)
@@ -3745,8 +3820,11 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) {
*
* That is, success is indicated by a return value of zero, and an
* error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
*/
-int wait_for_terminate_and_warn(const char *name, pid_t pid) {
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
int r;
siginfo_t status;
@@ -3754,20 +3832,17 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
assert(pid > 1);
r = wait_for_terminate(pid, &status);
- if (r < 0) {
- log_warning("Failed to wait for %s: %s", name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for %s: %m", name);
if (status.si_code == CLD_EXITED) {
- if (status.si_status != 0) {
- log_warning("%s failed with error code %i.", name, status.si_status);
- return status.si_status;
- }
-
- log_debug("%s succeeded.", name);
- return 0;
+ if (status.si_status != 0)
+ log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+ "%s failed with error code %i.", name, status.si_status);
+ else
+ log_debug("%s succeeded.", name);
+ return status.si_status;
} else if (status.si_code == CLD_KILLED ||
status.si_code == CLD_DUMPED) {
@@ -3984,13 +4059,13 @@ bool tty_is_vc_resolve(const char *tty) {
const char *default_term_for_tty(const char *tty) {
assert(tty);
- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102";
+ return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
}
bool dirent_is_file(const struct dirent *de) {
assert(de);
- if (ignore_file(de->d_name))
+ if (hidden_file(de->d_name))
return false;
if (de->d_type != DT_REG &&
@@ -4009,73 +4084,75 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
de->d_type != DT_UNKNOWN)
return false;
- if (ignore_file_allow_backup(de->d_name))
+ if (hidden_file_allow_backup(de->d_name))
return false;
return endswith(de->d_name, suffix);
}
-void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) {
- pid_t executor_pid;
- int r;
-
- assert(directory);
+static int do_execute(char **directories, usec_t timeout, char *argv[]) {
+ _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
+ _cleanup_set_free_free_ Set *seen = NULL;
+ char **directory;
- /* Executes all binaries in a directory in parallel and waits
- * for them to finish. Optionally a timeout is applied. */
+ /* We fork this all off from a child process so that we can
+ * somewhat cleanly make use of SIGALRM to set a time limit */
- executor_pid = fork();
- if (executor_pid < 0) {
- log_error("Failed to fork: %m");
- return;
+ reset_all_signal_handlers();
+ reset_signal_mask();
- } else if (executor_pid == 0) {
- _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
- _cleanup_closedir_ DIR *_d = NULL;
- struct dirent *de;
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- /* We fork this all off from a child process so that
- * we can somewhat cleanly make use of SIGALRM to set
- * a time limit */
+ pids = hashmap_new(NULL);
+ if (!pids)
+ return log_oom();
- reset_all_signal_handlers();
- reset_signal_mask();
+ seen = set_new(&string_hash_ops);
+ if (!seen)
+ return log_oom();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+ STRV_FOREACH(directory, directories) {
+ _cleanup_closedir_ DIR *d;
+ struct dirent *de;
+ d = opendir(*directory);
if (!d) {
- d = _d = opendir(directory);
- if (!d) {
- if (errno == ENOENT)
- _exit(EXIT_SUCCESS);
-
- log_error("Failed to enumerate directory %s: %m", directory);
- _exit(EXIT_FAILURE);
- }
- }
+ if (errno == ENOENT)
+ continue;
- pids = hashmap_new(NULL);
- if (!pids) {
- log_oom();
- _exit(EXIT_FAILURE);
+ return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
}
FOREACH_DIRENT(de, d, break) {
_cleanup_free_ char *path = NULL;
pid_t pid;
+ int r;
if (!dirent_is_file(de))
continue;
- path = strjoin(directory, "/", de->d_name, NULL);
- if (!path) {
- log_oom();
- _exit(EXIT_FAILURE);
+ if (set_contains(seen, de->d_name)) {
+ log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
+ continue;
}
+ r = set_put_strdup(seen, de->d_name);
+ if (r < 0)
+ return log_oom();
+
+ path = strjoin(*directory, "/", de->d_name, NULL);
+ if (!path)
+ return log_oom();
+
+ if (null_or_empty_path(path)) {
+ log_debug("%s is empty (a mask).", path);
+ continue;
+ } else
+ log_debug("%s will be executed.", path);
+
pid = fork();
if (pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
continue;
} else if (pid == 0) {
char *_argv[2];
@@ -4090,45 +4167,68 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
argv[0] = path;
execv(path, argv);
- log_error("Failed to execute %s: %m", path);
- _exit(EXIT_FAILURE);
+ return log_error_errno(errno, "Failed to execute %s: %m", path);
}
log_debug("Spawned %s as " PID_FMT ".", path, pid);
r = hashmap_put(pids, UINT_TO_PTR(pid), path);
- if (r < 0) {
- log_oom();
- _exit(EXIT_FAILURE);
- }
-
+ if (r < 0)
+ return log_oom();
path = NULL;
}
+ }
- /* Abort execution of this process after the
- * timout. We simply rely on SIGALRM as default action
- * terminating the process, and turn on alarm(). */
+ /* Abort execution of this process after the timout. We simply
+ * rely on SIGALRM as default action terminating the process,
+ * and turn on alarm(). */
- if (timeout != USEC_INFINITY)
- alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
+ if (timeout != USEC_INFINITY)
+ alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
- while (!hashmap_isempty(pids)) {
- _cleanup_free_ char *path = NULL;
- pid_t pid;
+ while (!hashmap_isempty(pids)) {
+ _cleanup_free_ char *path = NULL;
+ pid_t pid;
- pid = PTR_TO_UINT(hashmap_first_key(pids));
- assert(pid > 0);
+ pid = PTR_TO_UINT(hashmap_first_key(pids));
+ assert(pid > 0);
- path = hashmap_remove(pids, UINT_TO_PTR(pid));
- assert(path);
+ path = hashmap_remove(pids, UINT_TO_PTR(pid));
+ assert(path);
- wait_for_terminate_and_warn(path, pid);
- }
+ wait_for_terminate_and_warn(path, pid, true);
+ }
- _exit(EXIT_SUCCESS);
+ return 0;
+}
+
+void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
+ pid_t executor_pid;
+ int r;
+ char *name;
+ char **dirs = (char**) directories;
+
+ assert(!strv_isempty(dirs));
+
+ name = basename(dirs[0]);
+ assert(!isempty(name));
+
+ /* Executes all binaries in the directories in parallel and waits
+ * for them to finish. Optionally a timeout is applied. If a file
+ * with the same name exists in more than one directory, the
+ * earliest one wins. */
+
+ executor_pid = fork();
+ if (executor_pid < 0) {
+ log_error_errno(errno, "Failed to fork: %m");
+ return;
+
+ } else if (executor_pid == 0) {
+ r = do_execute(dirs, timeout, argv);
+ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
- wait_for_terminate_and_warn(directory, executor_pid);
+ wait_for_terminate_and_warn(name, executor_pid, true);
}
int kill_and_sigcont(pid_t pid, int sig) {
@@ -4186,6 +4286,11 @@ bool hostname_is_valid(const char *s) {
if (isempty(s))
return false;
+ /* Doesn't accept empty hostnames, hostnames with trailing or
+ * leading dots, and hostnames with multiple dots in a
+ * sequence. Also ensures that the length stays below
+ * HOST_NAME_MAX. */
+
for (p = s, dot = true; *p; p++) {
if (*p == '.') {
if (dot)
@@ -4295,15 +4400,15 @@ int fd_wait_for_event(int fd, int event, usec_t t) {
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
FILE *f;
char *t;
- int fd;
+ int r, fd;
assert(path);
assert(_f);
assert(_temp_path);
- t = tempfn_xxxxxx(path);
- if (!t)
- return -ENOMEM;
+ r = tempfn_xxxxxx(path, &t);
+ if (r < 0)
+ return r;
fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
@@ -4335,7 +4440,7 @@ int terminal_vhangup_fd(int fd) {
}
int terminal_vhangup(const char *name) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd;
fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
@@ -4415,13 +4520,14 @@ int vt_disallocate(const char *name) {
int symlink_atomic(const char *from, const char *to) {
_cleanup_free_ char *t = NULL;
+ int r;
assert(from);
assert(to);
- t = tempfn_random(to);
- if (!t)
- return -ENOMEM;
+ r = tempfn_random(to, &t);
+ if (r < 0)
+ return r;
if (symlink(from, t) < 0)
return -errno;
@@ -4436,12 +4542,13 @@ int symlink_atomic(const char *from, const char *to) {
int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
_cleanup_free_ char *t = NULL;
+ int r;
assert(path);
- t = tempfn_random(path);
- if (!t)
- return -ENOMEM;
+ r = tempfn_random(path, &t);
+ if (r < 0)
+ return r;
if (mknod(t, mode, dev) < 0)
return -errno;
@@ -4456,12 +4563,13 @@ int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
int mkfifo_atomic(const char *path, mode_t mode) {
_cleanup_free_ char *t = NULL;
+ int r;
assert(path);
- t = tempfn_random(path);
- if (!t)
- return -ENOMEM;
+ r = tempfn_random(path, &t);
+ if (r < 0)
+ return r;
if (mkfifo(t, mode) < 0)
return -errno;
@@ -5150,6 +5258,9 @@ char *format_bytes(char *buf, size_t l, off_t t) {
{ "K", 1024ULL },
};
+ if (t == (off_t) -1)
+ return NULL;
+
for (i = 0; i < ELEMENTSOF(table); i++) {
if (t >= table[i].factor) {
@@ -5290,7 +5401,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
* keep an unused copy of stdin around. */
fd = open("/dev/tty", O_WRONLY);
if (fd < 0) {
- log_error("Failed to open /dev/tty: %m");
+ log_error_errno(errno, "Failed to open /dev/tty: %m");
_exit(EXIT_FAILURE);
}
@@ -5401,25 +5512,56 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
return r;
}
-bool is_valid_documentation_url(const char *url) {
- assert(url);
+bool http_etag_is_valid(const char *etag) {
+ if (isempty(etag))
+ return false;
- if (startswith(url, "http://") && url[7])
- return true;
+ if (!endswith(etag, "\""))
+ return false;
- if (startswith(url, "https://") && url[8])
- return true;
+ if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
+ return false;
- if (startswith(url, "file:") && url[5])
- return true;
+ return true;
+}
- if (startswith(url, "info:") && url[5])
- return true;
+bool http_url_is_valid(const char *url) {
+ const char *p;
- if (startswith(url, "man:") && url[4])
+ if (isempty(url))
+ return false;
+
+ p = startswith(url, "http://");
+ if (!p)
+ p = startswith(url, "https://");
+ if (!p)
+ return false;
+
+ if (isempty(p))
+ return false;
+
+ return ascii_is_valid(p);
+}
+
+bool documentation_url_is_valid(const char *url) {
+ const char *p;
+
+ if (isempty(url))
+ return false;
+
+ if (http_url_is_valid(url))
return true;
- return false;
+ p = startswith(url, "file:/");
+ if (!p)
+ p = startswith(url, "info:");
+ if (!p)
+ p = startswith(url, "man:");
+
+ if (isempty(p))
+ return false;
+
+ return ascii_is_valid(p);
}
bool in_initrd(void) {
@@ -5473,16 +5615,12 @@ int make_console_stdio(void) {
/* Make /dev/console the controlling terminal and stdin/stdout/stderr */
fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
- if (fd < 0) {
- log_error("Failed to acquire terminal: %s", strerror(-fd));
- return fd;
- }
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to acquire terminal: %m");
r = make_stdio(fd);
- if (r < 0) {
- log_error("Failed to duplicate terminal fd: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to duplicate terminal fd: %m");
return 0;
}
@@ -5580,8 +5718,9 @@ int get_shell(char **_s) {
*_s = s;
return 0;
}
+#endif /* NM_IGNORED */
-bool filename_is_safe(const char *p) {
+bool filename_is_valid(const char *p) {
if (isempty(p))
return false;
@@ -5601,6 +5740,7 @@ bool filename_is_safe(const char *p) {
return true;
}
+#if 0 /* NM_IGNORED */
bool string_is_safe(const char *p) {
const char *t;
@@ -5687,6 +5827,11 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
return NULL;
}
+void init_gettext(void) {
+ setlocale(LC_ALL, "");
+ textdomain(GETTEXT_PACKAGE);
+}
+
bool is_locale_utf8(void) {
const char *set;
static int cached_answer = -1;
@@ -5914,7 +6059,7 @@ int on_ac_power(void) {
if (!de)
break;
- if (ignore_file(de->d_name))
+ if (hidden_file(de->d_name))
continue;
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -6241,38 +6386,16 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
}
int shall_restore_state(void) {
- _cleanup_free_ char *line = NULL;
- const char *p;
+ _cleanup_free_ char *value = NULL;
int r;
- r = proc_cmdline(&line);
+ r = get_proc_cmdline_key("systemd.restore_state=", &value);
if (r < 0)
return r;
+ if (r == 0)
+ return true;
- r = 1;
- p = line;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- const char *e;
- int k;
-
- k = unquote_first_word(&p, &word, true);
- if (k < 0)
- return k;
- if (k == 0)
- break;
-
- e = startswith(word, "systemd.restore_state=");
- if (!e)
- continue;
-
- k = parse_boolean(e);
- if (k >= 0)
- r = k;
- }
-
- return r;
+ return parse_boolean(value) != 0;
}
int proc_cmdline(char **ret) {
@@ -6323,6 +6446,59 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
return 0;
}
+int get_proc_cmdline_key(const char *key, char **value) {
+ _cleanup_free_ char *line = NULL, *ret = NULL;
+ bool found = false;
+ const char *p;
+ int r;
+
+ assert(key);
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ p = line;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ const char *e;
+
+ r = unquote_first_word(&p, &word, true);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ /* Filter out arguments that are intended only for the
+ * initrd */
+ if (!in_initrd() && startswith(word, "rd."))
+ continue;
+
+ if (value) {
+ e = startswith(word, key);
+ if (!e)
+ continue;
+
+ r = free_and_strdup(&ret, e);
+ if (r < 0)
+ return r;
+
+ found = true;
+ } else {
+ if (streq(word, key))
+ found = true;
+ }
+ }
+
+ if (value) {
+ *value = ret;
+ ret = NULL;
+ }
+
+ return found;
+
+}
+
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
@@ -6332,7 +6508,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
assert(machine);
assert(pid);
- p = strappenda("/run/systemd/machines/", machine);
+ p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
if (r == -ENOENT)
return -EHOSTDOWN;
@@ -6493,6 +6669,10 @@ int getpeercred(int fd, struct ucred *ucred) {
* to namespacing issues */
if (u.pid <= 0)
return -ENODATA;
+ if (u.uid == UID_INVALID)
+ return -ENODATA;
+ if (u.gid == GID_INVALID)
+ return -ENODATA;
*ucred = u;
return 0;
@@ -6569,7 +6749,7 @@ int open_tmpfile(const char *path, int flags) {
#endif
/* Fall back to unguessable name + unlinking */
- p = strappenda(path, "/systemd-tmp-XXXXXX");
+ p = strjoina(path, "/systemd-tmp-XXXXXX");
fd = mkostemp_safe(p, flags);
if (fd < 0)
@@ -6657,23 +6837,6 @@ uint64_t physical_memory(void) {
return (uint64_t) mem * (uint64_t) page_size();
}
-char* mount_test_option(const char *haystack, const char *needle) {
-
- struct mntent me = {
- .mnt_opts = (char*) haystack
- };
-
- assert(needle);
-
- /* Like glibc's hasmntopt(), but works on a string, not a
- * struct mntent */
-
- if (!haystack)
- return NULL;
-
- return hasmntopt(&me, needle);
-}
-
void hexdump(FILE *f, const void *p, size_t s) {
const uint8_t *b = p;
unsigned n = 0;
@@ -6798,6 +6961,15 @@ int umount_recursive(const char *prefix, int flags) {
return r ? r : n;
}
+static int get_mount_flags(const char *path, unsigned long *flags) {
+ struct statvfs buf;
+
+ if (statvfs(path, &buf) < 0)
+ return -errno;
+ *flags = buf.f_flag;
+ return 0;
+}
+
int bind_remount_recursive(const char *prefix, bool ro) {
_cleanup_set_free_free_ Set *done = NULL;
_cleanup_free_ char *cleaned = NULL;
@@ -6832,6 +7004,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
_cleanup_set_free_free_ Set *todo = NULL;
bool top_autofs = false;
char *x;
+ unsigned long orig_flags;
todo = set_new(&string_hash_ops);
if (!todo)
@@ -6909,7 +7082,11 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
return -errno;
- if (mount(NULL, prefix, NULL, MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+ orig_flags = 0;
+ (void) get_mount_flags(cleaned, &orig_flags);
+ orig_flags &= ~MS_RDONLY;
+
+ if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
return -errno;
x = strdup(cleaned);
@@ -6929,7 +7106,14 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (r < 0)
return r;
- if (mount(NULL, x, NULL, MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
+ /* Try to reuse the original flag set, but
+ * don't care for errors, in case of
+ * obstructed mounts */
+ orig_flags = 0;
+ (void) get_mount_flags(x, &orig_flags);
+ orig_flags &= ~MS_RDONLY;
+
+ if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
/* Deal with mount points that are
* obstructed by a later mount */
@@ -6955,43 +7139,62 @@ int fflush_and_check(FILE *f) {
return 0;
}
-char *tempfn_xxxxxx(const char *p) {
+int tempfn_xxxxxx(const char *p, char **ret) {
const char *fn;
char *t;
- size_t k;
assert(p);
+ assert(ret);
- t = new(char, strlen(p) + 1 + 6 + 1);
- if (!t)
- return NULL;
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#waldoXXXXXX
+ */
fn = basename(p);
- k = fn - p;
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ t = new(char, strlen(p) + 2 + 6 + 1);
+ if (!t)
+ return -ENOMEM;
- strcpy(stpcpy(stpcpy(mempcpy(t, p, k), "."), fn), "XXXXXX");
+ strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX");
- return t;
+ *ret = path_kill_slashes(t);
+ return 0;
}
#if 0 /* NM_IGNORED */
-char *tempfn_random(const char *p) {
+int tempfn_random(const char *p, char **ret) {
const char *fn;
char *t, *x;
uint64_t u;
- size_t k;
unsigned i;
assert(p);
+ assert(ret);
- t = new(char, strlen(p) + 1 + 16 + 1);
- if (!t)
- return NULL;
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#waldobaa2a261115984a9
+ */
fn = basename(p);
- k = fn - p;
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ t = new(char, strlen(p) + 2 + 16 + 1);
+ if (!t)
+ return -ENOMEM;
- x = stpcpy(stpcpy(mempcpy(t, p, k), "."), fn);
+ x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn);
u = random_u64();
for (i = 0; i < 16; i++) {
@@ -7001,7 +7204,40 @@ char *tempfn_random(const char *p) {
*x = 0;
- return t;
+ *ret = path_kill_slashes(t);
+ return 0;
+}
+
+int tempfn_random_child(const char *p, char **ret) {
+ char *t, *x;
+ uint64_t u;
+ unsigned i;
+
+ assert(p);
+ assert(ret);
+
+ /* Turns this:
+ * /foo/bar/waldo
+ * Into this:
+ * /foo/bar/waldo/.#3c2b6219aa75d7d0
+ */
+
+ t = new(char, strlen(p) + 3 + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ x = stpcpy(stpcpy(t, p), "/.#");
+
+ u = random_u64();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(u & 0xF);
+ u >>= 4;
+ }
+
+ *x = 0;
+
+ *ret = path_kill_slashes(t);
+ return 0;
}
#endif /* NM_IGNORED */
@@ -7046,7 +7282,7 @@ int take_password_lock(const char *root) {
* awfully racy, and thus we just won't do them. */
if (root)
- path = strappenda(root, "/etc/.pwd.lock");
+ path = strjoina(root, "/etc/.pwd.lock");
else
path = "/etc/.pwd.lock";
@@ -7342,5 +7578,598 @@ int sethostname_idempotent(const char *s) {
return 1;
}
+
+int ptsname_malloc(int fd, char **ret) {
+ size_t l = 100;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ for (;;) {
+ char *c;
+
+ c = new(char, l);
+ if (!c)
+ return -ENOMEM;
+
+ if (ptsname_r(fd, c, l) == 0) {
+ *ret = c;
+ return 0;
+ }
+ if (errno != ERANGE) {
+ free(c);
+ return -errno;
+ }
+
+ free(c);
+ l *= 2;
+ }
+}
+
+int openpt_in_namespace(pid_t pid, int flags) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ siginfo_t si;
+ pid_t child;
+ int r;
+
+ assert(pid > 0);
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ int master;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ master = posix_openpt(flags);
+ if (master < 0)
+ _exit(EXIT_FAILURE);
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
+
+ mh.msg_controllen = cmsg->cmsg_len;
+
+ if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return -EIO;
+
+ if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
+ return -errno;
+
+ for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ int *fds;
+ unsigned n_fds;
+
+ fds = (int*) CMSG_DATA(cmsg);
+ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+ if (n_fds != 1) {
+ close_many(fds, n_fds);
+ return -EIO;
+ }
+
+ return fds[0];
+ }
+
+ return -EIO;
+}
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+ _cleanup_close_ int fd = -1;
+ ssize_t l;
+
+ /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
+
+ fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+ if (fd < 0)
+ return -errno;
+
+ l = fgetxattr(fd, attribute, value, size);
+ if (l < 0)
+ return -errno;
+
+ return l;
+}
+
+static int parse_crtime(le64_t le, usec_t *usec) {
+ uint64_t u;
+
+ assert(usec);
+
+ u = le64toh(le);
+ if (u == 0 || u == (uint64_t) -1)
+ return -EIO;
+
+ *usec = (usec_t) u;
+ return 0;
+}
+
+int fd_getcrtime(int fd, usec_t *usec) {
+ le64_t le;
+ ssize_t n;
+
+ assert(fd >= 0);
+ assert(usec);
+
+ /* Until Linux gets a real concept of birthtime/creation time,
+ * let's fake one with xattrs */
+
+ n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
+ le64_t le;
+ ssize_t n;
+
+ n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int path_getcrtime(const char *p, usec_t *usec) {
+ le64_t le;
+ ssize_t n;
+
+ assert(p);
+ assert(usec);
+
+ n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int fd_setcrtime(int fd, usec_t usec) {
+ le64_t le;
+
+ assert(fd >= 0);
+
+ if (usec <= 0)
+ usec = now(CLOCK_REALTIME);
+
+ le = htole64((uint64_t) usec);
+ if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int same_fd(int a, int b) {
+ struct stat sta, stb;
+ pid_t pid;
+ int r, fa, fb;
+
+ assert(a >= 0);
+ assert(b >= 0);
+
+ /* Compares two file descriptors. Note that semantics are
+ * quite different depending on whether we have kcmp() or we
+ * don't. If we have kcmp() this will only return true for
+ * dup()ed file descriptors, but not otherwise. If we don't
+ * have kcmp() this will also return true for two fds of the same
+ * file, created by separate open() calls. Since we use this
+ * call mostly for filtering out duplicates in the fd store
+ * this difference hopefully doesn't matter too much. */
+
+ if (a == b)
+ return true;
+
+ /* Try to use kcmp() if we have it. */
+ pid = getpid();
+ r = kcmp(pid, pid, KCMP_FILE, a, b);
+ if (r == 0)
+ return true;
+ if (r > 0)
+ return false;
+ if (errno != ENOSYS)
+ return -errno;
+
+ /* We don't have kcmp(), use fstat() instead. */
+ if (fstat(a, &sta) < 0)
+ return -errno;
+
+ if (fstat(b, &stb) < 0)
+ return -errno;
+
+ if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
+ return false;
+
+ /* We consider all device fds different, since two device fds
+ * might refer to quite different device contexts even though
+ * they share the same inode and backing dev_t. */
+
+ if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
+ return false;
+
+ if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
+ return false;
+
+ /* The fds refer to the same inode on disk, let's also check
+ * if they have the same fd flags. This is useful to
+ * distuingish the read and write side of a pipe created with
+ * pipe(). */
+ fa = fcntl(a, F_GETFL);
+ if (fa < 0)
+ return -errno;
+
+ fb = fcntl(b, F_GETFL);
+ if (fb < 0)
+ return -errno;
+
+ return fa == fb;
+}
+
+int chattr_fd(int fd, bool b, unsigned mask) {
+ unsigned old_attr, new_attr;
+
+ assert(fd >= 0);
+
+ if (mask == 0)
+ return 0;
+
+ if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+ return -errno;
+
+ if (b)
+ new_attr = old_attr | mask;
+ else
+ new_attr = old_attr & ~mask;
+
+ if (new_attr == old_attr)
+ return 0;
+
+ if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int chattr_path(const char *p, bool b, unsigned mask) {
+ _cleanup_close_ int fd = -1;
+
+ assert(p);
+
+ if (mask == 0)
+ return 0;
+
+ fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return chattr_fd(fd, b, mask);
+}
+
+int read_attr_fd(int fd, unsigned *ret) {
+ assert(fd >= 0);
+
+ if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int read_attr_path(const char *p, unsigned *ret) {
+ _cleanup_close_ int fd = -1;
+
+ assert(p);
+ assert(ret);
+
+ fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return read_attr_fd(fd, ret);
+}
+
+int make_lock_file(const char *p, int operation, LockFile *ret) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ /*
+ * We use UNPOSIX locks if they are available. They have nice
+ * semantics, and are mostly compatible with NFS. However,
+ * they are only available on new kernels. When we detect we
+ * are running on an older kernel, then we fall back to good
+ * old BSD locks. They also have nice semantics, but are
+ * slightly problematic on NFS, where they are upgraded to
+ * POSIX locks, even though locally they are orthogonal to
+ * POSIX locks.
+ */
+
+ t = strdup(p);
+ if (!t)
+ return -ENOMEM;
+
+ for (;;) {
+ struct flock fl = {
+ .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
+ .l_whence = SEEK_SET,
+ };
+ struct stat st;
+
+ fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
+ if (fd < 0)
+ return -errno;
+
+ r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
+ if (r < 0) {
+
+ /* If the kernel is too old, use good old BSD locks */
+ if (errno == EINVAL)
+ r = flock(fd, operation);
+
+ if (r < 0)
+ return errno == EAGAIN ? -EBUSY : -errno;
+ }
+
+ /* If we acquired the lock, let's check if the file
+ * still exists in the file system. If not, then the
+ * previous exclusive owner removed it and then closed
+ * it. In such a case our acquired lock is worthless,
+ * hence try again. */
+
+ r = fstat(fd, &st);
+ if (r < 0)
+ return -errno;
+ if (st.st_nlink > 0)
+ break;
+
+ fd = safe_close(fd);
+ }
+
+ ret->path = t;
+ ret->fd = fd;
+ ret->operation = operation;
+
+ fd = -1;
+ t = NULL;
+
+ return r;
+}
+
+int make_lock_file_for(const char *p, int operation, LockFile *ret) {
+ const char *fn;
+ char *t;
+
+ assert(p);
+ assert(ret);
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ t = newa(char, strlen(p) + 2 + 4 + 1);
+ stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
+
+ return make_lock_file(t, operation, ret);
+}
+
+void release_lock_file(LockFile *f) {
+ int r;
+
+ if (!f)
+ return;
+
+ if (f->path) {
+
+ /* If we are the exclusive owner we can safely delete
+ * the lock file itself. If we are not the exclusive
+ * owner, we can try becoming it. */
+
+ if (f->fd >= 0 &&
+ (f->operation & ~LOCK_NB) == LOCK_SH) {
+ static const struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ };
+
+ r = fcntl(f->fd, F_OFD_SETLK, &fl);
+ if (r < 0 && errno == EINVAL)
+ r = flock(f->fd, LOCK_EX|LOCK_NB);
+
+ if (r >= 0)
+ f->operation = LOCK_EX|LOCK_NB;
+ }
+
+ if ((f->operation & ~LOCK_NB) == LOCK_EX)
+ unlink_noerrno(f->path);
+
+ free(f->path);
+ f->path = NULL;
+ }
+
+ f->fd = safe_close(f->fd);
+ f->operation = 0;
+}
+
+static size_t nul_length(const uint8_t *p, size_t sz) {
+ size_t n = 0;
+
+ while (sz > 0) {
+ if (*p != 0)
+ break;
+
+ n++;
+ p++;
+ sz--;
+ }
+
+ return n;
+}
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
+ const uint8_t *q, *w, *e;
+ ssize_t l;
+
+ q = w = p;
+ e = q + sz;
+ while (q < e) {
+ size_t n;
+
+ n = nul_length(q, e - q);
+
+ /* If there are more than the specified run length of
+ * NUL bytes, or if this is the beginning or the end
+ * of the buffer, then seek instead of write */
+ if ((n > run_length) ||
+ (n > 0 && q == p) ||
+ (n > 0 && q + n >= e)) {
+ if (q > w) {
+ l = write(fd, w, q - w);
+ if (l < 0)
+ return -errno;
+ if (l != q -w)
+ return -EIO;
+ }
+
+ if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
+ return -errno;
+
+ q += n;
+ w = q;
+ } else if (n > 0)
+ q += n;
+ else
+ q ++;
+ }
+
+ if (q > w) {
+ l = write(fd, w, q - w);
+ if (l < 0)
+ return -errno;
+ if (l != q - w)
+ return -EIO;
+ }
+
+ return q - (const uint8_t*) p;
+}
+
+void sigkill_wait(pid_t *pid) {
+ if (!pid)
+ return;
+ if (*pid <= 1)
+ return;
+
+ if (kill(*pid, SIGKILL) > 0)
+ (void) wait_for_terminate(*pid, NULL);
+}
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
+ int a = 0, b = 0, c = 0;
+ int k;
+
+ assert(p);
+ assert(*p);
+ assert(priority);
+
+ if ((*p)[0] != '<')
+ return 0;
+
+ if (!strchr(*p, '>'))
+ return 0;
+
+ if ((*p)[2] == '>') {
+ c = undecchar((*p)[1]);
+ k = 3;
+ } else if ((*p)[3] == '>') {
+ b = undecchar((*p)[1]);
+ c = undecchar((*p)[2]);
+ k = 4;
+ } else if ((*p)[4] == '>') {
+ a = undecchar((*p)[1]);
+ b = undecchar((*p)[2]);
+ c = undecchar((*p)[3]);
+ k = 5;
+ } else
+ return 0;
+
+ if (a < 0 || b < 0 || c < 0 ||
+ (!with_facility && (a || b || c > 7)))
+ return 0;
+
+ if (with_facility)
+ *priority = a*100 + b*10 + c;
+ else
+ *priority = (*priority & LOG_FACMASK) | c;
+
+ *p += k;
+ return 1;
+}
#endif /* NM_IGNORED */
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
+ size_t i;
+
+ if (!key)
+ return -1;
+
+ for (i = 0; i < len; ++i)
+ if (streq_ptr(table[i], key))
+ return (ssize_t)i;
+
+ return -1;
+}
+
+#if 0 /* NM_IGNORED */
+void cmsg_close_all(struct msghdr *mh) {
+ struct cmsghdr *cmsg;
+
+ assert(mh);
+
+ for (cmsg = CMSG_FIRSTHDR(mh); cmsg; cmsg = CMSG_NXTHDR(mh, cmsg))
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+}
+#endif /* NM_IGNORED */
diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.h b/src/dhcp-manager/systemd-dhcp/src/shared/util.h
index 68b08c4016..573852f754 100644
--- a/src/dhcp-manager/systemd-dhcp/src/shared/util.h
+++ b/src/dhcp-manager/systemd-dhcp/src/shared/util.h
@@ -27,7 +27,6 @@
#include <fcntl.h>
#include <inttypes.h>
#include <time.h>
-#include <sys/time.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -36,23 +35,24 @@
#include <sched.h>
#include <limits.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
-#include <sys/resource.h>
#include <stddef.h>
#include <unistd.h>
#include <locale.h>
#include <mntent.h>
-#include <sys/socket.h>
+#include <sys/inotify.h>
#if 0 /* NM_IGNORED */
#if SIZEOF_PID_T == 4
-# define PID_FMT "%" PRIu32
+# define PID_PRI PRIi32
#elif SIZEOF_PID_T == 2
-# define PID_FMT "%" PRIu16
+# define PID_PRI PRIi16
#else
# error Unknown pid_t size
#endif
+#define PID_FMT "%" PID_PRI
#if SIZEOF_UID_T == 4
# define UID_FMT "%" PRIu32
@@ -71,7 +71,7 @@
#endif
#if SIZEOF_TIME_T == 8
-# define PRI_TIME PRIu64
+# define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4
# define PRI_TIME PRIu32
#else
@@ -118,7 +118,7 @@
#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
-size_t page_size(void);
+size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define streq(a,b) (strcmp((a),(b)) == 0)
@@ -148,6 +148,10 @@ static inline const char* true_false(bool b) {
return b ? "true" : "false";
}
+static inline const char* one_zero(bool b) {
+ return b ? "1" : "0";
+}
+
static inline const char* strempty(const char *s) {
return s ? s : "";
}
@@ -269,7 +273,6 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
-int get_starttime_of_pid(pid_t pid, unsigned long long *st);
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
@@ -301,6 +304,9 @@ int get_process_exe(pid_t pid, char **name);
int get_process_uid(pid_t pid, uid_t *uid);
int get_process_gid(pid_t pid, gid_t *gid);
int get_process_capeff(pid_t pid, char **capeff);
+int get_process_cwd(pid_t pid, char **cwd);
+int get_process_root(pid_t pid, char **root);
+int get_process_environ(pid_t pid, char **environ);
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
@@ -321,7 +327,7 @@ char *ascii_strlower(char *path);
bool dirent_is_file(const struct dirent *de) _pure_;
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
-bool ignore_file(const char *filename) _pure_;
+bool hidden_file(const char *filename) _pure_;
bool chars_intersect(const char *a, const char *b) _pure_;
@@ -346,26 +352,29 @@ static inline uint32_t random_u32(void) {
}
/* For basic lookup tables with strictly enumerated entries */
-#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
+#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
return NULL; \
return name##_table[i]; \
- } \
- scope type name##_from_string(const char *s) { \
- type i; \
- if (!s) \
- return (type) -1; \
- for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
- if (name##_table[i] && \
- streq(name##_table[i], s)) \
- return i; \
- return (type) -1; \
- } \
+ }
+
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
+
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
+ scope inline type name##_from_string(const char *s) { \
+ return (type)string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+ }
+
+#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
struct __useless_struct_to_allow_trailing_semicolon__
-#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static)
+#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
@@ -379,7 +388,7 @@ static inline uint32_t random_u32(void) {
if (!s) \
return log_oom(); \
} else { \
- r = asprintf(&s, "%u", i); \
+ r = asprintf(&s, "%i", i); \
if (r < 0) \
return log_oom(); \
} \
@@ -429,7 +438,7 @@ int sigaction_many(const struct sigaction *sa, ...);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
-ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
bool is_device_path(const char *path);
@@ -457,6 +466,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
+int is_fd_on_temporary_fs(int fd);
+
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
@@ -469,6 +480,8 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus);
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
+#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
+
int fd_columns(int fd);
unsigned columns(void);
int fd_lines(int fd);
@@ -516,7 +529,7 @@ char *unquote(const char *s, const char *quotes);
char *normalize_env_assignment(const char *s);
int wait_for_terminate(pid_t pid, siginfo_t *status);
-int wait_for_terminate_and_warn(const char *name, pid_t pid);
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
noreturn void freeze(void);
@@ -535,7 +548,7 @@ bool tty_is_console(const char *tty) _pure_;
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
-void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[]);
+void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
int kill_and_sigcont(pid_t pid, int sig);
@@ -648,7 +661,10 @@ int setrlimit_closest(int resource, const struct rlimit *rlim);
int getenv_for_pid(pid_t pid, const char *field, char **_value);
-bool is_valid_documentation_url(const char *url) _pure_;
+bool http_url_is_valid(const char *url) _pure_;
+bool documentation_url_is_valid(const char *url) _pure_;
+
+bool http_etag_is_valid(const char *etag);
bool in_initrd(void);
@@ -661,13 +677,6 @@ static inline void freep(void *p) {
free(*(void**) p);
}
-#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
- static inline void func##p(type *p) { \
- if (*p) \
- func(*p); \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
-
static inline void closep(int *fd) {
safe_close(*fd);
}
@@ -716,7 +725,7 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_
return memdup(p, a * b);
}
-bool filename_is_safe(const char *p) _pure_;
+bool filename_is_valid(const char *p) _pure_;
bool path_is_safe(const char *p) _pure_;
bool string_is_safe(const char *p) _pure_;
bool string_has_cc(const char *p, const char *ok) _pure_;
@@ -732,6 +741,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *),
void *arg);
+#define _(String) gettext (String)
+void init_gettext(void);
bool is_locale_utf8(void);
typedef enum DrawSpecialChar {
@@ -773,10 +784,19 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
on_error; \
} \
break; \
- } else if (ignore_file((de)->d_name)) \
+ } else if (hidden_file((de)->d_name)) \
continue; \
else
+#define FOREACH_DIRENT_ALL(de, d, on_error) \
+ for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
+ if (!de) { \
+ if (errno > 0) { \
+ on_error; \
+ } \
+ break; \
+ } else
+
static inline void *mempset(void *s, int c, size_t n) {
memset(s, c, n);
return (uint8_t*)s + n;
@@ -841,7 +861,7 @@ static inline unsigned u32ctz(uint32_t n) {
#endif
}
-static inline int log2i(int x) {
+static inline unsigned log2i(int x) {
assert(x > 0);
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
@@ -885,6 +905,7 @@ int unlink_noerrno(const char *path);
(void *) memset(_new_, 0, _len_); \
})
+/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
#define alloca_align(size, align) \
({ \
void *_ptr_; \
@@ -901,19 +922,19 @@ int unlink_noerrno(const char *path);
(void*)memset(_new_, 0, _size_); \
})
-#define strappenda(a, ...) \
- ({ \
- int _len = strlen(a); \
- unsigned _i; \
- char *_d_, *_p_; \
- const char *_appendees_[] = { __VA_ARGS__ }; \
- for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
- _len += strlen(_appendees_[_i]); \
- _d_ = alloca(_len + 1); \
- _p_ = stpcpy(_d_, a); \
- for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
- _p_ = stpcpy(_p_, _appendees_[_i]); \
- _d_; \
+#define strjoina(a, ...) \
+ ({ \
+ const char *_appendees_[] = { a, __VA_ARGS__ }; \
+ char *_d_, *_p_; \
+ int _len_ = 0; \
+ unsigned _i_; \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _len_ += strlen(_appendees_[_i_]); \
+ _p_ = _d_ = alloca(_len_ + 1); \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _p_ = stpcpy(_p_, _appendees_[_i_]); \
+ *_p_ = 0; \
+ _d_; \
})
#define procfs_file_alloca(pid, field) \
@@ -929,32 +950,6 @@ int unlink_noerrno(const char *path);
_r_; \
})
-struct _locale_struct_ {
- locale_t saved_locale;
- locale_t new_locale;
- bool quit;
-};
-
-static inline void _reset_locale_(struct _locale_struct_ *s) {
- PROTECT_ERRNO;
- if (s->saved_locale != (locale_t) 0)
- uselocale(s->saved_locale);
- if (s->new_locale != (locale_t) 0)
- freelocale(s->new_locale);
-}
-
-#define RUN_WITH_LOCALE(mask, loc) \
- for (_cleanup_(_reset_locale_) struct _locale_struct_ _saved_locale_ = { (locale_t) 0, (locale_t) 0, false }; \
- ({ \
- if (!_saved_locale_.quit) { \
- PROTECT_ERRNO; \
- _saved_locale_.new_locale = newlocale((mask), (loc), (locale_t) 0); \
- if (_saved_locale_.new_locale != (locale_t) 0) \
- _saved_locale_.saved_locale = uselocale(_saved_locale_.new_locale); \
- } \
- !_saved_locale_.quit; }) ; \
- _saved_locale_.quit = true)
-
bool id128_is_valid(const char *s) _pure_;
int split_pair(const char *s, const char *sep, char **l, char **r);
@@ -975,6 +970,7 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size,
int proc_cmdline(char **ret);
int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
+int get_proc_cmdline_key(const char *parameter, char **value);
int container_get_leader(const char *machine, pid_t *pid);
@@ -1001,8 +997,6 @@ const char *personality_to_string(unsigned long);
uint64_t physical_memory(void);
-char* mount_test_option(const char *haystack, const char *needle);
-
void hexdump(FILE *f, const void *p, size_t s);
#if 0 /* NM_IGNORED */
@@ -1010,6 +1004,7 @@ union file_handle_union {
struct file_handle handle;
char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
};
+#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
#endif /* NM_IGNORED */
int update_reboot_param_file(const char *param);
@@ -1020,8 +1015,9 @@ int bind_remount_recursive(const char *prefix, bool ro);
int fflush_and_check(FILE *f);
-char *tempfn_xxxxxx(const char *p);
-char *tempfn_random(const char *p);
+int tempfn_xxxxxx(const char *p, char **ret);
+int tempfn_random(const char *p, char **ret);
+int tempfn_random_child(const char *p, char **ret);
bool is_localhost(const char *hostname);
@@ -1036,3 +1032,61 @@ int unquote_many_words(const char **p, ...) _sentinel_;
int free_and_strdup(char **p, const char *s);
int sethostname_idempotent(const char *s);
+
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
+
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
+ for ((e) = &buffer.ev; \
+ (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
+ (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
+
+union inotify_event_buffer {
+ struct inotify_event ev;
+ uint8_t raw[INOTIFY_EVENT_MAX];
+};
+
+#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
+
+int ptsname_malloc(int fd, char **ret);
+
+int openpt_in_namespace(pid_t pid, int flags);
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
+
+int fd_setcrtime(int fd, usec_t usec);
+int fd_getcrtime(int fd, usec_t *usec);
+int path_getcrtime(const char *p, usec_t *usec);
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
+
+int same_fd(int a, int b);
+
+int chattr_fd(int fd, bool b, unsigned mask);
+int chattr_path(const char *p, bool b, unsigned mask);
+
+int read_attr_fd(int fd, unsigned *ret);
+int read_attr_path(const char *p, unsigned *ret);
+
+typedef struct LockFile {
+ char *path;
+ int fd;
+ int operation;
+} LockFile;
+
+int make_lock_file(const char *p, int operation, LockFile *ret);
+int make_lock_file_for(const char *p, int operation, LockFile *ret);
+void release_lock_file(LockFile *f);
+
+#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
+
+#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
+
+#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
+
+void sigkill_wait(pid_t *pid);
+#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility);
+
+void cmsg_close_all(struct msghdr *mh);
diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
index 301f306705..e2646cbbc4 100644
--- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
+++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
@@ -35,6 +35,7 @@ enum {
DHCP6_EVENT_RESEND_EXPIRE = 10,
DHCP6_EVENT_RETRANS_MAX = 11,
DHCP6_EVENT_IP_ACQUIRE = 12,
+ DHCP6_EVENT_INFORMATION_REQUEST = 13,
};
typedef struct sd_dhcp6_client sd_dhcp6_client;
@@ -49,7 +50,10 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type);
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
size_t duid_len);
-int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname);
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
+ bool enabled);
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
+ bool *enabled);
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
uint16_t option);
diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
index e72eb8be05..84008cf590 100644
--- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
+++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
@@ -29,14 +29,11 @@
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
-int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
- struct in6_addr *addr,
- uint32_t *lifetime_preferred,
- uint32_t *lifetime_valid);
-int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
- struct in6_addr *addr,
- uint32_t *lifetime_preferred,
- uint32_t *lifetime_valid);
+void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
+int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
+ struct in6_addr *addr,
+ uint32_t *lifetime_preferred,
+ uint32_t *lifetime_valid);
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h
index df9b83c4c0..da1bb2fa24 100644
--- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h
+++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h
@@ -62,7 +62,7 @@ int sd_id128_get_boot(sd_id128_t *ret);
/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16
* times. It is hence not a good idea to call this macro with an
- * expensive function as paramater or an expression with side
+ * expensive function as parameter or an expression with side
* effects */
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
@@ -108,6 +108,10 @@ _sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
}
+_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) {
+ return a.qwords[0] == 0 && a.qwords[1] == 0;
+}
+
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
_SD_END_DECLARATIONS;