From b5a2179b10a8d624f24cf22ba9c0db44f61cd7ef Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 22 May 2016 07:02:41 -0400 Subject: nspawn: remove unreachable return statement (#3320) --- src/nspawn/nspawn.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8ec058431b..ac11bcea5a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2446,10 +2446,9 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { switch (status.si_code) { case CLD_EXITED: - if (status.si_status == 0) { + if (status.si_status == 0) log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine); - - } else + else log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s failed with error code %i.", arg_machine, status.si_status); *container = CONTAINER_TERMINATED; @@ -2457,13 +2456,11 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { case CLD_KILLED: if (status.si_status == SIGINT) { - log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine); *container = CONTAINER_TERMINATED; return 0; } else if (status.si_status == SIGHUP) { - log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine); *container = CONTAINER_REBOOTED; return 0; @@ -2479,8 +2476,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { log_error("Container %s failed due to unknown reason.", arg_machine); return -EIO; } - - return r; } static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { -- cgit v1.2.3-54-g00ecf From 2d3e72365747259ba990fa380689e24f1fdd2a93 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 May 2016 14:25:02 +0200 Subject: sd-ipv4acd: drop HASH_KEY definition, as it is unused --- src/libsystemd-network/sd-ipv4acd.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index cc7436db6b..c336c6a62d 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -480,8 +480,6 @@ static bool ether_addr_is_nul(const struct ether_addr *addr) { return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0; } -#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) - int sd_ipv4acd_start(sd_ipv4acd *ll) { int r; -- cgit v1.2.3-54-g00ecf From e78f9587abfe03ae49acb388becb64c8353a6cb2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 May 2016 14:26:06 +0200 Subject: sd-ipv4acd: do not define ether_addr_is_nul() redundantly we already have ether_addr_is_null() in ether-addr-util.h, let's use it here, too. --- src/libsystemd-network/sd-ipv4acd.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index c336c6a62d..68563ad423 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -28,6 +28,7 @@ #include "alloc-util.h" #include "arp-util.h" +#include "ether-addr-util.h" #include "fd-util.h" #include "in-addr-util.h" #include "list.h" @@ -472,14 +473,6 @@ int sd_ipv4acd_is_running(sd_ipv4acd *ll) { return ll->state != IPV4ACD_STATE_INIT; } -static bool ether_addr_is_nul(const struct ether_addr *addr) { - const struct ether_addr nul_addr = {}; - - assert(addr); - - return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0; -} - int sd_ipv4acd_start(sd_ipv4acd *ll) { int r; @@ -487,7 +480,7 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { assert_return(ll->event, -EINVAL); assert_return(ll->index > 0, -EINVAL); assert_return(ll->address != 0, -EINVAL); - assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL); + assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); ll->defend_window = 0; -- cgit v1.2.3-54-g00ecf From e095f51dd16c530e56d8eb96960c0517be12d9bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 May 2016 14:26:36 +0200 Subject: ipv4acd/ipv4ll: stop using read() on SOCK_DGRAM sockets This is a follow-up to cf447cb62d01137f4cbd1cd14b83b88823542bbf. Let's generally follow the rule to not use read() on SOCK_DGRAM sockets, let's always use recv() on that. Also, don't abort IPV4ACD logic in case we read a short packet. Simply log and ignore. --- src/libsystemd-network/sd-ipv4acd.c | 32 ++++++++++++++++++++++++-------- src/libsystemd-network/test-ipv4ll.c | 9 +++++---- 2 files changed, 29 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 68563ad423..c1f43c824b 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -156,8 +156,10 @@ static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counte static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { assert(ll); - if (ll->cb) - ll->cb(ll, event, ll->userdata); + if (!ll->cb) + return; + + ll->cb(ll, event, ll->userdata); } static void ipv4acd_stop(sd_ipv4acd *ll) { @@ -347,22 +349,36 @@ static void ipv4acd_on_conflict(sd_ipv4acd *ll) { ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT); } -static int ipv4acd_on_packet(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { +static int ipv4acd_on_packet( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata) { + sd_ipv4acd *ll = userdata; struct ether_arp packet; + ssize_t n; int r; + assert(s); assert(ll); assert(fd >= 0); - r = read(fd, &packet, sizeof(struct ether_arp)); - if (r < (int) sizeof(struct ether_arp)) + n = recv(fd, &packet, sizeof(struct ether_arp), 0); + if (n < 0) { + r = log_ipv4acd_debug_errno(ll, errno, "Failed to read ARP packet: %m"); goto out; + } + if ((size_t) n != sizeof(struct ether_arp)) { + log_ipv4acd_debug(ll, "Ignoring too short ARP packet."); + return 0; + } switch (ll->state) { + case IPV4ACD_STATE_ANNOUNCING: case IPV4ACD_STATE_RUNNING: + if (ipv4acd_arp_conflict(ll, &packet)) { usec_t ts; @@ -381,15 +397,15 @@ static int ipv4acd_on_packet(sd_event_source *s, int fd, } else ipv4acd_on_conflict(ll); } - break; + case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: case IPV4ACD_STATE_WAITING_ANNOUNCE: /* BPF ensures this packet indicates a conflict */ ipv4acd_on_conflict(ll); - break; + default: assert_not_reached("Invalid state."); } diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index a233e0378c..8cdbfb8ed8 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -38,7 +38,8 @@ static int test_fd[2]; static int basic_request_handler_bind = 0; static int basic_request_handler_stop = 0; -static void* basic_request_handler_userdata = (void*)0xCABCAB; +static void* basic_request_handler_userdata = (void*) 0xCABCAB; + static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) { assert_se(userdata == basic_request_handler_userdata); @@ -181,16 +182,16 @@ static void test_basic_request(sd_event *e) { /* PROBE */ sd_event_run(e, (uint64_t) -1); - assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp)); + assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); if (extended) { /* PROBE */ sd_event_run(e, (uint64_t) -1); - assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp)); + assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); /* PROBE */ sd_event_run(e, (uint64_t) -1); - assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp)); + assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); sd_event_run(e, (uint64_t) -1); assert_se(basic_request_handler_bind == 1); -- cgit v1.2.3-54-g00ecf From f134289ac59560946e6559d9487e60c7690396ba Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 23 May 2016 11:19:14 +0300 Subject: resolved: don't stop handle messages after receiving a zero length UDP packet (#3323) Fixes: -bash-4.3# ss --udp -l -p State Recv-Q Send-Q Local Address:Port Peer Address:Port UNCONN 0 0 *:5355 *:* users:(("systemd-resolve",pid=601,fd=12)) UNCONN 0 0 :::5355 :::* users:(("systemd-resolve",pid=601,fd=14)) -bash-4.3# nping --udp -p 5355 --data-length 0 -c 1 localhost -bash-4.3# journalctl -u systemd-resolved -b --no-hostname ... May 21 14:59:22 systemd-resolved[601]: Event source llmnr-ipv4-udp (type io) returned error, disabling: Input/output error ... -bash-4.3# nping --udp -p 5355 --data-length 1000 -c 1 localhost -bash-4.3# ss --udp -l State Recv-Q Send-Q Local Address:Port Peer Address:Port UNCONN 2304 0 *:5355 *:* UNCONN 0 0 :::5355 :::* --- src/resolve/resolved-manager.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index b3ff46b5da..9600bde1e9 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -643,6 +643,8 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { mh.msg_controllen = sizeof(control); l = recvmsg(fd, &mh, 0); + if (l == 0) + return 0; if (l < 0) { if (errno == EAGAIN || errno == EINTR) return 0; @@ -650,9 +652,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { return -errno; } - if (l <= 0) - return -EIO; - assert(!(mh.msg_flags & MSG_CTRUNC)); assert(!(mh.msg_flags & MSG_TRUNC)); -- cgit v1.2.3-54-g00ecf From 15fec93be37f12ef6c36a3e8f7dbb1984e1bcfe7 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 23 May 2016 14:43:57 +0530 Subject: networkd: networkd: ndisc set SO_BINDTODEVICE on socket (#3294) From the issue #2004 we are receiving packet even if this packet is not intended for this interface. This can be reproduced. lp3s0: Updating address: 2001:db8:1:0:7e7a:91ff:fe6d:ffe2/64 (valid for 1d) wlp3s0: Updating address: fe80::7e7a:91ff:fe6d:ffe2/64 (valid forever) NDisc CLIENT: Received RA from non-link-local address ::. Ignoring. NDisc CLIENT: Received RA on wrong interface: 2 != 6. Ignoring. NDisc CLIENT: Received RA on wrong interface: 2 != 3. Ignoring. enp0s25: Updating address: 2001:db8:1:0:2ad2:44ff:fe6a:ae07/64 (valid for 1d) enp0s25: Updating address: fe80::2ad2:44ff:fe6a:ae07/64 (valid forever) NDisc CLIENT: Sent Router Solicitation NDisc CLIENT: Sent Router Solicitation NDisc CLIENT: Sent Router Solicitation NDisc CLIENT: Received RA on wrong interface: 3 != 2. Ignoring. NDisc CLIENT: Received RA on wrong interface: 3 != 6. Ignoring. NDisc CLIENT: Received RA from non-link-local address ::. Ignoring. NDisc CLIENT: Received RA on wrong interface: 2 != 6. Ignoring. NDisc CLIENT: Received RA on wrong interface: 2 != 3. Ignoring. enp0s25: Updating address: 2001:db8:1:0:2ad2:44ff:fe6a:ae07/64 (valid for 1d) enp0s25: Updating address: fe80::2ad2:44ff:fe6a:ae07/64 (valid forever) Add SO_BINDTODEVICE to socket fixes #2004 --- src/libsystemd-network/icmp6-util.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index acad9d7d6a..d81e9ebd88 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "fd-util.h" @@ -47,6 +48,7 @@ int icmp6_bind_router_solicitation(int index) { .ipv6mr_interface = index, }; _cleanup_close_ int s = -1; + char ifname[IF_NAMESIZE] = ""; int r, zero = 0, one = 1, hops = 255; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); @@ -83,6 +85,13 @@ int icmp6_bind_router_solicitation(int index) { if (r < 0) return -errno; + if (if_indextoname(index, ifname) == 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); + if (r < 0) + return -errno; + r = s; s = -1; return r; -- cgit v1.2.3-54-g00ecf From 6fb09269769634df1096663ce90fac47585eb63a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 May 2016 16:48:46 -0400 Subject: core: fix the reversed sanity check when setting StartupBlockIOWeight over dbus bus_cgroup_set_property() was rejecting if the input value was in range. Reverse it. --- src/core/dbus-cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index eef1c47c14..76f07c550d 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -623,7 +623,7 @@ int bus_cgroup_set_property( if (r < 0) return r; - if (CGROUP_BLKIO_WEIGHT_IS_OK(weight)) + if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight)) return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); if (mode != UNIT_CHECK) { -- cgit v1.2.3-54-g00ecf From 0c2d96f5f542d701d9e066ba7f164f3e94f67737 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 May 2016 16:48:46 -0400 Subject: core: fix missing newlines when writing out drop-ins for cgroup settings Except for per-device BlockIO, IO and DeviceAllow/Deny settings, all were missing newline causing the next drop-in to be concatenated at the end of the line. Fix it. --- src/core/dbus-cgroup.c | 52 +++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 76f07c550d..d6053581f8 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -260,7 +260,7 @@ static int bus_cgroup_set_transient_property( if (mode != UNIT_CHECK) { c->delegate = b; - unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no"); + unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes\n" : "Delegate=no\n"); } return 1; @@ -295,7 +295,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU); - unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); + unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes\n" : "CPUAccounting=no\n"); } return 1; @@ -315,9 +315,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) - unit_write_drop_in_private(u, mode, name, "CPUShares="); + unit_write_drop_in_private(u, mode, name, "CPUShares=\n"); else - unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares); + unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64 "\n", shares); } return 1; @@ -337,9 +337,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); + unit_write_drop_in_private(u, mode, name, "StartupCPUShares=\n"); else - unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares); + unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64 "\n", shares); } return 1; @@ -357,7 +357,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_quota_per_sec_usec = u64; unit_invalidate_cgroup(u, CGROUP_MASK_CPU); - unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000)); + unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%\n", (double) (c->cpu_quota_per_sec_usec / 10000)); } return 1; @@ -372,7 +372,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->io_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_IO); - unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no"); + unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes\n" : "IOAccounting=no\n"); } return 1; @@ -392,9 +392,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_IO); if (weight == CGROUP_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "IOWeight="); + unit_write_drop_in_private(u, mode, name, "IOWeight=\n"); else - unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight); + unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64 "\n", weight); } return 1; @@ -414,9 +414,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_IO); if (weight == CGROUP_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupIOWeight="); + unit_write_drop_in_private(u, mode, name, "StartupIOWeight=\n"); else - unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight); + unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64 "\n", weight); } return 1; @@ -589,7 +589,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->blockio_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); - unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); + unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes\n" : "BlockIOAccounting=no\n"); } return 1; @@ -609,9 +609,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); + unit_write_drop_in_private(u, mode, name, "BlockIOWeight=\n"); else - unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight); + unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64 "\n", weight); } return 1; @@ -631,9 +631,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); + unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=\n"); else - unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight); + unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64 "\n", weight); } return 1; @@ -821,7 +821,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->memory_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); - unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); + unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes\n" : "MemoryAccounting=no\n"); } return 1; @@ -838,9 +838,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (limit == (uint64_t) -1) - unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); + unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity\n"); else - unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit); + unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64 "\n", limit); } return 1; @@ -858,13 +858,9 @@ int bus_cgroup_set_property( return -EINVAL; if (mode != UNIT_CHECK) { - char *buf; - c->device_policy = p; unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); - - buf = strjoina("DevicePolicy=", policy); - unit_write_drop_in_private(u, mode, name, buf); + unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s\n", policy); } return 1; @@ -968,7 +964,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->tasks_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); - unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); + unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes\n" : "TasksAccounting=no\n"); } return 1; @@ -985,9 +981,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); if (limit == (uint64_t) -1) - unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); + unit_write_drop_in_private(u, mode, name, "TasksMax=infinity\n"); else - unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); + unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64 "\n", limit); } return 1; -- cgit v1.2.3-54-g00ecf From bee26651fc3ca2fe6bed00cb0d9c91c429e9bb57 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Tue, 24 May 2016 01:34:29 +0200 Subject: sd-device: udev-db - handle properties with empty value (#3330) The statemachine was unable to parse properties with empty values, reported in [0]. When reaching the start of the KEY, we would unconditionally read one more character before starting to look for the end-of-line. Simply look for the end-of-line from the first character. [0]: --- src/libsystemd/sd-device/sd-device.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index b1c3d5f228..2d7e482b46 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -561,7 +561,6 @@ int device_read_uevent_file(sd_device *device) { state = VALUE; - break; case VALUE: if (strchr(NEWLINE, uevent[i])) { uevent[i] = '\0'; -- cgit v1.2.3-54-g00ecf From e77813ca9f4e0735fd0e3e2caae4d7d1ee436011 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 24 May 2016 05:32:30 -0400 Subject: Revert "rules: allow users to access frame buffer devices" (#3333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 483d8bbb4c0190f419bf9fba57fb0feb1a56bea6. In [1] Michel Dänzer and Daniel Vetter wrote: >> The scenario you describe isn't possible if the Wayland compositor >> directly uses the KMS API of /dev/dri/card*, but it may be possible if >> the Wayland compositor uses the fbdev API of /dev/fb* instead (e.g. if >> weston uses its fbdev backend). > > Yeah, if both weston and your screen grabber uses native fbdev API you can > now screenshot your desktop. And since fbdev has no concept of "current > owner of the display hw" like the drm master, I think this is not fixable. > At least not just in userspace. Also even with native KMS compositors > fbdev still doesn't have the concept of ownership, which is why it doesn't > bother clearing it's buffer before KMS takes over. I agree that this > should be reverted or at least hidden better. TBH, I think that privilege separation between processes running under the same UID is tenuous. Even with drm, in common setups any user process can ptrace the "current owner of the display" and call DROP_MASTER or do whatever. It *is* possible to prevent that, e.g. by disabling ptrace using yama.ptrace_scope, or selinux, and so on, but afaik this is not commonly done. E.g. all Fedora systems pull in elfutils-default-yama-scope.rpm through dependencies which sets yama.ptrace_scope=0. And even assuming that ptrace was disabled, it is trivial to modify files on disk, communicate through dbus, etc; there is just to many ways for a non-sandboxed process to interact maliciously with the display shell to close them all off. To achieve real protection, some sort of sandboxing must be implemented, and in that case there is no need to rely on access mode on the device files, since much more stringent measures have to be implemented anyway. The situation is similar for framebuffer devices. It is common to add framebuffer users to video group to allow them unlimited access to /dev/fb*. Using uaccess would be better solution in that case. Also, since there is no "current owner" limitation like in DRM, processes running under the same UID should be able to access /proc//fd/* and gain access to the devices. Nevertheless, weston implements a suid wrapper to access the devices and then drop privileges, and this patch would make this daemon pointless. So if the weston developers feel that this change reduces security, I prefer to revert it. [1] https://lists.freedesktop.org/archives/wayland-devel/2016-May/029017.html --- src/login/70-uaccess.rules | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 886c5bfcdf..50dcd2e275 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -42,9 +42,8 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" -# DRI and frame buffer video devices +# DRI video devices SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" -SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess" # KVM SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" -- cgit v1.2.3-54-g00ecf From 6af621248f2255f9ce50b0bafdde475305dc4e57 Mon Sep 17 00:00:00 2001 From: Werner Fink Date: Wed, 18 Nov 2015 12:28:30 +0100 Subject: ask-password: ask for passphrases not only on the first console of /dev/console but also on all other consoles. This does help on e.g. mainframes where often a serial console together with other consoles are used. Even rack based servers attachted to both a serial console as well as having a virtual console do sometimes miss a connected monitor. To be able to ask on all terminal devices of /dev/console the devices are collected. If more than one device are found, then on each of the terminals a inquiring task for passphrase is forked and do not return to the caller. Every task has its own session and its own controlling terminal. If one of the tasks does handle a password, the remaining tasks will be terminated. Also let contradictory options on the command of systemd-tty-ask-password-agent fail. Spwan for each device of the system console /dev/console a own process. Replace the system call wait() with with system call waitid(). Use SIGTERM instead of SIGHUP to get unresponsive childs down. Port the collect_consoles() function forward to a pulbic and strv based function "get_kernel_consoles()" in terminal-util.c and use this in tty-ask-password-agent.c. --- src/basic/terminal-util.c | 59 ++++++ src/basic/terminal-util.h | 1 + .../tty-ask-password-agent.c | 229 +++++++++++++++++++-- 3 files changed, 272 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 9521b79daa..3189b8789d 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -50,6 +50,7 @@ #include "socket-util.h" #include "stat-util.h" #include "string-util.h" +#include "strv.h" #include "terminal-util.h" #include "time-util.h" #include "util.h" @@ -708,6 +709,64 @@ char *resolve_dev_console(char **active) { return tty; } +int get_kernel_consoles(char ***consoles) { + _cleanup_strv_free_ char **con = NULL; + _cleanup_free_ char *line = NULL; + const char *active; + int r; + + assert(consoles); + + r = read_one_line_file("/sys/class/tty/console/active", &line); + if (r < 0) + return r; + + active = line; + for (;;) { + _cleanup_free_ char *tty = NULL; + char *path; + + r = extract_first_word(&active, &tty, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + if (streq(tty, "tty0")) { + tty = mfree(tty); + r = read_one_line_file("/sys/class/tty/tty0/active", &tty); + if (r < 0) + return r; + } + + path = strappend("/dev/", tty); + if (!path) + return -ENOMEM; + + if (access(path, F_OK) < 0) { + log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path); + free(path); + continue; + } + + r = strv_consume(&con, path); + if (r < 0) + return r; + } + + if (strv_isempty(con)) { + log_debug("No devices found for system console"); + + r = strv_extend(&con, "/dev/console"); + if (r < 0) + return r; + } + + *consoles = con; + con = NULL; + return 0; +} + bool tty_is_vc_resolve(const char *tty) { _cleanup_free_ char *active = NULL; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index a7c96a77cb..b449370974 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -62,6 +62,7 @@ int ask_string(char **ret, const char *text, ...) _printf_(2, 3); int vt_disallocate(const char *name); char *resolve_dev_console(char **active); +int get_kernel_consoles(char ***consoles); bool tty_is_vc(const char *tty); bool tty_is_vc_resolve(const char *tty); bool tty_is_console(const char *tty) _pure_; diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index ee879c7b89..8851af449d 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -2,6 +2,7 @@ This file is part of systemd. Copyright 2010 Lennart Poettering + Copyright 2015 Werner Fink 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 @@ -21,12 +22,15 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#include #include #include @@ -35,8 +39,12 @@ #include "conf-parser.h" #include "def.h" #include "dirent-util.h" +#include "exit-status.h" #include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" #include "io-util.h" +#include "macro.h" #include "mkdir.h" #include "path-util.h" #include "process-util.h" @@ -57,6 +65,7 @@ static enum { static bool arg_plymouth = false; static bool arg_console = false; +static const char *arg_device = NULL; static int ask_password_plymouth( const char *message, @@ -354,7 +363,9 @@ static int parse_password(const char *filename, char **wall) { int tty_fd = -1; if (arg_console) { - tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY); + const char *con = arg_device ? arg_device : "/dev/console"; + + tty_fd = acquire_terminal(con, false, false, false, USEC_INFINITY); if (tty_fd < 0) return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m"); @@ -586,14 +597,14 @@ static int parse_argv(int argc, char *argv[]) { }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "list", no_argument, NULL, ARG_LIST }, - { "query", no_argument, NULL, ARG_QUERY }, - { "watch", no_argument, NULL, ARG_WATCH }, - { "wall", no_argument, NULL, ARG_WALL }, - { "plymouth", no_argument, NULL, ARG_PLYMOUTH }, - { "console", no_argument, NULL, ARG_CONSOLE }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "list", no_argument, NULL, ARG_LIST }, + { "query", no_argument, NULL, ARG_QUERY }, + { "watch", no_argument, NULL, ARG_WATCH }, + { "wall", no_argument, NULL, ARG_WALL }, + { "plymouth", no_argument, NULL, ARG_PLYMOUTH }, + { "console", optional_argument, NULL, ARG_CONSOLE }, {} }; @@ -635,6 +646,15 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CONSOLE: arg_console = true; + if (optarg) { + + if (isempty(optarg)) { + log_error("Empty console device path is not allowed."); + return -EINVAL; + } + + arg_device = optarg; + } break; case '?': @@ -649,9 +669,171 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } + if (arg_plymouth || arg_console) { + + if (!IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH)) { + log_error("Options --query and --watch conflict."); + return -EINVAL; + } + + if (arg_plymouth && arg_console) { + log_error("Options --plymouth and --console conflict."); + return -EINVAL; + } + } + return 1; } +/* + * To be able to ask on all terminal devices of /dev/console + * the devices are collected. If more than one device is found, + * then on each of the terminals a inquiring task is forked. + * Every task has its own session and its own controlling terminal. + * If one of the tasks does handle a password, the remaining tasks + * will be terminated. + */ +static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv[]) { + struct sigaction sig = { + .sa_handler = nop_signal_handler, + .sa_flags = SA_NOCLDSTOP | SA_RESTART, + }; + + assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0); + + assert_se(sigemptyset(&sig.sa_mask) >= 0); + assert_se(sigaction(SIGCHLD, &sig, NULL) >= 0); + + sig.sa_handler = SIG_DFL; + assert_se(sigaction(SIGHUP, &sig, NULL) >= 0); + + *pid = fork(); + if (*pid < 0) + return log_error_errno(errno, "Failed to fork process: %m"); + + if (*pid == 0) { + int ac; + + assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0); + + reset_signal_mask(); + reset_all_signal_handlers(); + + for (ac = 0; ac < argc; ac++) { + if (streq(argv[ac], "--console")) { + argv[ac] = strjoina("--console=", tty, NULL); + break; + } + } + + assert(ac < argc); + + execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv); + _exit(EXIT_FAILURE); + } + return 0; +} + +static void terminate_agents(Set *pids) { + struct timespec ts; + siginfo_t status = {}; + sigset_t set; + Iterator i; + void *p; + int r, signum; + + /* + * Request termination of the remaining processes as those + * are not required anymore. + */ + SET_FOREACH(p, pids, i) + (void) kill(PTR_TO_PID(p), SIGTERM); + + /* + * Collect the processes which have go away. + */ + assert_se(sigemptyset(&set) >= 0); + assert_se(sigaddset(&set, SIGCHLD) >= 0); + timespec_store(&ts, 50 * USEC_PER_MSEC); + + while (!set_isempty(pids)) { + + zero(status); + r = waitid(P_ALL, 0, &status, WEXITED|WNOHANG); + if (r < 0 && errno == EINTR) + continue; + + if (r == 0 && status.si_pid > 0) { + set_remove(pids, PID_TO_PTR(status.si_pid)); + continue; + } + + signum = sigtimedwait(&set, NULL, &ts); + if (signum < 0) { + if (errno != EAGAIN) + log_error_errno(errno, "sigtimedwait() failed: %m"); + break; + } + assert(signum == SIGCHLD); + } + + /* + * Kill hanging processes. + */ + SET_FOREACH(p, pids, i) { + log_warning("Failed to terminate child %d, killing it", PTR_TO_PID(p)); + (void) kill(PTR_TO_PID(p), SIGKILL); + } +} + +static int ask_on_consoles(int argc, char *argv[]) { + _cleanup_set_free_ Set *pids = NULL; + _cleanup_strv_free_ char **consoles = NULL; + siginfo_t status = {}; + char **tty; + pid_t pid; + int r; + + r = get_kernel_consoles(&consoles); + if (r < 0) + return log_error_errno(r, "Failed to determine devices of /dev/console: %m"); + + pids = set_new(NULL); + if (!pids) + return log_oom(); + + /* Start an agent on each console. */ + STRV_FOREACH(tty, consoles) { + r = ask_on_this_console(*tty, &pid, argc, argv); + if (r < 0) + return r; + + if (set_put(pids, PID_TO_PTR(pid)) < 0) + return log_oom(); + } + + /* Wait for an agent to exit. */ + for (;;) { + zero(status); + + if (waitid(P_ALL, 0, &status, WEXITED) < 0) { + if (errno == EINTR) + continue; + + return log_error_errno(errno, "waitid() failed: %m"); + } + + set_remove(pids, PID_TO_PTR(status.si_pid)); + break; + } + + if (!is_clean_exit(status.si_code, status.si_status, NULL)) + log_error("Password agent failed with: %d", status.si_status); + + terminate_agents(pids); + return 0; +} + int main(int argc, char *argv[]) { int r; @@ -665,15 +847,28 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - if (arg_console) { - (void) setsid(); - (void) release_terminal(); - } + if (arg_console && !arg_device) + /* + * Spawn for each console device a separate process. + */ + r = ask_on_consoles(argc, argv); + else { + + if (arg_device) { + /* + * Later on, a controlling terminal will be acquired, + * therefore the current process has to become a session + * leader and should not have a controlling terminal already. + */ + (void) setsid(); + (void) release_terminal(); + } - if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL)) - r = watch_passwords(); - else - r = show_passwords(); + if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL)) + r = watch_passwords(); + else + r = show_passwords(); + } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.2.3-54-g00ecf From 755700bbd4a67661f40e963faccf8cf1fef84f9a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 24 May 2016 06:07:42 -0400 Subject: Udevadm trivial cleanups (#3331) * udevadm-info: use _cleanup_ * udevadm-info: propagate return value from export_devices() * sd-device: add comment and remove unnecessary braces --- src/libsystemd/sd-device/sd-device.c | 5 ++- src/udev/udevadm-info.c | 62 +++++++++++++++--------------------- 2 files changed, 28 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 2d7e482b46..5c9e00ed80 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -533,7 +533,7 @@ int device_read_uevent_file(sd_device *device) { return r; } - for (i = 0; i < uevent_len; i++) { + for (i = 0; i < uevent_len; i++) switch (state) { case PRE_KEY: if (!strchr(NEWLINE, uevent[i])) { @@ -558,9 +558,9 @@ int device_read_uevent_file(sd_device *device) { break; case PRE_VALUE: value = &uevent[i]; - state = VALUE; + /* fall through to handle empty property */ case VALUE: if (strchr(NEWLINE, uevent[i])) { uevent[i] = '\0'; @@ -576,7 +576,6 @@ int device_read_uevent_file(sd_device *device) { default: assert_not_reached("invalid state when parsing uevent file"); } - } if (major) { r = device_set_devnum(device, major, minor); diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 7182668f23..66b51c1209 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -156,7 +156,7 @@ static int stat_device(const char *name, bool export, const char *prefix) { struct stat statbuf; if (stat(name, &statbuf) != 0) - return -1; + return -errno; if (export) { if (prefix == NULL) @@ -171,23 +171,22 @@ static int stat_device(const char *name, bool export, const char *prefix) { } static int export_devices(struct udev *udev) { - struct udev_enumerate *udev_enumerate; + _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate; struct udev_list_entry *list_entry; udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) - return -1; + return -ENOMEM; + udev_enumerate_scan_devices(udev_enumerate); udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) { - struct udev_device *device; + _cleanup_udev_device_unref_ struct udev_device *device; device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); - if (device != NULL) { + if (device != NULL) print_record(device); - udev_device_unref(device); - } } - udev_enumerate_unref(udev_enumerate); + return 0; } @@ -220,39 +219,29 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) { } static void cleanup_db(struct udev *udev) { - DIR *dir; + _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL; - unlink("/run/udev/queue.bin"); + (void) unlink("/run/udev/queue.bin"); - dir = opendir("/run/udev/data"); - if (dir != NULL) { - cleanup_dir(dir, S_ISVTX, 1); - closedir(dir); - } + dir1 = opendir("/run/udev/data"); + if (dir1 != NULL) + cleanup_dir(dir1, S_ISVTX, 1); - dir = opendir("/run/udev/links"); - if (dir != NULL) { - cleanup_dir(dir, 0, 2); - closedir(dir); - } + dir2 = opendir("/run/udev/links"); + if (dir2 != NULL) + cleanup_dir(dir2, 0, 2); - dir = opendir("/run/udev/tags"); - if (dir != NULL) { - cleanup_dir(dir, 0, 2); - closedir(dir); - } + dir3 = opendir("/run/udev/tags"); + if (dir3 != NULL) + cleanup_dir(dir3, 0, 2); - dir = opendir("/run/udev/static_node-tags"); - if (dir != NULL) { - cleanup_dir(dir, 0, 2); - closedir(dir); - } + dir4 = opendir("/run/udev/static_node-tags"); + if (dir4 != NULL) + cleanup_dir(dir4, 0, 2); - dir = opendir("/run/udev/watch"); - if (dir != NULL) { - cleanup_dir(dir, 0, 1); - closedir(dir); - } + dir5 = opendir("/run/udev/watch"); + if (dir5 != NULL) + cleanup_dir(dir5, 0, 1); } static void help(void) { @@ -374,7 +363,8 @@ static int uinfo(struct udev *udev, int argc, char *argv[]) { action = ACTION_ATTRIBUTE_WALK; break; case 'e': - export_devices(udev); + if (export_devices(udev) < 0) + return 1; return 0; case 'c': cleanup_db(udev); -- cgit v1.2.3-54-g00ecf From fbc38f230bcc296772f53898fb79cda7075025b8 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Wed, 25 May 2016 20:04:01 +0800 Subject: networkd: set IFLA_INET6_ADDR_GEN_MODE as per stable_secret Although networkd has option (LinkLocalAddressing=) to toggle IPv6LL autoconfiguration, when it is enabled, the address is autoconfigured by the kernel, but not networkd. Therefore, we do not statically set IFLA_INET6_ADDR_GEN_MODE to IN6_ADDR_GEN_MODE_EUI64, but dynamically depending on whether stable_secret is set, just as what the kernel does by default. Note that this does NOT affect the global addresses configured by networkd. --- src/basic/missing.h | 1 + src/network/networkd-link.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index 651e414395..9b4be5e3d0 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -565,6 +565,7 @@ struct btrfs_ioctl_quota_ctl_args { #define IN6_ADDR_GEN_MODE_EUI64 0 #define IN6_ADDR_GEN_MODE_NONE 1 +#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 #endif #if !HAVE_DECL_IFLA_MACVLAN_FLAGS diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a021fc886f..9d2f244087 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1607,7 +1607,20 @@ static int link_up(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m"); - ipv6ll_mode = link_ipv6ll_enabled(link) ? IN6_ADDR_GEN_MODE_EUI64 : IN6_ADDR_GEN_MODE_NONE; + if (!link_ipv6ll_enabled(link)) + ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; + else { + const char *p = NULL; + _cleanup_free_ char *stable_secret = NULL; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret"); + r = read_one_line_file(p, &stable_secret); + + if (r < 0) + ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; + else + ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + } r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); -- cgit v1.2.3-54-g00ecf From 4cef7fe3d1e8db7b1c20fb920c6e0ba05b0d2fc0 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Wed, 25 May 2016 20:40:48 +0800 Subject: networkd: Disable IPv6 when DHCPv6 is only enabled DHCPv6 requires an IPv6 link-local address to work. The client will not be started (even when enabled explicitly with `DHCP=`) if none is configured (either by autoconfiguration or manually). Therefore, disable IPv6 in such case. --- src/network/networkd-link.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9d2f244087..6e6f9618b0 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -110,7 +110,8 @@ static bool link_ipv6_enabled(Link *link) { if (!socket_ipv6_is_supported()) return false; - return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); + /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */ + return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); } static bool link_lldp_rx_enabled(Link *link) { @@ -1577,7 +1578,7 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not set MAC address: %m"); } - /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled) + /* If IPv6 not configured (no static IPv6 address and IPv6LL autoconfiguration is disabled) for this interface then disable IPv6 else enable it. */ (void) link_enable_ipv6(link); -- cgit v1.2.3-54-g00ecf From 004845d18ed31fe5ffc153699f63e58dc8b24171 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 15:56:01 +0200 Subject: sd-network: unify packet processing logic a bit Let's always check for errno being EAGAIN/EINTR the same way, and always log if we receive weirdly short packets. --- src/libsystemd-network/dhcp-internal.h | 3 ++- src/libsystemd-network/sd-dhcp-client.c | 6 +++--- src/libsystemd-network/sd-dhcp6-client.c | 12 ++++++++++-- src/libsystemd-network/sd-ipv4acd.c | 3 +++ src/libsystemd-network/sd-ndisc.c | 8 ++++++-- 5 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 4662b0d847..99f690897d 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -65,4 +65,5 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); #define DHCP_CLIENT_DONT_DESTROY(client) \ _cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) -#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) +#define log_dhcp_client_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) +#define log_dhcp_client(client, fmt, ...) log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index ad79c6cc2c..f0ad9efbc6 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1645,9 +1645,9 @@ static int client_receive_message_udp( if (errno == EAGAIN || errno == EINTR) return 0; - log_dhcp_client(client, "Could not receive message from UDP socket: %m"); - return -errno; - } else if ((size_t)len < sizeof(DHCPMessage)) { + return log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket: %m"); + } + if ((size_t) len < sizeof(DHCPMessage)) { log_dhcp_client(client, "Too small to be a DHCP message: ignoring"); return 0; } diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 05972e01c9..7dead24836 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -898,7 +898,12 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver return r; } -static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +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; @@ -924,8 +929,11 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); - } else if ((size_t)len < sizeof(DHCP6Message)) + } + if ((size_t) len < sizeof(DHCP6Message)) { + log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring"); return 0; + } switch(message->type) { case DHCP6_SOLICIT: diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index c1f43c824b..3c9fa85198 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -366,6 +366,9 @@ static int ipv4acd_on_packet( n = recv(fd, &packet, sizeof(struct ether_arp), 0); if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + r = log_ipv4acd_debug_errno(ll, errno, "Failed to read ARP packet: %m"); goto out; } diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index fb4ef55673..8d18707de1 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -517,9 +517,13 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m"); return -errno; - } else if ((size_t)len < sizeof(struct nd_router_advert)) { + } + if ((size_t) len < sizeof(struct nd_router_advert)) { + log_ndisc(nd, "Too small to be a router advertisement: ignoring"); return 0; - } else if (msg.msg_namelen == 0) + } + + if (msg.msg_namelen == 0) gw = NULL; /* only happens when running the test-suite over a socketpair */ else if (msg.msg_namelen != sizeof(sa.in6)) { log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen); -- cgit v1.2.3-54-g00ecf From 3d0b8a55f26e6924d5177d2e65670436922790c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 15:57:18 +0200 Subject: manager: remove spurious newline --- src/core/manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 7838f56fd2..14d97a87d0 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1610,9 +1610,9 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const } static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_fdset_free_ FDSet *fds = NULL; Manager *m = userdata; - char buf[NOTIFY_BUFFER_MAX+1]; struct iovec iovec = { .iov_base = buf, -- cgit v1.2.3-54-g00ecf From 16f0b479cafb745c23efb1a96ccc520fe29e8d7c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 15:57:31 +0200 Subject: sd-dhcp: shorten NUL initialization a bit --- src/libsystemd-network/sd-dhcp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index f0ad9efbc6..aa028e1d24 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1624,7 +1624,7 @@ static int client_receive_message_udp( sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; - const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; + const struct ether_addr zero_mac = {}; const struct ether_addr *expected_chaddr = NULL; uint8_t expected_hlen = 0; ssize_t len, buflen; -- cgit v1.2.3-54-g00ecf From 9c2438b84e1071a841364250f2dec2b15dafceb7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 15:57:39 +0200 Subject: sd-ndisc: properly make various parameters unsigned --- src/libsystemd-network/sd-ndisc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 8d18707de1..bb62cc21a3 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -34,8 +34,8 @@ #include "socket-util.h" #include "string-util.h" -#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC -#define NDISC_MAX_ROUTER_SOLICITATIONS 3 +#define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC) +#define NDISC_MAX_ROUTER_SOLICITATIONS 3U enum NDiscState { NDISC_STATE_IDLE, @@ -45,9 +45,9 @@ enum NDiscState { _NDISC_STATE_INVALID = -1, }; -#define IP6_MIN_MTU (unsigned)1280 +#define IP6_MIN_MTU 1280U #define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) -#define NDISC_OPT_LEN_UNITS 8 +#define NDISC_OPT_LEN_UNITS 8U #define ND_RA_FLAG_PREF 0x18 #define ND_RA_FLAG_PREF_LOW 0x03 @@ -82,7 +82,7 @@ struct sd_ndisc { int fd; sd_event_source *recv; sd_event_source *timeout; - int nd_sent; + unsigned nd_sent; sd_ndisc_router_callback_t router_callback; sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback; -- cgit v1.2.3-54-g00ecf From 2f8e763376e932395c859d0ab5a8931b7f27fe18 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:13:18 +0200 Subject: sd-network: rename "index" field of the various clients to "ifindex" A field "index" is not particularly precise and also might conflict with libc's index() function definition. Also, pretty much everywhere else we call this concept "ifindex", including in networkd, the primary user of these libraries. Hence, let's fix this up and call this "ifindex" everywhere here too. --- src/libsystemd-network/sd-dhcp-client.c | 27 +++++++++++++-------------- src/libsystemd-network/sd-dhcp6-client.c | 27 +++++++++++---------------- src/libsystemd-network/sd-ipv4acd.c | 20 ++++++++++---------- src/libsystemd-network/sd-ipv4ll.c | 5 +++-- src/libsystemd-network/sd-ndisc.c | 17 ++++++++--------- src/libsystemd-network/test-acd.c | 2 +- src/libsystemd-network/test-dhcp-client.c | 16 ++++++++-------- src/libsystemd-network/test-dhcp6-client.c | 10 +++++----- src/libsystemd-network/test-ipv4ll-manual.c | 2 +- src/libsystemd-network/test-ipv4ll.c | 12 ++++++------ src/libsystemd-network/test-ndisc-rs.c | 2 +- src/network/networkd-dhcp4.c | 2 +- src/network/networkd-dhcp6.c | 2 +- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-ndisc.c | 2 +- src/systemd/sd-dhcp-client.h | 2 +- src/systemd/sd-dhcp6-client.h | 2 +- src/systemd/sd-ipv4acd.h | 2 +- src/systemd/sd-ipv4ll.h | 2 +- src/systemd/sd-ndisc.h | 2 +- 20 files changed, 76 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index aa028e1d24..fab9f3f088 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -53,7 +53,7 @@ struct sd_dhcp_client { sd_event *event; int event_priority; sd_event_source *timeout_resend; - int index; + int ifindex; int fd; union sockaddr_union link; sd_event_source *receive_message; @@ -194,14 +194,13 @@ int sd_dhcp_client_set_request_address( return 0; } -int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { - assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); - assert_return(interface_index > 0, -EINVAL); +int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { - client->index = interface_index; + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); + assert_return(ifindex > 0, -EINVAL); + client->ifindex = ifindex; return 0; } @@ -348,7 +347,7 @@ int sd_dhcp_client_set_iaid_duid( /* If IAID is not configured, generate it. */ if (iaid == 0) { - r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); if (r < 0) @@ -565,7 +564,7 @@ static int client_message_init( client->client_id.type = 255; - r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); if (r < 0) return r; @@ -1101,7 +1100,7 @@ static int client_start_delayed(sd_dhcp_client *client) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); + assert_return(client->ifindex > 0, -EINVAL); assert_return(client->fd < 0, -EBUSY); assert_return(client->xid == 0, -EINVAL); assert_return(client->state == DHCP_STATE_INIT || @@ -1109,7 +1108,7 @@ static int client_start_delayed(sd_dhcp_client *client) { client->xid = random_u32(); - r = dhcp_network_bind_raw_socket(client->index, &client->link, + r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, client->mac_addr_len, client->arp_type); if (r < 0) { @@ -1157,7 +1156,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->state = DHCP_STATE_REBINDING; client->attempt = 1; - r = dhcp_network_bind_raw_socket(client->index, &client->link, + r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, client->mac_addr_len, client->arp_type); if (r < 0) { @@ -1778,7 +1777,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { r = client_start(client); if (r >= 0) - log_dhcp_client(client, "STARTED on ifindex %i", client->index); + log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex); return r; } @@ -1879,7 +1878,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->n_ref = 1; client->state = DHCP_STATE_INIT; - client->index = -1; + client->ifindex = -1; client->fd = -1; client->attempt = 1; client->mtu = DHCP_DEFAULT_MIN_SIZE; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7dead24836..15667c26d7 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -45,7 +45,7 @@ struct sd_dhcp6_client { enum DHCP6State state; sd_event *event; int event_priority; - int index; + int ifindex; struct in6_addr local_address; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; @@ -123,14 +123,13 @@ int sd_dhcp6_client_set_callback( return 0; } -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { - assert_return(client, -EINVAL); - assert_return(interface_index >= -1, -EINVAL); +int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) { + assert_return(client, -EINVAL); + assert_return(ifindex >= -1, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - client->index = interface_index; - + client->ifindex = ifindex; return 0; } @@ -671,7 +670,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { if (client->ia_na.id) return 0; - r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id); + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->ia_na.id); if (r < 0) return r; @@ -1027,7 +1026,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); + assert_return(client->ifindex > 0, -EINVAL); assert_return(client->state != state, -EINVAL); client->timeout_resend_expire = @@ -1160,12 +1159,12 @@ int sd_dhcp6_client_is_running(sd_dhcp6_client *client) { } int sd_dhcp6_client_start(sd_dhcp6_client *client) { - int r = 0; enum DHCP6State state = DHCP6_STATE_SOLICITATION; + int r = 0; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); + assert_return(client->ifindex > 0, -EINVAL); assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL); if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) @@ -1183,7 +1182,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (r < 0) return r; - r = dhcp6_network_bind_udp_socket(client->index, &client->local_address); + r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); if (r < 0) { _cleanup_free_ char *p = NULL; @@ -1301,15 +1300,11 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { return -ENOMEM; client->n_ref = 1; - client->ia_na.type = SD_DHCP6_OPTION_IA_NA; - - client->index = -1; - + client->ifindex = -1; client->fd = -1; client->req_opts_len = ELEMENTSOF(default_req_opts); - client->req_opts = new0(be16_t, client->req_opts_len); if (!client->req_opts) return -ENOMEM; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 3c9fa85198..fcce97cfd9 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -81,7 +81,7 @@ struct sd_ipv4acd { RefCount n_ref; IPv4ACDState state; - int index; + int ifindex; int fd; int iteration; int conflict; @@ -131,7 +131,7 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) { ll->n_ref = REFCNT_INIT; ll->state = IPV4ACD_STATE_INIT; - ll->index = -1; + ll->ifindex = -1; ll->fd = -1; *ret = ll; @@ -264,7 +264,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: /* Send a probe */ - r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); + r = arp_send_probe(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m"); goto out; @@ -301,7 +301,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) } case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ - r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; @@ -390,7 +390,7 @@ static int ipv4acd_on_packet( /* Defend address */ if (ts > ll->defend_window) { ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC; - r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; @@ -420,12 +420,12 @@ out: return 1; } -int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) { +int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int ifindex) { assert_return(ll, -EINVAL); - assert_return(interface_index > 0, -EINVAL); + assert_return(ifindex > 0, -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); - ll->index = interface_index; + ll->ifindex = ifindex; return 0; } @@ -497,14 +497,14 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { assert_return(ll, -EINVAL); assert_return(ll->event, -EINVAL); - assert_return(ll->index > 0, -EINVAL); + assert_return(ll->ifindex > 0, -EINVAL); assert_return(ll->address != 0, -EINVAL); assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); ll->defend_window = 0; - r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr); + r = arp_network_bind_raw_socket(ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) goto out; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 2a06418c53..184603de52 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -125,10 +125,11 @@ int sd_ipv4ll_stop(sd_ipv4ll *ll) { return 0; } -int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) { +int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { assert_return(ll, -EINVAL); + assert_return(ifindex > 0, -EINVAL); - return sd_ipv4acd_set_index(ll->acd, interface_index); + return sd_ipv4acd_set_ifindex(ll->acd, ifindex); } #define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index bb62cc21a3..ab2527b915 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -75,7 +75,7 @@ struct sd_ndisc { enum NDiscState state; sd_event *event; int event_priority; - int index; + int ifindex; struct ether_addr mac_addr; uint32_t mtu; LIST_HEAD(NDiscPrefix, prefixes); @@ -145,12 +145,11 @@ int sd_ndisc_set_callback(sd_ndisc *nd, return 0; } -int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) { - assert(nd); - assert(interface_index >= -1); - - nd->index = interface_index; +int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { + assert_return(nd, -EINVAL); + assert_return(ifindex > 0, -EINVAL); + nd->ifindex = ifindex; return 0; } @@ -254,7 +253,7 @@ int sd_ndisc_new(sd_ndisc **ret) { nd->n_ref = 1; - nd->index = -1; + nd->ifindex = -1; nd->fd = -1; LIST_HEAD_INIT(nd->prefixes); @@ -675,10 +674,10 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { if (nd->state != NDISC_STATE_IDLE) return -EBUSY; - if (nd->index < 1) + if (nd->ifindex < 1) return -EINVAL; - r = icmp6_bind_router_solicitation(nd->index); + r = icmp6_bind_router_solicitation(nd->ifindex); if (r < 0) return r; diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c index 75564615b9..27fcc332a3 100644 --- a/src/libsystemd-network/test-acd.c +++ b/src/libsystemd-network/test-acd.c @@ -56,7 +56,7 @@ static int client_run(int ifindex, const struct in_addr *pa, const struct ether_ assert_se(sd_ipv4acd_new(&acd) >= 0); assert_se(sd_ipv4acd_attach_event(acd, e, 0) >= 0); - assert_se(sd_ipv4acd_set_index(acd, ifindex) >= 0); + assert_se(sd_ipv4acd_set_ifindex(acd, ifindex) >= 0); assert_se(sd_ipv4acd_set_mac(acd, ha) >= 0); assert_se(sd_ipv4acd_set_address(acd, pa) >= 0); assert_se(sd_ipv4acd_set_callback(acd, acd_handler, NULL) >= 0); diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index c3c08fef5e..2a101cb1fe 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -66,13 +66,13 @@ static void test_request_basic(sd_event *e) { assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL); assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL); - assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL); + assert_se(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL); - assert_se(sd_dhcp_client_set_index(client, 15) == 0); - assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL); - assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL); - assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL); - assert_se(sd_dhcp_client_set_index(client, 1) == 0); + assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0); + assert_se(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL); + assert_se(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL); + assert_se(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL); + assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0); assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST); @@ -243,7 +243,7 @@ static void test_discover_message(sd_event *e) { r = sd_dhcp_client_attach_event(client, e, 0); assert_se(r >= 0); - assert_se(sd_dhcp_client_set_index(client, 42) >= 0); + assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0); assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0); @@ -458,7 +458,7 @@ static void test_addr_acq(sd_event *e) { r = sd_dhcp_client_attach_event(client, e, 0); assert_se(r >= 0); - assert_se(sd_dhcp_client_set_index(client, 42) >= 0); + assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0); assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index e74c8c72db..bd289fa802 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -59,10 +59,10 @@ static int test_client_basic(sd_event *e) { assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); - assert_se(sd_dhcp6_client_set_index(client, 15) == 0); - assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL); - assert_se(sd_dhcp6_client_set_index(client, -1) == 0); - assert_se(sd_dhcp6_client_set_index(client, 42) >= 0); + assert_se(sd_dhcp6_client_set_ifindex(client, 15) == 0); + assert_se(sd_dhcp6_client_set_ifindex(client, -42) == -EINVAL); + assert_se(sd_dhcp6_client_set_ifindex(client, -1) == 0); + assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0); assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, sizeof (mac_addr), @@ -712,7 +712,7 @@ static int test_client_solicit(sd_event *e) { assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); - assert_se(sd_dhcp6_client_set_index(client, test_index) == 0); + assert_se(sd_dhcp6_client_set_ifindex(client, test_index) == 0); assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, sizeof (mac_addr), ARPHRD_ETHER) >= 0); diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index 85dd61470d..2b1387fa91 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -64,7 +64,7 @@ static int client_run(int ifindex, const char *seed_str, const struct ether_addr assert_se(sd_ipv4ll_new(&ll) >= 0); assert_se(sd_ipv4ll_attach_event(ll, e, 0) >= 0); - assert_se(sd_ipv4ll_set_index(ll, ifindex) >= 0); + assert_se(sd_ipv4ll_set_ifindex(ll, ifindex) >= 0); assert_se(sd_ipv4ll_set_mac(ll, ha) >= 0); assert_se(sd_ipv4ll_set_callback(ll, ll_handler, NULL) >= 0); diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index 8cdbfb8ed8..aad3c476a0 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -136,11 +136,11 @@ static void test_public_api_setters(sd_event *e) { assert_se(sd_ipv4ll_set_mac(ll, NULL) == -EINVAL); assert_se(sd_ipv4ll_set_mac(ll, &mac_addr) == 0); - assert_se(sd_ipv4ll_set_index(NULL, -1) == -EINVAL); - assert_se(sd_ipv4ll_set_index(ll, -1) == -EINVAL); - assert_se(sd_ipv4ll_set_index(ll, -99) == -EINVAL); - assert_se(sd_ipv4ll_set_index(ll, 1) == 0); - assert_se(sd_ipv4ll_set_index(ll, 99) == 0); + assert_se(sd_ipv4ll_set_ifindex(NULL, -1) == -EINVAL); + assert_se(sd_ipv4ll_set_ifindex(ll, -1) == -EINVAL); + assert_se(sd_ipv4ll_set_ifindex(ll, -99) == -EINVAL); + assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0); + assert_se(sd_ipv4ll_set_ifindex(ll, 99) == 0); assert_se(sd_ipv4ll_ref(ll) == ll); assert_se(sd_ipv4ll_unref(ll) == NULL); @@ -172,7 +172,7 @@ static void test_basic_request(sd_event *e) { basic_request_handler_userdata) == 0); assert_se(sd_ipv4ll_start(ll) == -EINVAL); - assert_se(sd_ipv4ll_set_index(ll, 1) == 0); + assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0); assert_se(sd_ipv4ll_start(ll) == 0); sd_event_run(e, (uint64_t) -1); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index f7b2eb8050..4817c968ac 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -130,7 +130,7 @@ static void test_rs(void) { assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0); - assert_se(sd_ndisc_set_index(nd, 42) >= 0); + assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0); assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 2ddcee9db8..12fb8e3fce 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -554,7 +554,7 @@ int dhcp4_configure(Link *link) { if (r < 0) return r; - r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex); + r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex); if (r < 0) return r; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 37e13e639e..a44c9ea71d 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -237,7 +237,7 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - r = sd_dhcp6_client_set_index(client, link->ifindex); + r = sd_dhcp6_client_set_ifindex(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index ae323d595b..a41f231f8c 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -231,7 +231,7 @@ int ipv4ll_configure(Link *link) { if (r < 0) return r; - r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex); + r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex); if (r < 0) return r; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 1a380bd214..3baca2e63c 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -243,7 +243,7 @@ int ndisc_configure(Link *link) { if (r < 0) return r; - r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex); + r = sd_ndisc_set_ifindex(link->ndisc_router_discovery, link->ifindex); if (r < 0) return r; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 20b8c2873f..9a90c2ed42 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -99,7 +99,7 @@ int sd_dhcp_client_set_request_address( int sd_dhcp_client_set_request_broadcast( sd_dhcp_client *client, int broadcast); -int sd_dhcp_client_set_index( +int sd_dhcp_client_set_ifindex( sd_dhcp_client *client, int interface_index); int sd_dhcp_client_set_mac( diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 90f62eaca4..7819f0d2de 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -82,7 +82,7 @@ int sd_dhcp6_client_set_callback( sd_dhcp6_client_callback_t cb, void *userdata); -int sd_dhcp6_client_set_index( +int sd_dhcp6_client_set_ifindex( sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address( diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 9e3e14a30c..604160ae3f 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -44,7 +44,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority); int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); -int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); +int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *ll); int sd_ipv4acd_start(sd_ipv4acd *ll); diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 6fa38a2243..95ed972ffe 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -43,7 +43,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority); int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); -int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); int sd_ipv4ll_is_running(sd_ipv4ll *ll); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 29bcbe8e3e..2b774233b8 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -49,7 +49,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_prefix_autonomous_callback_t pacb, sd_ndisc_callback_t cb, void *userdata); -int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); -- cgit v1.2.3-54-g00ecf From 5c4c338adc88d6c3c09263a07aa35ff45de85321 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:15:04 +0200 Subject: sd-ndisc: rename sd_ndisc_init() to sd_ndisc_reset() After all, it's actually used for resetting the state, not only for the initial initialization. While we are at it, also simplify the error path for sd_ndisc_discovery_start(). --- src/libsystemd-network/sd-ndisc.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index ab2527b915..fe9ba43167 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -209,7 +209,7 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { return nd; } -static int ndisc_init(sd_ndisc *nd) { +static int ndisc_reset(sd_ndisc *nd) { assert(nd); nd->recv = sd_event_source_unref(nd->recv); @@ -231,7 +231,7 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { if (nd->n_ref > 0) return NULL; - ndisc_init(nd); + ndisc_reset(nd); sd_ndisc_detach_event(nd); LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) @@ -655,7 +655,7 @@ int sd_ndisc_stop(sd_ndisc *nd) { log_ndisc(client, "Stop NDisc"); - ndisc_init(nd); + ndisc_reset(nd); nd->state = NDISC_STATE_IDLE; @@ -683,34 +683,30 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { nd->fd = r; - r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, - ndisc_router_advertisment_recv, nd); + r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, ndisc_router_advertisment_recv, nd); if (r < 0) - goto error; + goto fail; r = sd_event_source_set_priority(nd->recv, nd->event_priority); if (r < 0) - goto error; + goto fail; - r = sd_event_source_set_description(nd->recv, "ndisc-receive-message"); - if (r < 0) - goto error; + (void) sd_event_source_set_description(nd->recv, "ndisc-receive-message"); - r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), - 0, 0, ndisc_router_solicitation_timeout, nd); + r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd); if (r < 0) - goto error; + goto fail; r = sd_event_source_set_priority(nd->timeout, nd->event_priority); if (r < 0) - goto error; + goto fail; - r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); -error: - if (r < 0) - ndisc_init(nd); - else - log_ndisc(client, "Start Router Solicitation"); + (void) sd_event_source_set_description(nd->timeout, "ndisc-timeout"); + + log_ndisc(client, "Started IPv6 Router Solicitation client"); + return 0; +fail: + ndisc_reset(nd); return r; } -- cgit v1.2.3-54-g00ecf From a114066685b6a996c3f0ae914ee32587e8f59f2f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:27:05 +0200 Subject: sd-network: fix up assertion chaos assert_return() should only be used to validate user-facing parameters and state, assert() should be used for checking our own internal state and parameters. --- src/libsystemd-network/sd-dhcp-client.c | 41 +++++++++++++++++------------ src/libsystemd-network/sd-dhcp6-client.c | 35 +++++++++++++++++-------- src/libsystemd-network/sd-ndisc.c | 44 +++++++++++++++----------------- 3 files changed, 68 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index fab9f3f088..09e174cc01 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -151,10 +151,10 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { size_t i; assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); + assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); switch(option) { + case SD_DHCP_OPTION_PAD: case SD_DHCP_OPTION_OVERLOAD: case SD_DHCP_OPTION_MESSAGE_TYPE: @@ -182,9 +182,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { int sd_dhcp_client_set_request_address( sd_dhcp_client *client, const struct in_addr *last_addr) { + assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); + assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); if (last_addr) client->last_addr = last_addr->s_addr; @@ -230,8 +230,7 @@ int sd_dhcp_client_set_mac( return 0; if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing MAC address on running DHCP " - "client, restarting"); + log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting"); need_restart = true; client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); } @@ -283,14 +282,17 @@ int sd_dhcp_client_set_client_id( assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); switch (type) { + case ARPHRD_ETHER: if (data_len != ETH_ALEN) return -EINVAL; break; + case ARPHRD_INFINIBAND: if (data_len != INFINIBAND_ALEN) return -EINVAL; break; + default: break; } @@ -434,14 +436,14 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); - assert_return(ret, -EINVAL); if (client->state != DHCP_STATE_BOUND && client->state != DHCP_STATE_RENEWING && client->state != DHCP_STATE_REBINDING) return -EADDRNOTAVAIL; - *ret = client->lease; + if (ret) + *ret = client->lease; return 0; } @@ -454,8 +456,7 @@ static void client_notify(sd_dhcp_client *client, int event) { static int client_initialize(sd_dhcp_client *client) { assert_return(client, -EINVAL); - client->receive_message = - sd_event_source_unref(client->receive_message); + client->receive_message = sd_event_source_unref(client->receive_message); client->fd = asynchronous_close(client->fd); @@ -750,8 +751,9 @@ static int client_send_request(sd_dhcp_client *client) { size_t optoffset, optlen; int r; - r = client_message_init(client, &request, DHCP_REQUEST, - &optlen, &optoffset); + assert(client); + + r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset); if (r < 0) return r; @@ -848,18 +850,23 @@ static int client_send_request(sd_dhcp_client *client) { return r; switch (client->state) { + case DHCP_STATE_REQUESTING: log_dhcp_client(client, "REQUEST (requesting)"); break; + case DHCP_STATE_INIT_REBOOT: log_dhcp_client(client, "REQUEST (init-reboot)"); break; + case DHCP_STATE_RENEWING: log_dhcp_client(client, "REQUEST (renewing)"); break; + case DHCP_STATE_REBINDING: log_dhcp_client(client, "REQUEST (rebinding)"); break; + default: log_dhcp_client(client, "REQUEST (invalid)"); break; @@ -891,6 +898,7 @@ static int client_timeout_resend( goto error; switch (client->state) { + case DHCP_STATE_RENEWING: time_left = (client->lease->t2 - client->lease->t1) / 2; @@ -1103,8 +1111,7 @@ static int client_start_delayed(sd_dhcp_client *client) { assert_return(client->ifindex > 0, -EINVAL); assert_return(client->fd < 0, -EBUSY); assert_return(client->xid == 0, -EINVAL); - assert_return(client->state == DHCP_STATE_INIT || - client->state == DHCP_STATE_INIT_REBOOT, -EBUSY); + assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY); client->xid = random_u32(); @@ -1150,6 +1157,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) DHCP_CLIENT_DONT_DESTROY(client); int r; + assert(client); + client->receive_message = sd_event_source_unref(client->receive_message); client->fd = asynchronous_close(client->fd); @@ -1821,8 +1830,7 @@ int sd_dhcp_client_detach_event(sd_dhcp_client *client) { } sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { - if (!client) - return NULL; + assert_return(client, NULL); return client->event; } @@ -1884,7 +1892,6 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->mtu = DHCP_DEFAULT_MIN_SIZE; client->req_opts_size = ELEMENTSOF(default_req_opts); - client->req_opts = memdup(default_req_opts, client->req_opts_size); if (!client->req_opts) return -ENOMEM; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 15667c26d7..203deaa50d 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -255,6 +255,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); switch(option) { + case SD_DHCP6_OPTION_DNS_SERVERS: case SD_DHCP6_OPTION_DOMAIN_LIST: case SD_DHCP6_OPTION_SNTP_SERVERS: @@ -296,15 +297,18 @@ static void client_notify(sd_dhcp6_client *client, int event) { } static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) { + assert(client); + if (client->lease) { dhcp6_lease_clear_timers(&client->lease->ia); sd_dhcp6_lease_unref(client->lease); } + client->lease = lease; } static int client_reset(sd_dhcp6_client *client) { - assert_return(client, -EINVAL); + assert(client); client_set_lease(client, NULL); @@ -352,6 +356,8 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { usec_t elapsed_usec; be16_t elapsed_time; + assert(client); + len = sizeof(DHCP6Message) + optlen; message = malloc0(len); @@ -453,9 +459,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; - assert_return(s, -EINVAL); - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); + assert(s); + assert(client); + assert(client->lease); client->lease->ia.timeout_t2 = sd_event_source_unref(client->lease->ia.timeout_t2); @@ -470,9 +476,9 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; - assert_return(s, -EINVAL); - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); + assert(s); + assert(client); + assert(client->lease); client->lease->ia.timeout_t1 = sd_event_source_unref(client->lease->ia.timeout_t1); @@ -689,6 +695,11 @@ static int client_parse_message( bool clientid = false; be32_t iaid_lease; + assert(client); + assert(message); + assert(len >= sizeof(DHCP6Message)); + assert(lease); + option = (uint8_t *)message + sizeof(DHCP6Message); len -= sizeof(DHCP6Message); @@ -833,9 +844,12 @@ static int client_parse_message( } static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { - int r; _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; bool rapid_commit; + int r; + + assert(client); + assert(reply); if (reply->type != DHCP6_REPLY) return 0; @@ -864,9 +878,9 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si } static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { - int r; _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; + int r; if (advertise->type != DHCP6_ADVERTISE) return 0; @@ -1251,8 +1265,7 @@ int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) { } sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { - if (!client) - return NULL; + assert_return(client, NULL); return client->event; } diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index fe9ba43167..06afafd2c7 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -128,13 +128,15 @@ static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { return 0; } -int sd_ndisc_set_callback(sd_ndisc *nd, - sd_ndisc_router_callback_t router_callback, - sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback, - sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback, - sd_ndisc_callback_t callback, - void *userdata) { - assert(nd); +int sd_ndisc_set_callback( + sd_ndisc *nd, + sd_ndisc_router_callback_t router_callback, + sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback, + sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback, + sd_ndisc_callback_t callback, + void *userdata) { + + assert_return(nd, -EINVAL); nd->router_callback = router_callback; nd->prefix_onlink_callback = prefix_onlink_callback; @@ -154,7 +156,7 @@ int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { } int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { - assert(nd); + assert_return(nd, -EINVAL); if (mac_addr) memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr)); @@ -193,7 +195,7 @@ int sd_ndisc_detach_event(sd_ndisc *nd) { } sd_event *sd_ndisc_get_event(sd_ndisc *nd) { - assert(nd); + assert_return(nd, NULL); return nd->event; } @@ -245,14 +247,13 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { int sd_ndisc_new(sd_ndisc **ret) { _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL; - assert(ret); + assert_return(ret, -EINVAL); nd = new0(sd_ndisc, 1); if (!nd) return -ENOMEM; nd->n_ref = 1; - nd->ifindex = -1; nd->fd = -1; @@ -272,7 +273,6 @@ int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { return -ENOMSG; *mtu = nd->mtu; - return 0; } @@ -281,8 +281,8 @@ static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, uint8_t addr_prefixlen) { uint8_t bytes, mask, len; - assert_return(prefix, -EINVAL); - assert_return(addr, -EINVAL); + assert(prefix); + assert(addr); len = MIN(prefixlen, addr_prefixlen); @@ -414,8 +414,8 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len void *opt; struct nd_opt_hdr *opt_hdr; - assert_return(nd, -EINVAL); - assert_return(ra, -EINVAL); + assert(nd); + assert(ra); len -= sizeof(*ra); if (len < NDISC_OPT_LEN_UNITS) { @@ -668,14 +668,10 @@ int sd_ndisc_stop(sd_ndisc *nd) { int sd_ndisc_router_discovery_start(sd_ndisc *nd) { int r; - assert(nd); - assert(nd->event); - - if (nd->state != NDISC_STATE_IDLE) - return -EBUSY; - - if (nd->ifindex < 1) - return -EINVAL; + assert_return(nd, -EINVAL); + assert_return(nd->event, -EINVAL); + assert_return(nd->ifindex > 0, -EINVAL); + assert_return(nd->state == NDISC_STATE_IDLE, -EBUSY); r = icmp6_bind_router_solicitation(nd->ifindex); if (r < 0) -- cgit v1.2.3-54-g00ecf From c1c9b211e3337e3491acc5f2550e8d48542986aa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:27:59 +0200 Subject: sd-ndisc: make the _stop() call idempotent It's a good idea to make stopcalls idempotent, so that they become nops if the object is already stopped. --- src/libsystemd-network/sd-ndisc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 06afafd2c7..c03e104e3b 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -651,12 +651,13 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, int sd_ndisc_stop(sd_ndisc *nd) { assert_return(nd, -EINVAL); - assert_return(nd->event, -EINVAL); - log_ndisc(client, "Stop NDisc"); + if (nd->state == NDISC_STATE_IDLE) + return 0; + + log_ndisc(client, "Stopping IPv6 Router Solicitation client"); ndisc_reset(nd); - nd->state = NDISC_STATE_IDLE; if (nd->callback) -- cgit v1.2.3-54-g00ecf From 671eaa74050fc2683a068a7e90bb5e66ef038395 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:46:50 +0200 Subject: dhcp: fix operator precedence issue with macro --- src/libsystemd-network/dhcp-protocol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index 3e32484c1d..5cf7abbff9 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -59,7 +59,7 @@ typedef struct DHCPPacket DHCPPacket; #define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) #define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) #define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ -#define DHCP_MIN_OPTIONS_SIZE DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE +#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE) #define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) enum { -- cgit v1.2.3-54-g00ecf From 45aa74c72e4a315403611ebff5415dc1e8a196ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 16:48:56 +0200 Subject: sd-network: don't needlessly abbreviate "callback" as "cb" in struct members It's OK to abbreviate this in the local scope, but otherwise, let's not be needlessly terse. --- src/libsystemd-network/sd-dhcp-client.c | 11 +++++++---- src/libsystemd-network/sd-dhcp6-client.c | 11 +++++++---- src/libsystemd-network/sd-ipv4acd.c | 8 ++++---- src/libsystemd-network/sd-ipv4ll.c | 8 ++++---- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 09e174cc01..179e5950bd 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -101,7 +101,7 @@ struct sd_dhcp_client { sd_event_source *timeout_t1; sd_event_source *timeout_t2; sd_event_source *timeout_expire; - sd_dhcp_client_callback_t cb; + sd_dhcp_client_callback_t callback; void *userdata; sd_dhcp_lease *lease; usec_t start_delay; @@ -131,9 +131,10 @@ int sd_dhcp_client_set_callback( sd_dhcp_client *client, sd_dhcp_client_callback_t cb, void *userdata) { + assert_return(client, -EINVAL); - client->cb = cb; + client->callback = cb; client->userdata = userdata; return 0; @@ -449,8 +450,10 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { } static void client_notify(sd_dhcp_client *client, int event) { - if (client->cb) - client->cb(client, event, client->userdata); + assert(client); + + if (client->callback) + client->callback(client, event, client->userdata); } static int client_initialize(sd_dhcp_client *client) { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 203deaa50d..463fde401c 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -64,7 +64,7 @@ struct sd_dhcp6_client { uint8_t retransmit_count; sd_event_source *timeout_resend; sd_event_source *timeout_resend_expire; - sd_dhcp6_client_callback_t cb; + sd_dhcp6_client_callback_t callback; void *userdata; struct duid duid; size_t duid_len; @@ -115,9 +115,10 @@ int sd_dhcp6_client_set_callback( sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) { + assert_return(client, -EINVAL); - client->cb = cb; + client->callback = cb; client->userdata = userdata; return 0; @@ -292,8 +293,10 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { } static void client_notify(sd_dhcp6_client *client, int event) { - if (client->cb) - client->cb(client, event, client->userdata); + assert(client); + + if (client->callback) + client->callback(client, event, client->userdata); } static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) { diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index fcce97cfd9..7414f33adb 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -93,7 +93,7 @@ struct sd_ipv4acd { struct ether_addr mac_addr; sd_event *event; int event_priority; - sd_ipv4acd_callback_t cb; + sd_ipv4acd_callback_t callback; void* userdata; }; @@ -156,10 +156,10 @@ static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counte static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { assert(ll); - if (!ll->cb) + if (!ll->callback) return; - ll->cb(ll, event, ll->userdata); + ll->callback(ll, event, ll->userdata); } static void ipv4acd_stop(sd_ipv4acd *ll) { @@ -470,7 +470,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) { int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); - ll->cb = cb; + ll->callback = cb; ll->userdata = userdata; return 0; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 184603de52..f9779a8601 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -52,7 +52,7 @@ struct sd_ipv4ll { /* External */ be32_t claimed_address; - sd_ipv4ll_callback_t cb; + sd_ipv4ll_callback_t callback; void* userdata; }; @@ -176,7 +176,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); - ll->cb = cb; + ll->callback = cb; ll->userdata = userdata; return 0; @@ -312,8 +312,8 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) { static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { assert(ll); - if (ll->cb) - ll->cb(ll, event, ll->userdata); + if (ll->callback) + ll->callback(ll, event, ll->userdata); } void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { -- cgit v1.2.3-54-g00ecf From c116f52635c96548986b8e6f877ceaafec2a80bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:17:37 +0200 Subject: sd-ipv4{acl,ll}: don't make use of RefCnt objects These objects are only useful when multiple threads are involved, as they operate with atomic operations. Given that our libraries are explicitly not thread-safe don't make use of RefCnt here, and make things a bit simpler. --- src/libsystemd-network/sd-ipv4acd.c | 20 ++++++++++++++------ src/libsystemd-network/sd-ipv4ll.c | 1 - 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 7414f33adb..5f6e0f6c7f 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -33,7 +33,6 @@ #include "in-addr-util.h" #include "list.h" #include "random-util.h" -#include "refcnt.h" #include "siphash24.h" #include "util.h" @@ -78,7 +77,7 @@ typedef enum IPv4ACDState { } IPv4ACDState; struct sd_ipv4acd { - RefCount n_ref; + unsigned n_ref; IPv4ACDState state; int ifindex; @@ -98,14 +97,23 @@ struct sd_ipv4acd { }; sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) { - if (ll) - assert_se(REFCNT_INC(ll->n_ref) >= 2); + if (!ll) + return NULL; + + assert_se(ll->n_ref >= 1); + ll->n_ref++; return ll; } sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { - if (!ll || REFCNT_DEC(ll->n_ref) > 0) + if (!ll) + return NULL; + + assert_se(ll->n_ref >= 1); + ll->n_ref--; + + if (ll->n_ref > 0) return NULL; ll->receive_message = sd_event_source_unref(ll->receive_message); @@ -129,7 +137,7 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) { if (!ll) return -ENOMEM; - ll->n_ref = REFCNT_INIT; + ll->n_ref = 1; ll->state = IPV4ACD_STATE_INIT; ll->ifindex = -1; ll->fd = -1; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index f9779a8601..ea6d9d22f1 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -31,7 +31,6 @@ #include "in-addr-util.h" #include "list.h" #include "random-util.h" -#include "refcnt.h" #include "siphash24.h" #include "sparse-endian.h" #include "util.h" -- cgit v1.2.3-54-g00ecf From a48fc60a331803fcd4add17cdb5b3cae99bc2e80 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:18:58 +0200 Subject: ipv4acd: library code should never log Or actually, not at any level higher than debug. --- src/libsystemd-network/sd-ipv4acd.c | 38 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 5f6e0f6c7f..2fc8651399 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -51,19 +51,8 @@ #define IPV4ACD_NETWORK 0xA9FE0000L #define IPV4ACD_NETMASK 0xFFFF0000L -#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__) - -#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__) -#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__) -#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__) -#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__) -#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__) - -#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__) -#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__) -#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__) -#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__) -#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__) +#define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__) typedef enum IPv4ACDState { IPV4ACD_STATE_INIT, @@ -178,7 +167,7 @@ static void ipv4acd_stop(sd_ipv4acd *ll) { ll->timer = sd_event_source_unref(ll->timer); - log_ipv4acd_debug(ll, "STOPPED"); + log_ipv4acd(ll, "STOPPED"); ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true); } @@ -256,7 +245,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); if (ll->conflict >= MAX_CONFLICTS) { - log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); + log_ipv4acd(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); + r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); if (r < 0) goto out; @@ -274,7 +264,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) /* Send a probe */ r = arp_send_probe(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { - log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m"); + log_ipv4acd_errno(ll, r, "Failed to send ARP probe: %m"); goto out; } else { _cleanup_free_ char *address = NULL; @@ -282,7 +272,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = in_addr_to_string(AF_INET, &addr, &address); if (r >= 0) - log_ipv4acd_debug(ll, "Probing %s", address); + log_ipv4acd(ll, "Probing %s", address); } if (ll->iteration < PROBE_NUM - 2) { @@ -311,10 +301,10 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) /* Send announcement packet */ r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { - log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); + log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; } else - log_ipv4acd_debug(ll, "ANNOUNCE"); + log_ipv4acd(ll, "ANNOUNCE"); ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false); @@ -350,7 +340,7 @@ static void ipv4acd_on_conflict(sd_ipv4acd *ll) { r = in_addr_to_string(AF_INET, &addr, &address); if (r >= 0) - log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict); + log_ipv4acd(ll, "Conflict on %s (%u)", address, ll->conflict); ipv4acd_stop(ll); @@ -377,11 +367,11 @@ static int ipv4acd_on_packet( if (errno == EAGAIN || errno == EINTR) return 0; - r = log_ipv4acd_debug_errno(ll, errno, "Failed to read ARP packet: %m"); + r = log_ipv4acd_errno(ll, errno, "Failed to read ARP packet: %m"); goto out; } if ((size_t) n != sizeof(struct ether_arp)) { - log_ipv4acd_debug(ll, "Ignoring too short ARP packet."); + log_ipv4acd(ll, "Ignoring too short ARP packet."); return 0; } @@ -400,10 +390,10 @@ static int ipv4acd_on_packet( ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC; r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { - log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); + log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); goto out; } else - log_ipv4acd_debug(ll, "DEFEND"); + log_ipv4acd(ll, "DEFEND"); } else ipv4acd_on_conflict(ll); -- cgit v1.2.3-54-g00ecf From 73e94c0dcb41c0924d506a329f874e69409437f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:19:35 +0200 Subject: ipv4l-{acd,ll}: make sure ipv4 addresses are unsigned And some other minor fixes. --- src/libsystemd-network/sd-ipv4acd.c | 4 ++-- src/libsystemd-network/sd-ipv4ll.c | 20 +++++++------------- src/systemd/sd-ipv4ll.h | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 2fc8651399..e78d8a04f2 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -48,8 +48,8 @@ #define RATE_LIMIT_INTERVAL 60 #define DEFEND_INTERVAL 10 -#define IPV4ACD_NETWORK 0xA9FE0000L -#define IPV4ACD_NETMASK 0xFFFF0000L +#define IPV4ACD_NETWORK 0xA9FE0000UL +#define IPV4ACD_NETMASK 0xFFFF0000UL #define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__) #define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index ea6d9d22f1..1f6da4bb16 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -35,8 +35,8 @@ #include "sparse-endian.h" #include "util.h" -#define IPV4LL_NETWORK 0xA9FE0000L -#define IPV4LL_NETMASK 0xFFFF0000L +#define IPV4LL_NETWORK 0xA9FE0000UL +#define IPV4LL_NETMASK 0xFFFF0000UL #define IPV4LL_DONT_DESTROY(ll) \ _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) @@ -161,15 +161,9 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { } int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { - int r; - assert_return(ll, -EINVAL); - r = sd_ipv4acd_attach_event(ll->acd, event, priority); - if (r < 0) - return r; - - return 0; + return sd_ipv4acd_attach_event(ll->acd, event, priority); } int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { @@ -275,7 +269,7 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { r = random_r(ll->random_data, &random); if (r < 0) return r; - addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); + addr = htobe32((random & 0x0000FFFF) | IPV4LL_NETWORK); } while (addr == ll->address || (ntohl(addr) & 0x0000FF00) == 0x0000 || (ntohl(addr) & 0x0000FF00) == 0xFF00); @@ -324,17 +318,17 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { assert(ll); switch (event) { + case SD_IPV4ACD_EVENT_STOP: ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); - ll->claimed_address = 0; - break; + case SD_IPV4ACD_EVENT_BIND: ll->claimed_address = ll->address; ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND); - break; + case SD_IPV4ACD_EVENT_CONFLICT: /* if an address was already bound we must call up to the user to handle this, otherwise we just try again */ diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 95ed972ffe..4682dd6605 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -51,7 +51,7 @@ int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); -int sd_ipv4ll_new (sd_ipv4ll **ret); +int sd_ipv4ll_new(sd_ipv4ll **ret); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref); -- cgit v1.2.3-54-g00ecf From 784cdc2d0bb1e4102345fc3883e1e4587f0ec967 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:23:40 +0200 Subject: ipv4acd: make the iteration and conflict fields unsigned They are counters after all, and can never go below zero, hence don't pretend with the chose type that they could. Also, prefix their name with "n_", to indicate that they are counters. --- src/libsystemd-network/sd-ipv4acd.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index e78d8a04f2..730b8ca785 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -71,14 +71,19 @@ struct sd_ipv4acd { IPv4ACDState state; int ifindex; int fd; - int iteration; - int conflict; + + unsigned n_iteration; + unsigned n_conflict; + sd_event_source *receive_message; sd_event_source *timer; + usec_t defend_window; be32_t address; + /* External */ struct ether_addr mac_addr; + sd_event *event; int event_priority; sd_ipv4acd_callback_t callback; @@ -143,10 +148,10 @@ static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counte assert(st < _IPV4ACD_STATE_MAX); if (st == ll->state && !reset_counter) - ll->iteration++; + ll->n_iteration++; else { ll->state = st; - ll->iteration = 0; + ll->n_iteration = 0; } } @@ -244,14 +249,14 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); - if (ll->conflict >= MAX_CONFLICTS) { + if (ll->n_conflict >= MAX_CONFLICTS) { log_ipv4acd(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); if (r < 0) goto out; - ll->conflict = 0; + ll->n_conflict = 0; } else { r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT); if (r < 0) @@ -275,7 +280,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) log_ipv4acd(ll, "Probing %s", address); } - if (ll->iteration < PROBE_NUM - 2) { + if (ll->n_iteration < PROBE_NUM - 2) { ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false); r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); @@ -292,7 +297,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) break; case IPV4ACD_STATE_ANNOUNCING: - if (ll->iteration >= ANNOUNCE_NUM - 1) { + if (ll->n_iteration >= ANNOUNCE_NUM - 1) { ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false); break; @@ -312,8 +317,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) if (r < 0) goto out; - if (ll->iteration == 0) { - ll->conflict = 0; + if (ll->n_iteration == 0) { + ll->n_conflict = 0; ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND); } @@ -336,11 +341,11 @@ static void ipv4acd_on_conflict(sd_ipv4acd *ll) { assert(ll); - ll->conflict++; + ll->n_conflict++; r = in_addr_to_string(AF_INET, &addr, &address); if (r >= 0) - log_ipv4acd(ll, "Conflict on %s (%u)", address, ll->conflict); + log_ipv4acd(ll, "Conflict on %s (%u)", address, ll->n_conflict); ipv4acd_stop(ll); -- cgit v1.2.3-54-g00ecf From 4dbf7b3a9330482b21685e57d3098a67693e2956 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:32:18 +0200 Subject: ipv4acd: add "_event_source" suffix to event source objects Otherwise the field "receive_message" is a bit too confusing, as it suggests it actually stores a message object of some kind. --- src/libsystemd-network/sd-ipv4acd.c | 45 +++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 730b8ca785..7393be45f5 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -75,8 +75,8 @@ struct sd_ipv4acd { unsigned n_iteration; unsigned n_conflict; - sd_event_source *receive_message; - sd_event_source *timer; + sd_event_source *receive_message_event_source; + sd_event_source *timer_event_source; usec_t defend_window; be32_t address; @@ -110,10 +110,10 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { if (ll->n_ref > 0) return NULL; - ll->receive_message = sd_event_source_unref(ll->receive_message); - ll->fd = safe_close(ll->fd); + ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); + ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); - ll->timer = sd_event_source_unref(ll->timer); + ll->fd = safe_close(ll->fd); sd_ipv4acd_detach_event(ll); @@ -143,7 +143,6 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) { } static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { - assert(ll); assert(st < _IPV4ACD_STATE_MAX); @@ -167,21 +166,20 @@ static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { static void ipv4acd_stop(sd_ipv4acd *ll) { assert(ll); - ll->receive_message = sd_event_source_unref(ll->receive_message); - ll->fd = safe_close(ll->fd); + ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); - ll->timer = sd_event_source_unref(ll->timer); + ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); + ll->fd = safe_close(ll->fd); log_ipv4acd(ll, "STOPPED"); - ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true); + ipv4acd_set_state(ll, IPV4ACD_STATE_INIT, true); } int sd_ipv4acd_stop(sd_ipv4acd *ll) { assert_return(ll, -EINVAL); ipv4acd_stop(ll); - ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP); return 0; @@ -215,12 +213,10 @@ static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) { if (r < 0) return r; - r = sd_event_source_set_description(timer, "ipv4acd-timer"); - if (r < 0) - return r; + (void) sd_event_source_set_description(timer, "ipv4acd-timer"); - ll->timer = sd_event_source_unref(ll->timer); - ll->timer = timer; + sd_event_source_unref(ll->timer_event_source); + ll->timer_event_source = timer; timer = NULL; return 0; @@ -245,8 +241,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) assert(ll); switch (ll->state) { - case IPV4ACD_STATE_INIT: + case IPV4ACD_STATE_INIT: ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); if (ll->n_conflict >= MAX_CONFLICTS) { @@ -264,6 +260,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) } break; + case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: /* Send a probe */ @@ -299,9 +296,11 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) case IPV4ACD_STATE_ANNOUNCING: if (ll->n_iteration >= ANNOUNCE_NUM - 1) { ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false); - break; } + + /* fall through */ + case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); @@ -323,6 +322,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) } break; + default: assert_not_reached("Invalid state."); } @@ -514,18 +514,15 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { ll->fd = safe_close(ll->fd); ll->fd = r; - r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd, - EPOLLIN, ipv4acd_on_packet, ll); + r = sd_event_add_io(ll->event, &ll->receive_message_event_source, ll->fd, EPOLLIN, ipv4acd_on_packet, ll); if (r < 0) goto out; - r = sd_event_source_set_priority(ll->receive_message, ll->event_priority); + r = sd_event_source_set_priority(ll->receive_message_event_source, ll->event_priority); if (r < 0) goto out; - r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message"); - if (r < 0) - goto out; + (void) sd_event_source_set_description(ll->receive_message_event_source, "ipv4acd-receive-message"); r = ipv4acd_set_next_wakeup(ll, 0, 0); if (r < 0) -- cgit v1.2.3-54-g00ecf From d246e77a4343ff8a0266fc7dd5a7de5c524f9e44 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 17:52:08 +0200 Subject: ipv4acd: rename ipv4acd_stop() → ipv4acd_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is much less confusing, since there's also sd_ipv4acd_stop(), which was idfferent from ipv4acd_stop(). After renaming it, let's also use the funciton when destroying ipv4acd objects, as the code is pretty much the same for that. --- src/libsystemd-network/sd-ipv4acd.c | 94 +++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 7393be45f5..163d0f9199 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -34,6 +34,7 @@ #include "list.h" #include "random-util.h" #include "siphash24.h" +#include "string-util.h" #include "util.h" /* Constants from the RFC */ @@ -90,6 +91,29 @@ struct sd_ipv4acd { void* userdata; }; +static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { + assert(ll); + assert(st < _IPV4ACD_STATE_MAX); + + if (st == ll->state && !reset_counter) + ll->n_iteration++; + else { + ll->state = st; + ll->n_iteration = 0; + } +} + +static void ipv4acd_reset(sd_ipv4acd *ll) { + assert(ll); + + ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); + ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); + + ll->fd = safe_close(ll->fd); + + ipv4acd_set_state(ll, IPV4ACD_STATE_INIT, true); +} + sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) { if (!ll) return NULL; @@ -110,11 +134,7 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { if (ll->n_ref > 0) return NULL; - ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); - ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); - - ll->fd = safe_close(ll->fd); - + ipv4acd_reset(ll); sd_ipv4acd_detach_event(ll); free(ll); @@ -142,18 +162,6 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) { return 0; } -static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { - assert(ll); - assert(st < _IPV4ACD_STATE_MAX); - - if (st == ll->state && !reset_counter) - ll->n_iteration++; - else { - ll->state = st; - ll->n_iteration = 0; - } -} - static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { assert(ll); @@ -163,23 +171,13 @@ static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { ll->callback(ll, event, ll->userdata); } -static void ipv4acd_stop(sd_ipv4acd *ll) { - assert(ll); - - ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); +int sd_ipv4acd_stop(sd_ipv4acd *ll) { + assert_return(ll, -EINVAL); - ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); - ll->fd = safe_close(ll->fd); + ipv4acd_reset(ll); log_ipv4acd(ll, "STOPPED"); - ipv4acd_set_state(ll, IPV4ACD_STATE_INIT, true); -} - -int sd_ipv4acd_stop(sd_ipv4acd *ll) { - assert_return(ll, -EINVAL); - - ipv4acd_stop(ll); ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP); return 0; @@ -272,9 +270,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = ll->address }; - r = in_addr_to_string(AF_INET, &addr, &address); - if (r >= 0) - log_ipv4acd(ll, "Probing %s", address); + (void) in_addr_to_string(AF_INET, &addr, &address); + log_ipv4acd(ll, "Probing %s", strna(address)); } if (ll->n_iteration < PROBE_NUM - 2) { @@ -337,18 +334,15 @@ out: static void ipv4acd_on_conflict(sd_ipv4acd *ll) { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = ll->address }; - int r; assert(ll); ll->n_conflict++; - r = in_addr_to_string(AF_INET, &addr, &address); - if (r >= 0) - log_ipv4acd(ll, "Conflict on %s (%u)", address, ll->n_conflict); - - ipv4acd_stop(ll); + (void) in_addr_to_string(AF_INET, &addr, &address); + log_ipv4acd(ll, "Conflict on %s (%u)", strna(address), ll->n_conflict); + ipv4acd_reset(ll); ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT); } @@ -505,33 +499,31 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); - ll->defend_window = 0; - r = arp_network_bind_raw_socket(ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) - goto out; + return r; - ll->fd = safe_close(ll->fd); + safe_close(ll->fd); ll->fd = r; + ll->defend_window = 0; r = sd_event_add_io(ll->event, &ll->receive_message_event_source, ll->fd, EPOLLIN, ipv4acd_on_packet, ll); if (r < 0) - goto out; + goto fail; r = sd_event_source_set_priority(ll->receive_message_event_source, ll->event_priority); if (r < 0) - goto out; + goto fail; (void) sd_event_source_set_description(ll->receive_message_event_source, "ipv4acd-receive-message"); r = ipv4acd_set_next_wakeup(ll, 0, 0); if (r < 0) - goto out; -out: - if (r < 0) { - ipv4acd_stop(ll); - return r; - } + goto fail; return 0; + +fail: + ipv4acd_reset(ll); + return r; } -- cgit v1.2.3-54-g00ecf From c9e458a419ae8961a27cea19d0a15b7058a132f9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:06:33 +0200 Subject: ipv4acd: introduce new "started" state This state is active immediately after the state engine was started, but before the first timer hits. This way multiple _start() invocations on the same object are always detected correctly. --- src/libsystemd-network/sd-ipv4acd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 163d0f9199..59b87f42b7 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -57,6 +57,7 @@ typedef enum IPv4ACDState { IPV4ACD_STATE_INIT, + IPV4ACD_STATE_STARTED, IPV4ACD_STATE_WAITING_PROBE, IPV4ACD_STATE_PROBING, IPV4ACD_STATE_WAITING_ANNOUNCE, @@ -240,7 +241,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) switch (ll->state) { - case IPV4ACD_STATE_INIT: + case IPV4ACD_STATE_STARTED: ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); if (ll->n_conflict >= MAX_CONFLICTS) { @@ -521,6 +522,7 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { if (r < 0) goto fail; + ipv4acd_set_state(ll, IPV4ACD_STATE_STARTED, true); return 0; fail: -- cgit v1.2.3-54-g00ecf From d914f7a5639b72a400472dda622280f1015b6866 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:07:42 +0200 Subject: ipv4acd: no need to memcpy() where assignment suffices --- src/libsystemd-network/sd-ipv4acd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 59b87f42b7..12003fb796 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -433,7 +433,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) { assert_return(addr, -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); - memcpy(&ll->mac_addr, addr, ETH_ALEN); + ll->mac_addr = *addr; return 0; } -- cgit v1.2.3-54-g00ecf From d63458452dabeb59665c316693df07e90b9a9395 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:07:51 +0200 Subject: ipv4acd: in case the state engine is reused, reset n_conflict timer to 0 --- src/libsystemd-network/sd-ipv4acd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 12003fb796..99505181a4 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -507,6 +507,7 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) { safe_close(ll->fd); ll->fd = r; ll->defend_window = 0; + ll->n_conflict = 0; r = sd_event_add_io(ll->event, &ll->receive_message_event_source, ll->fd, EPOLLIN, ipv4acd_on_packet, ll); if (r < 0) -- cgit v1.2.3-54-g00ecf From e3f4eedba14f6485ef40bc87624d3b617f1b6ac7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:18:04 +0200 Subject: ipv4acd: normalize time types to usec_t We try to stick to usec_t for encoding time information, do that here too. In particular, get rid of "int" second specifications, since signed timespans are a weird thing. --- src/libsystemd-network/sd-ipv4acd.c | 51 +++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 99505181a4..f5b8fb2c0a 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -38,16 +38,16 @@ #include "util.h" /* Constants from the RFC */ -#define PROBE_WAIT 1 -#define PROBE_NUM 3 -#define PROBE_MIN 1 -#define PROBE_MAX 2 -#define ANNOUNCE_WAIT 2 -#define ANNOUNCE_NUM 2 -#define ANNOUNCE_INTERVAL 2 -#define MAX_CONFLICTS 10 -#define RATE_LIMIT_INTERVAL 60 -#define DEFEND_INTERVAL 10 +#define PROBE_WAIT_USEC (1U * USEC_PER_SEC) +#define PROBE_NUM 3U +#define PROBE_MIN_USEC (1U * USEC_PER_SEC) +#define PROBE_MAX_USEC (2U * USEC_PER_SEC) +#define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC) +#define ANNOUNCE_NUM 2U +#define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC) +#define MAX_CONFLICTS 10U +#define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC) +#define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC) #define IPV4ACD_NETWORK 0xA9FE0000UL #define IPV4ACD_NETMASK 0xFFFF0000UL @@ -186,25 +186,21 @@ int sd_ipv4acd_stop(sd_ipv4acd *ll) { static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); -static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) { +static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, usec_t usec, usec_t random_usec) { _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; - usec_t next_timeout; - usec_t time_now; + usec_t next_timeout, time_now; int r; - assert(sec >= 0); - assert(random_sec >= 0); assert(ll); - next_timeout = sec * USEC_PER_SEC; + next_timeout = usec; - if (random_sec) - next_timeout += random_u32() % (random_sec * USEC_PER_SEC); + if (random_usec > 0) + next_timeout += (usec_t) random_u64() % random_usec; assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0); - r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(), - time_now + next_timeout, 0, ipv4acd_on_timeout, ll); + r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, ll); if (r < 0) return r; @@ -245,15 +241,16 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); if (ll->n_conflict >= MAX_CONFLICTS) { - log_ipv4acd(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); + char ts[FORMAT_TIMESPAN_MAX]; + log_ipv4acd(ll, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); - r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); + r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto out; ll->n_conflict = 0; } else { - r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT); + r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT_USEC); if (r < 0) goto out; } @@ -278,13 +275,13 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) if (ll->n_iteration < PROBE_NUM - 2) { ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false); - r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); + r = ipv4acd_set_next_wakeup(ll, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); if (r < 0) goto out; } else { ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true); - r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0); + r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT_USEC, 0); if (r < 0) goto out; } @@ -310,7 +307,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false); - r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0); + r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL_USEC, 0); if (r < 0) goto out; @@ -387,7 +384,7 @@ static int ipv4acd_on_packet( /* Defend address */ if (ts > ll->defend_window) { - ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC; + ll->defend_window = ts + DEFEND_INTERVAL_USEC; r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); -- cgit v1.2.3-54-g00ecf From ff0c5ebd4a29be137080021f741b072d4c44b1a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:26:49 +0200 Subject: ipv4acd: make sure our event handler callbacks never check uninitialized "r" for errors --- src/libsystemd-network/sd-ipv4acd.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index f5b8fb2c0a..31a05ae6dc 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -246,13 +246,13 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) - goto out; + goto fail; ll->n_conflict = 0; } else { r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT_USEC); if (r < 0) - goto out; + goto fail; } break; @@ -263,7 +263,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = arp_send_probe(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_errno(ll, r, "Failed to send ARP probe: %m"); - goto out; + goto fail; } else { _cleanup_free_ char *address = NULL; union in_addr_union addr = { .in.s_addr = ll->address }; @@ -277,13 +277,13 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(ll, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); if (r < 0) - goto out; + goto fail; } else { ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true); r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT_USEC, 0); if (r < 0) - goto out; + goto fail; } break; @@ -301,7 +301,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); - goto out; + goto fail; } else log_ipv4acd(ll, "ANNOUNCE"); @@ -309,7 +309,7 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL_USEC, 0); if (r < 0) - goto out; + goto fail; if (ll->n_iteration == 0) { ll->n_conflict = 0; @@ -322,11 +322,11 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) assert_not_reached("Invalid state."); } -out: - if (r < 0) - sd_ipv4acd_stop(ll); + return 0; - return 1; +fail: + sd_ipv4acd_stop(ll); + return 0; } static void ipv4acd_on_conflict(sd_ipv4acd *ll) { @@ -364,8 +364,8 @@ static int ipv4acd_on_packet( if (errno == EAGAIN || errno == EINTR) return 0; - r = log_ipv4acd_errno(ll, errno, "Failed to read ARP packet: %m"); - goto out; + log_ipv4acd_errno(ll, errno, "Failed to read ARP packet: %m"); + goto fail; } if ((size_t) n != sizeof(struct ether_arp)) { log_ipv4acd(ll, "Ignoring too short ARP packet."); @@ -388,7 +388,7 @@ static int ipv4acd_on_packet( r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); if (r < 0) { log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); - goto out; + goto fail; } else log_ipv4acd(ll, "DEFEND"); @@ -408,11 +408,11 @@ static int ipv4acd_on_packet( assert_not_reached("Invalid state."); } -out: - if (r < 0) - sd_ipv4acd_stop(ll); + return 0; - return 1; +fail: + sd_ipv4acd_stop(ll); + return 0; } int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int ifindex) { -- cgit v1.2.3-54-g00ecf From 38958cd66e87037c75109408bf4093be21811eba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 18:33:17 +0200 Subject: ipv4ll: change "seed" parameter to be uint64_t Let's make clear this always has the same size, since otherwise it's not useful for reproducible runs, which this is really about however. --- src/libsystemd-network/sd-ipv4ll.c | 8 +++----- src/libsystemd-network/test-ipv4ll.c | 2 +- src/network/networkd-ipv4ll.c | 4 +--- src/systemd/sd-ipv4ll.h | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 1f6da4bb16..0e6a9df9e5 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -144,9 +144,7 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { /* If no random data is set, generate some from the MAC */ seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes); - assert_cc(sizeof(unsigned) <= 8); - - r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed)); + r = sd_ipv4ll_set_address_seed(ll, htole64(seed)); if (r < 0) return r; } @@ -187,7 +185,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { return 0; } -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) { +int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) { _cleanup_free_ struct random_data *random_data = NULL; _cleanup_free_ char *random_data_state = NULL; int r; @@ -202,7 +200,7 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) { if (!random_data_state) return -ENOMEM; - r = initstate_r(seed, random_data_state, 128, random_data); + r = initstate_r((unsigned) seed, random_data_state, 128, random_data); if (r < 0) return r; diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index aad3c476a0..fe70697075 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -101,7 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad static void test_public_api_setters(sd_event *e) { struct in_addr address = {}; - unsigned seed = 0; + uint64_t seed = 0; sd_ipv4ll *ll; struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}}; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index a41f231f8c..735c231a4c 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -215,9 +215,7 @@ int ipv4ll_configure(Link *link) { if (link->udev_device) { r = net_get_unique_predictable_data(link->udev_device, &seed); if (r >= 0) { - assert_cc(sizeof(unsigned) <= 8); - - r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed); + r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); if (r < 0) return r; } diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 4682dd6605..1109ec52e0 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -45,7 +45,7 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdat int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); +int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); int sd_ipv4ll_is_running(sd_ipv4ll *ll); int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll); -- cgit v1.2.3-54-g00ecf From 96a7979f3d77d1e629dcfe5ee018d18c281771a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 19:24:21 +0200 Subject: ipv4acd: rework how we pick ipv4ll addresses Let's make the seed actually work as stable seed, and use siphash24 to generate the series of addresses, instead of the opaque libc random_r(). This not only makes the seed truly work as stable, portable seed, but also makes the code quite a bit shorter, and removes a couple of memory allocations. --- src/libsystemd-network/sd-ipv4ll.c | 131 +++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 0e6a9df9e5..4fcb06a308 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -28,6 +28,7 @@ #include "sd-ipv4ll.h" #include "alloc-util.h" +#include "ether-addr-util.h" #include "in-addr-util.h" #include "list.h" #include "random-util.h" @@ -35,8 +36,8 @@ #include "sparse-endian.h" #include "util.h" -#define IPV4LL_NETWORK 0xA9FE0000UL -#define IPV4LL_NETMASK 0xFFFF0000UL +#define IPV4LL_NETWORK UINT32_C(0xA9FE0000) +#define IPV4LL_NETMASK UINT32_C(0xFFFF0000) #define IPV4LL_DONT_DESTROY(ll) \ _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) @@ -45,16 +46,25 @@ struct sd_ipv4ll { unsigned n_ref; sd_ipv4acd *acd; + be32_t address; /* the address pushed to ACD */ - struct random_data *random_data; - char *random_data_state; + struct ether_addr mac; + + struct { + le64_t value; + le64_t generation; + } seed; + bool seed_set; /* External */ be32_t claimed_address; + sd_ipv4ll_callback_t callback; void* userdata; }; +static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); + sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { if (!ll) return NULL; @@ -76,16 +86,11 @@ sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { return NULL; sd_ipv4acd_unref(ll->acd); - - free(ll->random_data); - free(ll->random_data_state); free(ll); return NULL; } -static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); - int sd_ipv4ll_new(sd_ipv4ll **ret) { _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; int r; @@ -113,43 +118,32 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { } int sd_ipv4ll_stop(sd_ipv4ll *ll) { - int r; - assert_return(ll, -EINVAL); - r = sd_ipv4acd_stop(ll->acd); - if (r < 0) - return r; - - return 0; + return sd_ipv4acd_stop(ll->acd); } int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { assert_return(ll, -EINVAL); assert_return(ifindex > 0, -EINVAL); + assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); return sd_ipv4acd_set_ifindex(ll->acd, ifindex); } -#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) - int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { int r; assert_return(ll, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - if (!ll->random_data) { - uint64_t seed; - - /* If no random data is set, generate some from the MAC */ - seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes); - - r = sd_ipv4ll_set_address_seed(ll, htole64(seed)); - if (r < 0) - return r; - } + r = sd_ipv4acd_set_mac(ll->acd, addr); + if (r < 0) + return r; - return sd_ipv4acd_set_mac(ll->acd, addr); + ll->mac = *addr; + return 0; } int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { @@ -186,31 +180,11 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { } int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) { - _cleanup_free_ struct random_data *random_data = NULL; - _cleanup_free_ char *random_data_state = NULL; - int r; - assert_return(ll, -EINVAL); + assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - random_data = new0(struct random_data, 1); - if (!random_data) - return -ENOMEM; - - random_data_state = new0(char, 128); - if (!random_data_state) - return -ENOMEM; - - r = initstate_r((unsigned) seed, random_data_state, 128, random_data); - if (r < 0) - return r; - - free(ll->random_data); - ll->random_data = random_data; - random_data = NULL; - - free(ll->random_data_state); - ll->random_data_state = random_data_state; - random_data_state = NULL; + ll->seed.value = htole64(seed); + ll->seed_set = true; return 0; } @@ -254,48 +228,64 @@ int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { return 0; } +#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b) + static int ipv4ll_pick_address(sd_ipv4ll *ll) { - struct in_addr in_addr; be32_t addr; - int r; - int32_t random; assert(ll); - assert(ll->random_data); do { - r = random_r(ll->random_data, &random); - if (r < 0) - return r; - addr = htobe32((random & 0x0000FFFF) | IPV4LL_NETWORK); - } while (addr == ll->address || - (ntohl(addr) & 0x0000FF00) == 0x0000 || - (ntohl(addr) & 0x0000FF00) == 0xFF00); + uint64_t h; - in_addr.s_addr = addr; + h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes); - r = sd_ipv4ll_set_address(ll, &in_addr); - if (r < 0) - return r; + /* Increase the generation counter by one */ + ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1); - return 0; + addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK); + } while (addr == ll->address || + (be32toh(addr) & 0x0000FF00) == 0x0000 || + (be32toh(addr) & 0x0000FF00) == 0xFF00); + + return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); } +#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) + int sd_ipv4ll_start(sd_ipv4ll *ll) { int r; + bool picked_address = false; assert_return(ll, -EINVAL); - assert_return(ll->random_data, -EINVAL); + assert_return(!ether_addr_is_null(&ll->mac), -EINVAL); + assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); + + /* If no random seed is set, generate some from the MAC address */ + if (!ll->seed_set) + ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes)); + + /* Restart the generation counter. */ + ll->seed.generation = 0; if (ll->address == 0) { r = ipv4ll_pick_address(ll); if (r < 0) return r; + + picked_address = true; } r = sd_ipv4acd_start(ll->acd); - if (r < 0) + if (r < 0) { + + /* We couldn't start? If so, let's forget the picked address again, the user might make a change and + * retry, and we want the new data to take effect when picking an address. */ + if (picked_address) + ll->address = 0; + return r; + } return 0; } @@ -345,6 +335,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { } break; + default: assert_not_reached("Invalid IPv4ACD event."); } -- cgit v1.2.3-54-g00ecf From 3aacc173e92126c3c9006aa163a2848c6523fd28 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 19:35:18 +0200 Subject: sd-ipv4acd: drop IPV4ACD_NETWORK definition Appears to be a copy/paste mistake from sd-ipv4ll. Let's get rid of this. --- src/libsystemd-network/sd-ipv4acd.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 31a05ae6dc..a4d57bd964 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -49,12 +49,6 @@ #define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC) #define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC) -#define IPV4ACD_NETWORK 0xA9FE0000UL -#define IPV4ACD_NETMASK 0xFFFF0000UL - -#define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__) -#define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__) - typedef enum IPv4ACDState { IPV4ACD_STATE_INIT, IPV4ACD_STATE_STARTED, @@ -92,6 +86,9 @@ struct sd_ipv4acd { void* userdata; }; +#define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__) + static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { assert(ll); assert(st < _IPV4ACD_STATE_MAX); -- cgit v1.2.3-54-g00ecf From 703945c1dcf2e46e5bf48427c7b23f5d90b6d53b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 19:35:54 +0200 Subject: sd-ipv4ll: add a bit of logging to IPv4LL too --- src/libsystemd-network/sd-ipv4ll.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 4fcb06a308..cba9a89b76 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -34,6 +34,7 @@ #include "random-util.h" #include "siphash24.h" #include "sparse-endian.h" +#include "string-util.h" #include "util.h" #define IPV4LL_NETWORK UINT32_C(0xA9FE0000) @@ -63,6 +64,9 @@ struct sd_ipv4ll { void* userdata; }; +#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__) +#define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) + static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { @@ -231,6 +235,7 @@ int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { #define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b) static int ipv4ll_pick_address(sd_ipv4ll *ll) { + _cleanup_free_ char *address = NULL; be32_t addr; assert(ll); @@ -248,6 +253,9 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { (be32toh(addr) & 0x0000FF00) == 0x0000 || (be32toh(addr) & 0x0000FF00) == 0xFF00); + (void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address); + log_ipv4ll(ll, "Picked new IP address %s.", strna(address)); + return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); } -- cgit v1.2.3-54-g00ecf From b24ef0493abec10435f43c4ce3791f625bad97f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 May 2016 19:39:44 +0200 Subject: ipv4acd: rename "ll" parameter to "acd" everywhere Appears to be a (confusing) left-over from copy/paste when this still was ipv4ll code. --- src/libsystemd-network/sd-ipv4acd.c | 304 ++++++++++++++++++------------------ src/systemd/sd-ipv4acd.h | 28 ++-- 2 files changed, 166 insertions(+), 166 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index a4d57bd964..662885840f 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -86,140 +86,140 @@ struct sd_ipv4acd { void* userdata; }; -#define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) -#define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__) +#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) -static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { - assert(ll); +static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { + assert(acd); assert(st < _IPV4ACD_STATE_MAX); - if (st == ll->state && !reset_counter) - ll->n_iteration++; + if (st == acd->state && !reset_counter) + acd->n_iteration++; else { - ll->state = st; - ll->n_iteration = 0; + acd->state = st; + acd->n_iteration = 0; } } -static void ipv4acd_reset(sd_ipv4acd *ll) { - assert(ll); +static void ipv4acd_reset(sd_ipv4acd *acd) { + assert(acd); - ll->timer_event_source = sd_event_source_unref(ll->timer_event_source); - ll->receive_message_event_source = sd_event_source_unref(ll->receive_message_event_source); + acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); + acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source); - ll->fd = safe_close(ll->fd); + acd->fd = safe_close(acd->fd); - ipv4acd_set_state(ll, IPV4ACD_STATE_INIT, true); + ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true); } -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) { - if (!ll) +sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd) { + if (!acd) return NULL; - assert_se(ll->n_ref >= 1); - ll->n_ref++; + assert_se(acd->n_ref >= 1); + acd->n_ref++; - return ll; + return acd; } -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { - if (!ll) +sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) { + if (!acd) return NULL; - assert_se(ll->n_ref >= 1); - ll->n_ref--; + assert_se(acd->n_ref >= 1); + acd->n_ref--; - if (ll->n_ref > 0) + if (acd->n_ref > 0) return NULL; - ipv4acd_reset(ll); - sd_ipv4acd_detach_event(ll); + ipv4acd_reset(acd); + sd_ipv4acd_detach_event(acd); - free(ll); + free(acd); return NULL; } int sd_ipv4acd_new(sd_ipv4acd **ret) { - _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *ll = NULL; + _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; assert_return(ret, -EINVAL); - ll = new0(sd_ipv4acd, 1); - if (!ll) + acd = new0(sd_ipv4acd, 1); + if (!acd) return -ENOMEM; - ll->n_ref = 1; - ll->state = IPV4ACD_STATE_INIT; - ll->ifindex = -1; - ll->fd = -1; + acd->n_ref = 1; + acd->state = IPV4ACD_STATE_INIT; + acd->ifindex = -1; + acd->fd = -1; - *ret = ll; - ll = NULL; + *ret = acd; + acd = NULL; return 0; } -static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { - assert(ll); +static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) { + assert(acd); - if (!ll->callback) + if (!acd->callback) return; - ll->callback(ll, event, ll->userdata); + acd->callback(acd, event, acd->userdata); } -int sd_ipv4acd_stop(sd_ipv4acd *ll) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_stop(sd_ipv4acd *acd) { + assert_return(acd, -EINVAL); - ipv4acd_reset(ll); + ipv4acd_reset(acd); - log_ipv4acd(ll, "STOPPED"); + log_ipv4acd(acd, "STOPPED"); - ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP); + ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP); return 0; } static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); -static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, usec_t usec, usec_t random_usec) { +static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) { _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; usec_t next_timeout, time_now; int r; - assert(ll); + assert(acd); next_timeout = usec; if (random_usec > 0) next_timeout += (usec_t) random_u64() % random_usec; - assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0); + assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, ll); + r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd); if (r < 0) return r; - r = sd_event_source_set_priority(timer, ll->event_priority); + r = sd_event_source_set_priority(timer, acd->event_priority); if (r < 0) return r; (void) sd_event_source_set_description(timer, "ipv4acd-timer"); - sd_event_source_unref(ll->timer_event_source); - ll->timer_event_source = timer; + sd_event_source_unref(acd->timer_event_source); + acd->timer_event_source = timer; timer = NULL; return 0; } -static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) { - assert(ll); +static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) { + assert(acd); assert(arp); /* see the BPF */ - if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0) + if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0) return true; /* the TPA matched instead of the SPA, this is not a conflict */ @@ -227,27 +227,27 @@ static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) { } static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_ipv4acd *ll = userdata; + sd_ipv4acd *acd = userdata; int r = 0; - assert(ll); + assert(acd); - switch (ll->state) { + switch (acd->state) { case IPV4ACD_STATE_STARTED: - ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); + ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true); - if (ll->n_conflict >= MAX_CONFLICTS) { + if (acd->n_conflict >= MAX_CONFLICTS) { char ts[FORMAT_TIMESPAN_MAX]; - log_ipv4acd(ll, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); + log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); - r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); + r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto fail; - ll->n_conflict = 0; + acd->n_conflict = 0; } else { - r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT_USEC); + r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); if (r < 0) goto fail; } @@ -257,28 +257,28 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: /* Send a probe */ - r = arp_send_probe(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); + r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { - log_ipv4acd_errno(ll, r, "Failed to send ARP probe: %m"); + log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m"); goto fail; } else { _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = ll->address }; + union in_addr_union addr = { .in.s_addr = acd->address }; (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(ll, "Probing %s", strna(address)); + log_ipv4acd(acd, "Probing %s", strna(address)); } - if (ll->n_iteration < PROBE_NUM - 2) { - ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false); + if (acd->n_iteration < PROBE_NUM - 2) { + ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false); - r = ipv4acd_set_next_wakeup(ll, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); + r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); if (r < 0) goto fail; } else { - ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true); + ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true); - r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT_USEC, 0); + r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0); if (r < 0) goto fail; } @@ -286,8 +286,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) break; case IPV4ACD_STATE_ANNOUNCING: - if (ll->n_iteration >= ANNOUNCE_NUM - 1) { - ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false); + if (acd->n_iteration >= ANNOUNCE_NUM - 1) { + ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false); break; } @@ -295,22 +295,22 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ - r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); + r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { - log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); + log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); goto fail; } else - log_ipv4acd(ll, "ANNOUNCE"); + log_ipv4acd(acd, "ANNOUNCE"); - ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false); + ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false); - r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL_USEC, 0); + r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0); if (r < 0) goto fail; - if (ll->n_iteration == 0) { - ll->n_conflict = 0; - ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND); + if (acd->n_iteration == 0) { + acd->n_conflict = 0; + ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND); } break; @@ -322,23 +322,23 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) return 0; fail: - sd_ipv4acd_stop(ll); + sd_ipv4acd_stop(acd); return 0; } -static void ipv4acd_on_conflict(sd_ipv4acd *ll) { +static void ipv4acd_on_conflict(sd_ipv4acd *acd) { _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = ll->address }; + union in_addr_union addr = { .in.s_addr = acd->address }; - assert(ll); + assert(acd); - ll->n_conflict++; + acd->n_conflict++; (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(ll, "Conflict on %s (%u)", strna(address), ll->n_conflict); + log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict); - ipv4acd_reset(ll); - ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT); + ipv4acd_reset(acd); + ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT); } static int ipv4acd_on_packet( @@ -347,13 +347,13 @@ static int ipv4acd_on_packet( uint32_t revents, void *userdata) { - sd_ipv4acd *ll = userdata; + sd_ipv4acd *acd = userdata; struct ether_arp packet; ssize_t n; int r; assert(s); - assert(ll); + assert(acd); assert(fd >= 0); n = recv(fd, &packet, sizeof(struct ether_arp), 0); @@ -361,36 +361,36 @@ static int ipv4acd_on_packet( if (errno == EAGAIN || errno == EINTR) return 0; - log_ipv4acd_errno(ll, errno, "Failed to read ARP packet: %m"); + log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m"); goto fail; } if ((size_t) n != sizeof(struct ether_arp)) { - log_ipv4acd(ll, "Ignoring too short ARP packet."); + log_ipv4acd(acd, "Ignoring too short ARP packet."); return 0; } - switch (ll->state) { + switch (acd->state) { case IPV4ACD_STATE_ANNOUNCING: case IPV4ACD_STATE_RUNNING: - if (ipv4acd_arp_conflict(ll, &packet)) { + if (ipv4acd_arp_conflict(acd, &packet)) { usec_t ts; - assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0); + assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0); /* Defend address */ - if (ts > ll->defend_window) { - ll->defend_window = ts + DEFEND_INTERVAL_USEC; - r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr); + if (ts > acd->defend_window) { + acd->defend_window = ts + DEFEND_INTERVAL_USEC; + r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) { - log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m"); + log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); goto fail; } else - log_ipv4acd(ll, "DEFEND"); + log_ipv4acd(acd, "DEFEND"); } else - ipv4acd_on_conflict(ll); + ipv4acd_on_conflict(acd); } break; @@ -398,7 +398,7 @@ static int ipv4acd_on_packet( case IPV4ACD_STATE_PROBING: case IPV4ACD_STATE_WAITING_ANNOUNCE: /* BPF ensures this packet indicates a conflict */ - ipv4acd_on_conflict(ll); + ipv4acd_on_conflict(acd); break; default: @@ -408,119 +408,119 @@ static int ipv4acd_on_packet( return 0; fail: - sd_ipv4acd_stop(ll); + sd_ipv4acd_stop(acd); return 0; } -int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int ifindex) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) { + assert_return(acd, -EINVAL); assert_return(ifindex > 0, -EINVAL); - assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - ll->ifindex = ifindex; + acd->ifindex = ifindex; return 0; } -int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) { + assert_return(acd, -EINVAL); assert_return(addr, -EINVAL); - assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - ll->mac_addr = *addr; + acd->mac_addr = *addr; return 0; } -int sd_ipv4acd_detach_event(sd_ipv4acd *ll) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_detach_event(sd_ipv4acd *acd) { + assert_return(acd, -EINVAL); - ll->event = sd_event_unref(ll->event); + acd->event = sd_event_unref(acd->event); return 0; } -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) { +int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) { int r; - assert_return(ll, -EINVAL); - assert_return(!ll->event, -EBUSY); + assert_return(acd, -EINVAL); + assert_return(!acd->event, -EBUSY); if (event) - ll->event = sd_event_ref(event); + acd->event = sd_event_ref(event); else { - r = sd_event_default(&ll->event); + r = sd_event_default(&acd->event); if (r < 0) return r; } - ll->event_priority = priority; + acd->event_priority = priority; return 0; } -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) { + assert_return(acd, -EINVAL); - ll->callback = cb; - ll->userdata = userdata; + acd->callback = cb; + acd->userdata = userdata; return 0; } -int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) { - assert_return(ll, -EINVAL); +int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) { + assert_return(acd, -EINVAL); assert_return(address, -EINVAL); - assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - ll->address = address->s_addr; + acd->address = address->s_addr; return 0; } -int sd_ipv4acd_is_running(sd_ipv4acd *ll) { - assert_return(ll, false); +int sd_ipv4acd_is_running(sd_ipv4acd *acd) { + assert_return(acd, false); - return ll->state != IPV4ACD_STATE_INIT; + return acd->state != IPV4ACD_STATE_INIT; } -int sd_ipv4acd_start(sd_ipv4acd *ll) { +int sd_ipv4acd_start(sd_ipv4acd *acd) { int r; - assert_return(ll, -EINVAL); - assert_return(ll->event, -EINVAL); - assert_return(ll->ifindex > 0, -EINVAL); - assert_return(ll->address != 0, -EINVAL); - assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL); - assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + assert_return(acd, -EINVAL); + assert_return(acd->event, -EINVAL); + assert_return(acd->ifindex > 0, -EINVAL); + assert_return(acd->address != 0, -EINVAL); + assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL); + assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - r = arp_network_bind_raw_socket(ll->ifindex, ll->address, &ll->mac_addr); + r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr); if (r < 0) return r; - safe_close(ll->fd); - ll->fd = r; - ll->defend_window = 0; - ll->n_conflict = 0; + safe_close(acd->fd); + acd->fd = r; + acd->defend_window = 0; + acd->n_conflict = 0; - r = sd_event_add_io(ll->event, &ll->receive_message_event_source, ll->fd, EPOLLIN, ipv4acd_on_packet, ll); + r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); if (r < 0) goto fail; - r = sd_event_source_set_priority(ll->receive_message_event_source, ll->event_priority); + r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority); if (r < 0) goto fail; - (void) sd_event_source_set_description(ll->receive_message_event_source, "ipv4acd-receive-message"); + (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message"); - r = ipv4acd_set_next_wakeup(ll, 0, 0); + r = ipv4acd_set_next_wakeup(acd, 0, 0); if (r < 0) goto fail; - ipv4acd_set_state(ll, IPV4ACD_STATE_STARTED, true); + ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true); return 0; fail: - ipv4acd_reset(ll); + ipv4acd_reset(acd); return r; } diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 604160ae3f..16d99983a8 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -37,20 +37,20 @@ enum { }; typedef struct sd_ipv4acd sd_ipv4acd; -typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata); - -int sd_ipv4acd_detach_event(sd_ipv4acd *ll); -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority); -int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata); -int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); -int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int interface_index); -int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); -int sd_ipv4acd_is_running(sd_ipv4acd *ll); -int sd_ipv4acd_start(sd_ipv4acd *ll); -int sd_ipv4acd_stop(sd_ipv4acd *ll); -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); +typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata); + +int sd_ipv4acd_detach_event(sd_ipv4acd *acd); +int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority); +int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); +int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); +int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); +int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); +int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); +int sd_ipv4acd_is_running(sd_ipv4acd *acd); +int sd_ipv4acd_start(sd_ipv4acd *acd); +int sd_ipv4acd_stop(sd_ipv4acd *acd); +sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); +sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); int sd_ipv4acd_new(sd_ipv4acd **ret); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref); -- cgit v1.2.3-54-g00ecf From d54b734adc45708e34437f23878ce0601cfcc0ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:15:49 +0200 Subject: sd-ndisc: Typo fix: s/advertisment/advertisement/ --- src/libsystemd-network/sd-ndisc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index c03e104e3b..c4d5eb45d2 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -40,7 +40,7 @@ enum NDiscState { NDISC_STATE_IDLE, NDISC_STATE_SOLICITATION_SENT, - NDISC_STATE_ADVERTISMENT_LISTEN, + NDISC_STATE_ADVERTISEMENT_LISTEN, _NDISC_STATE_MAX, _NDISC_STATE_INVALID = -1, }; @@ -355,7 +355,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, if (r != -EADDRNOTAVAIL) return r; - /* if router advertisment prefix valid timeout is zero, the timeout + /* if router advertisement prefix valid timeout is zero, the timeout callback will be called immediately to clean up the prefix */ r = ndisc_prefix_new(nd, &prefix); @@ -470,7 +470,7 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len return 0; } -static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_free_ struct nd_router_advert *ra = NULL; sd_ndisc *nd = userdata; union { @@ -565,7 +565,7 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r nd->timeout = sd_event_source_unref(nd->timeout); - nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; + nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3; @@ -612,7 +612,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { if (nd->callback) nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata); - nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; + nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; } else { r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); if (r < 0) @@ -680,7 +680,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { nd->fd = r; - r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, ndisc_router_advertisment_recv, nd); + r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd); if (r < 0) goto fail; -- cgit v1.2.3-54-g00ecf From b3dfcf6a767442ca1e912615b49449d5095429fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:16:36 +0200 Subject: sd-ndisc: use the right object to pass to log_ndisc() There's no "client" object, in both cases. There's only "nd". This wasn't noticed before, as the context object is currently not actually used by the log macros. --- src/libsystemd-network/sd-ndisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index c4d5eb45d2..3432c71f33 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -655,7 +655,7 @@ int sd_ndisc_stop(sd_ndisc *nd) { if (nd->state == NDISC_STATE_IDLE) return 0; - log_ndisc(client, "Stopping IPv6 Router Solicitation client"); + log_ndisc(nd, "Stopping IPv6 Router Solicitation client"); ndisc_reset(nd); nd->state = NDISC_STATE_IDLE; @@ -700,7 +700,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->timeout, "ndisc-timeout"); - log_ndisc(client, "Started IPv6 Router Solicitation client"); + log_ndisc(ns, "Started IPv6 Router Solicitation client"); return 0; fail: -- cgit v1.2.3-54-g00ecf From ad2998abd52678f49b2882a45474fd80fb90172c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:20:30 +0200 Subject: sd-ndisc: add log_ndisc_errno() macro, to complement log_ndisc() like elsewhere Also make use of it where appropriate. --- src/libsystemd-network/sd-ndisc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 3432c71f33..2f021debc1 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -90,7 +90,8 @@ struct sd_ndisc { void *userdata; }; -#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) +#define log_ndisc_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) +#define log_ndisc(p, fmt, ...) log_ndisc_errno(p, 0, fmt, ##__VA_ARGS__) static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { @@ -514,8 +515,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t if (errno == EAGAIN || errno == EINTR) return 0; - log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m"); - return -errno; + return log_ndisc_errno(nd, errno, "Could not receive message from ICMPv6 socket: %m"); } if ((size_t) len < sizeof(struct nd_router_advert)) { log_ndisc(nd, "Too small to be a router advertisement: ignoring"); @@ -588,7 +588,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t r = ndisc_ra_parse(nd, ra, len); if (r < 0) { - log_ndisc(nd, "Could not parse Router Advertisement: %s", strerror(-r)); + log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m"); return 0; } @@ -616,7 +616,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, } else { r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); if (r < 0) - log_ndisc(nd, "Error sending Router Solicitation"); + log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m"); else { nd->state = NDISC_STATE_SOLICITATION_SENT; log_ndisc(nd, "Sent Router Solicitation"); -- cgit v1.2.3-54-g00ecf From 3e261cfd3ce480eb60014248368461548ef1601f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:23:04 +0200 Subject: sd-ndisc: append "event_source" to event source objects stored in structures Otherwise it gets too confusing whether "timeout" refers to an event source or just a timeout time specification. --- src/libsystemd-network/sd-ndisc.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 2f021debc1..d1c51b4ed6 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -80,8 +80,8 @@ struct sd_ndisc { uint32_t mtu; LIST_HEAD(NDiscPrefix, prefixes); int fd; - sd_event_source *recv; - sd_event_source *timeout; + sd_event_source *recv_event_source; + sd_event_source *timeout_event_source; unsigned nd_sent; sd_ndisc_router_callback_t router_callback; sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; @@ -215,9 +215,9 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { static int ndisc_reset(sd_ndisc *nd) { assert(nd); - nd->recv = sd_event_source_unref(nd->recv); + nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); nd->fd = asynchronous_close(nd->fd); - nd->timeout = sd_event_source_unref(nd->timeout); + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); return 0; } @@ -563,7 +563,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t if (ra->nd_ra_code != 0) return 0; - nd->timeout = sd_event_source_unref(nd->timeout); + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; @@ -607,7 +607,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, assert(nd); assert(nd->event); - nd->timeout = sd_event_source_unref(nd->timeout); + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { if (nd->callback) @@ -628,7 +628,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; - r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), + r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), next_timeout, 0, ndisc_router_solicitation_timeout, nd); if (r < 0) { @@ -637,13 +637,11 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, return 0; } - r = sd_event_source_set_priority(nd->timeout, nd->event_priority); + r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); if (r < 0) return 0; - r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); - if (r < 0) - return 0; + (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); } return 0; @@ -680,25 +678,25 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { nd->fd = r; - r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd); + r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd); if (r < 0) goto fail; - r = sd_event_source_set_priority(nd->recv, nd->event_priority); + r = sd_event_source_set_priority(nd->recv_event_source, nd->event_priority); if (r < 0) goto fail; - (void) sd_event_source_set_description(nd->recv, "ndisc-receive-message"); + (void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message"); - r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd); + r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd); if (r < 0) goto fail; - r = sd_event_source_set_priority(nd->timeout, nd->event_priority); + r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); if (r < 0) goto fail; - (void) sd_event_source_set_description(nd->timeout, "ndisc-timeout"); + (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); log_ndisc(ns, "Started IPv6 Router Solicitation client"); return 0; -- cgit v1.2.3-54-g00ecf From 745c5152c210738e20bae5e377262e270f7a0335 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:24:43 +0200 Subject: sd-ndisc: simplify clamping of router "pref" parameter --- src/libsystemd-network/sd-ndisc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index d1c51b4ed6..c7969dbc1c 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -570,14 +570,8 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3; - switch (pref) { - case ND_RA_FLAG_PREF_LOW: - case ND_RA_FLAG_PREF_HIGH: - break; - default: + if (!IN_SET(pref, ND_RA_FLAG_PREF_LOW, ND_RA_FLAG_PREF_HIGH)) pref = ND_RA_FLAG_PREF_MEDIUM; - break; - } lifetime = be16toh(ra->nd_ra_router_lifetime); -- cgit v1.2.3-54-g00ecf From 901c983b6dca860e675fd77f703a44f15d900101 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:28:11 +0200 Subject: sd-ndisc: rework size checking in ndisc_ra_parse() Let's better check the size before we subtract. Also, let's change the size argument to size_t, as it cannot be signed anyway. Finally, use EBADMSG for indicating invalid packets, like we do everywhere else. --- src/libsystemd-network/sd-ndisc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index c7969dbc1c..36c6d444cc 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -336,7 +336,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, assert(prefix_opt); if (len < prefix_opt->nd_opt_pi_len) - return -ENOMSG; + return -EBADMSG; if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO))) return 0; @@ -411,20 +411,19 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, return 0; } -static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) { +static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) { void *opt; struct nd_opt_hdr *opt_hdr; assert(nd); assert(ra); - len -= sizeof(*ra); - if (len < NDISC_OPT_LEN_UNITS) { + if (len < sizeof(struct nd_router_advert) + NDISC_OPT_LEN_UNITS) { log_ndisc(nd, "Router Advertisement below minimum length"); - - return -ENOMSG; + return -EBADMSG; } + len -= sizeof(struct nd_router_advert); opt = ra + 1; opt_hdr = opt; @@ -434,7 +433,7 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len struct nd_opt_prefix_info *opt_prefix; if (opt_hdr->nd_opt_len == 0) - return -ENOMSG; + return -EBADMSG; switch (opt_hdr->nd_opt_type) { case ND_OPT_MTU: @@ -580,7 +579,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium", lifetime); - r = ndisc_ra_parse(nd, ra, len); + r = ndisc_ra_parse(nd, ra, (size_t) len); if (r < 0) { log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m"); return 0; -- cgit v1.2.3-54-g00ecf From b9e7b1cf06cdfb95397b11c60211f5bbe9df28d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:32:33 +0200 Subject: sd-ndisc: stop discovery properly when something fails --- src/libsystemd-network/sd-ndisc.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 36c6d444cc..28133e7a69 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -608,9 +608,10 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; } else { r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); - if (r < 0) + if (r < 0) { log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m"); - else { + goto fail; + } else { nd->state = NDISC_STATE_SOLICITATION_SENT; log_ndisc(nd, "Sent Router Solicitation"); } @@ -625,19 +626,24 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, next_timeout, 0, ndisc_router_solicitation_timeout, nd); if (r < 0) { - /* we cannot continue if we are unable to rearm the timer */ - sd_ndisc_stop(nd); - return 0; + log_ndisc_errno(nd, r, "Failed to allocate timer event: %m"); + goto fail; } r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); - if (r < 0) - return 0; + if (r < 0) { + log_ndisc_errno(nd, r, "Cannot set timer priority: %m"); + goto fail; + } (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); } return 0; + +fail: + sd_ndisc_stop(nd); + return 0; } int sd_ndisc_stop(sd_ndisc *nd) { -- cgit v1.2.3-54-g00ecf From 79b490b79606519fc197bd65098208f9e1312e1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:34:25 +0200 Subject: sd-ndisc: add more whitespace Whitespace doesn't hurt and helps structuring things. --- src/libsystemd-network/sd-ndisc.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 28133e7a69..4744fec4c0 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -73,16 +73,22 @@ struct sd_ndisc { unsigned n_ref; enum NDiscState state; + int ifindex; + int fd; + sd_event *event; int event_priority; - int ifindex; + struct ether_addr mac_addr; uint32_t mtu; + LIST_HEAD(NDiscPrefix, prefixes); - int fd; + sd_event_source *recv_event_source; sd_event_source *timeout_event_source; + unsigned nd_sent; + sd_ndisc_router_callback_t router_callback; sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback; @@ -412,8 +418,8 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, } static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) { - void *opt; struct nd_opt_hdr *opt_hdr; + void *opt; assert(nd); assert(ra); @@ -429,13 +435,14 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) { struct nd_opt_mtu *opt_mtu; - uint32_t mtu; struct nd_opt_prefix_info *opt_prefix; + uint32_t mtu; if (opt_hdr->nd_opt_len == 0) return -EBADMSG; switch (opt_hdr->nd_opt_type) { + case ND_OPT_MTU: opt_mtu = opt; @@ -443,18 +450,14 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) if (mtu != nd->mtu) { nd->mtu = MAX(mtu, IP6_MIN_MTU); - - log_ndisc(nd, "Router Advertisement link MTU %d using %d", - mtu, nd->mtu); + log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu); } break; case ND_OPT_PREFIX_INFORMATION: opt_prefix = opt; - ndisc_prefix_update(nd, len, opt_prefix); - break; } @@ -563,7 +566,6 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t return 0; nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); -- cgit v1.2.3-54-g00ecf From 9c4f6ccb70a192abb3ae58ac8f22d12c942ea898 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 May 2016 21:34:48 +0200 Subject: sd-ndisc: small coding style fixes Let's use usec_t internally always, when dealing with time values. Let's use uint8_t* pointers if we are dealing with generic byte pointers. --- src/libsystemd-network/sd-ndisc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 4744fec4c0..ccb8002173 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -462,8 +462,7 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) } len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS; - opt = (void *)((char *)opt + - opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); + opt = (void*) ((uint8_t*) opt + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); opt_hdr = opt; } @@ -595,7 +594,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ndisc *nd = userdata; - uint64_t time_now, next_timeout; + usec_t time_now, next_timeout; int r; assert(s); -- cgit v1.2.3-54-g00ecf From ae06d1be4efed2448315cd8e5e4bf08abaa03e26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 26 May 2016 15:32:23 +0200 Subject: ipv4ll: shorten some checks by using IN_SET a bit As suggested: https://github.com/systemd/systemd/pull/3328#discussion-diff-64285764 --- src/libsystemd-network/sd-ipv4ll.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index cba9a89b76..5603a533a5 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -200,20 +200,12 @@ int sd_ipv4ll_is_running(sd_ipv4ll *ll) { } static bool ipv4ll_address_is_valid(const struct in_addr *address) { - uint32_t addr; - assert(address); if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) return false; - addr = be32toh(address->s_addr); - - if ((addr & 0x0000FF00) == 0x0000 || - (addr & 0x0000FF00) == 0xFF00) - return false; - - return true; + return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); } int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { @@ -250,8 +242,7 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK); } while (addr == ll->address || - (be32toh(addr) & 0x0000FF00) == 0x0000 || - (be32toh(addr) & 0x0000FF00) == 0xFF00); + IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U)); (void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address); log_ipv4ll(ll, "Picked new IP address %s.", strna(address)); -- cgit v1.2.3-54-g00ecf From acc0269cad31d1aaef2034a055b34c07c88a353d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 May 2016 15:57:37 +0200 Subject: {machine,system}ctl: always pass &changes and &n_changes (#3350) We have to pass addresses of changes and n_changes to bus_deserialize_and_dump_unit_file_changes(). Otherwise we are hit by missing information (subsequent calls to unit_file_changes_add() to not add anything). Also prevent null pointer dereference in bus_deserialize_and_dump_unit_file_changes() by asserting. Fixes #3339 --- src/machine/machinectl.c | 15 ++++++++--- src/shared/bus-unit-util.c | 5 ++++ src/systemctl/systemctl.c | 64 +++++++++++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 1165ab5afa..8e4ffa9a39 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1602,6 +1602,8 @@ static int start_machine(int argc, char *argv[], void *userdata) { static int enable_machine(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int carries_install_info = 0; const char *method = NULL; sd_bus *bus = userdata; @@ -1662,9 +1664,9 @@ static int enable_machine(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); } - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; r = sd_bus_call_method( bus, @@ -1677,10 +1679,15 @@ static int enable_machine(int argc, char *argv[], void *userdata) { NULL); if (r < 0) { log_error("Failed to reload daemon: %s", bus_error_message(&error, -r)); - return r; + goto finish; } - return 0; + r = 0; + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) { diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f6559cd854..f68c4a41ac 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -865,6 +865,11 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un const char *type, *path, *source; int r; + /* changes is dereferenced when calling unit_file_dump_changes() later, + * so we have to make sure this is not NULL. */ + assert(changes); + assert(n_changes); + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); if (r < 0) return bus_log_parse_error(r); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b943c68e1b..0500593d06 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2058,6 +2058,8 @@ static int get_default(int argc, char *argv[], void *userdata) { static int set_default(int argc, char *argv[], void *userdata) { _cleanup_free_ char *unit = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int r; assert(argc >= 2); @@ -2068,13 +2070,8 @@ static int set_default(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to mangle unit name: %m"); if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -2098,9 +2095,9 @@ static int set_default(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; /* Try to reload if enabled */ if (!arg_no_reload) @@ -2109,6 +2106,9 @@ static int set_default(int argc, char *argv[], void *userdata) { r = 0; } +finish: + unit_file_changes_free(changes, n_changes); + return r; } @@ -5650,6 +5650,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *target = NULL; const char *verb = argv[0]; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; UnitDependency dep; int r = 0; @@ -5672,13 +5674,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown verb"); if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5712,27 +5709,32 @@ static int add_dependency(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; - if (arg_no_reload) - return 0; - return daemon_reload(argc, argv, userdata); + if (arg_no_reload) { + r = 0; + goto finish; + } + + r = daemon_reload(argc, argv, userdata); } + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int preset_all(int argc, char *argv[], void *userdata) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int r; if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5759,14 +5761,22 @@ static int preset_all(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; - if (arg_no_reload) - return 0; - return daemon_reload(argc, argv, userdata); + if (arg_no_reload) { + r = 0; + goto finish; + } + + r = daemon_reload(argc, argv, userdata); } + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int unit_is_enabled(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From 87c05f365d0f11e7207e9ff03a50e5988e1af5ce Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Thu, 26 May 2016 22:38:25 +0200 Subject: nspawn: a bench of special fileystems that should not be shifted Add some special filesystems that should not be shifted, most of them relate to the host and not to containers. --- src/basic/missing.h | 12 ++++++++++++ src/nspawn/nspawn-patch-uid.c | 3 +++ 2 files changed, 15 insertions(+) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index 651e414395..2077ada72d 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -453,6 +453,18 @@ struct btrfs_ioctl_quota_ctl_args { #define MQUEUE_MAGIC 0x19800202 #endif +#ifndef SECURITYFS_MAGIC +#define SECURITYFS_MAGIC 0x73636673 +#endif + +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + +#ifndef BPF_FS_MAGIC +#define BPF_FS_MAGIC 0xcafe4a11 +#endif + #ifndef MS_MOVE #define MS_MOVE 8192 #endif diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c index c7382d412d..6b26b074d9 100644 --- a/src/nspawn/nspawn-patch-uid.c +++ b/src/nspawn/nspawn-patch-uid.c @@ -300,6 +300,9 @@ static int is_procfs_sysfs_or_suchlike(int fd) { F_TYPE_EQUAL(sfs.f_type, PSTOREFS_MAGIC) || F_TYPE_EQUAL(sfs.f_type, SELINUX_MAGIC) || F_TYPE_EQUAL(sfs.f_type, SMACK_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, SECURITYFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, BPF_FS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, TRACEFS_MAGIC) || F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC); } -- cgit v1.2.3-54-g00ecf From 231bfb1b02e0ff3fc335018cc58d83d8ef085dd8 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Thu, 26 May 2016 12:59:49 +0200 Subject: nspawn: rename is_procfs_sysfs_or_suchlike() to is_fs_fully_userns_compatible() Rename is_procfs_sysfs_or_suchlike() to is_fs_fully_userns_compatible() to give it the real meaning. This may prevent future modifications that may introduce bugs. --- src/nspawn/nspawn-patch-uid.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c index 6b26b074d9..cc79597c95 100644 --- a/src/nspawn/nspawn-patch-uid.c +++ b/src/nspawn/nspawn-patch-uid.c @@ -280,7 +280,13 @@ static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift return r > 0 || changed; } -static int is_procfs_sysfs_or_suchlike(int fd) { +/* + * Check if the filesystem is fully compatible with user namespaces or + * UID/GID patching. Some filesystems in this list can be fully mounted inside + * user namespaces, however their inodes may relate to host resources or only + * valid in the global user namespace, therefore no patching should be applied. + */ +static int is_fs_fully_userns_compatible(int fd) { struct statfs sfs; assert(fd >= 0); @@ -314,8 +320,8 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we * probably shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's - * stop the recursion when we hit a procfs or sysfs file system. */ - r = is_procfs_sysfs_or_suchlike(fd); + * stop the recursion when we hit procfs, sysfs or some other special file systems. */ + r = is_fs_fully_userns_compatible(fd); if (r < 0) goto finish; if (r > 0) { -- cgit v1.2.3-54-g00ecf From f011b0b87a5ab3b2c85849558d464fcfcad85923 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Thu, 26 May 2016 22:42:29 +0200 Subject: nspawn: split out seccomp call into nspawn-seccomp.[ch] Split seccomp into nspawn-seccomp.[ch]. Currently there are no changes, but this will make it easy in the future to share or use the seccomp logic from systemd core. --- Makefile.am | 2 + src/nspawn/nspawn-seccomp.c | 143 ++++++++++++++++++++++++++++++++++++++++++++ src/nspawn/nspawn-seccomp.h | 24 ++++++++ src/nspawn/nspawn.c | 102 +------------------------------ 4 files changed, 171 insertions(+), 100 deletions(-) create mode 100644 src/nspawn/nspawn-seccomp.c create mode 100644 src/nspawn/nspawn-seccomp.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 305099ab66..f8e1fac967 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3016,6 +3016,8 @@ systemd_nspawn_SOURCES = \ src/nspawn/nspawn-expose-ports.h \ src/nspawn/nspawn-cgroup.c \ src/nspawn/nspawn-cgroup.h \ + src/nspawn/nspawn-seccomp.c \ + src/nspawn/nspawn-seccomp.h \ src/nspawn/nspawn-register.c \ src/nspawn/nspawn-register.h \ src/nspawn/nspawn-setuid.c \ diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c new file mode 100644 index 0000000000..2d145b68a7 --- /dev/null +++ b/src/nspawn/nspawn-seccomp.c @@ -0,0 +1,143 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include +#include +#include + +#ifdef HAVE_SECCOMP +#include +#endif + +#include "log.h" + +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif + +#include "nspawn-seccomp.h" + +#ifdef HAVE_SECCOMP + +static int seccomp_add_default_syscall_filter(scmp_filter_ctx ctx, + uint64_t cap_list_retain) { + unsigned i; + int r; + static const struct { + uint64_t capability; + int syscall_num; + } blacklist[] = { + { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, + { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, + { CAP_SYS_BOOT, SCMP_SYS(kexec_load) }, + { CAP_SYS_ADMIN, SCMP_SYS(swapon) }, + { CAP_SYS_ADMIN, SCMP_SYS(swapoff) }, + { CAP_SYS_ADMIN, SCMP_SYS(open_by_handle_at) }, + { CAP_SYS_MODULE, SCMP_SYS(init_module) }, + { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, + { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, + { CAP_SYSLOG, SCMP_SYS(syslog) }, + }; + + for (i = 0; i < ELEMENTSOF(blacklist); i++) { + if (cap_list_retain & (1ULL << blacklist[i].capability)) + continue; + + r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0); + if (r == -EFAULT) + continue; /* unknown syscall */ + if (r < 0) { + log_error_errno(r, "Failed to block syscall: %m"); + return r; + } + } + + return 0; +} + +int setup_seccomp(uint64_t cap_list_retain) { + scmp_filter_ctx seccomp; + int r; + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return log_oom(); + + r = seccomp_add_secondary_archs(seccomp); + if (r < 0) { + log_error_errno(r, "Failed to add secondary archs to seccomp filter: %m"); + goto finish; + } + + r = seccomp_add_default_syscall_filter(seccomp, cap_list_retain); + if (r < 0) + goto finish; + + /* + Audit is broken in containers, much of the userspace audit + hookup will fail if running inside a container. We don't + care and just turn off creation of audit sockets. + + This will make socket(AF_NETLINK, *, NETLINK_AUDIT) fail + with EAFNOSUPPORT which audit userspace uses as indication + that audit is disabled in the kernel. + */ + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EAFNOSUPPORT), + SCMP_SYS(socket), + 2, + SCMP_A0(SCMP_CMP_EQ, AF_NETLINK), + SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT)); + if (r < 0) { + log_error_errno(r, "Failed to add audit seccomp rule: %m"); + goto finish; + } + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) { + log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m"); + goto finish; + } + + r = seccomp_load(seccomp); + if (r == -EINVAL) { + log_debug_errno(r, "Kernel is probably not configured with CONFIG_SECCOMP. Disabling seccomp audit filter: %m"); + r = 0; + goto finish; + } + if (r < 0) { + log_error_errno(r, "Failed to install seccomp audit filter: %m"); + goto finish; + } + +finish: + seccomp_release(seccomp); + return r; +} + +#else + +int setup_seccomp(uint64_t cap_list_retain) { + return 0; +} + +#endif diff --git a/src/nspawn/nspawn-seccomp.h b/src/nspawn/nspawn-seccomp.h new file mode 100644 index 0000000000..5bde16faf9 --- /dev/null +++ b/src/nspawn/nspawn-seccomp.h @@ -0,0 +1,24 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +int setup_seccomp(uint64_t cap_list_retain); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ac11bcea5a..646ef96f9b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -26,9 +26,6 @@ #include #include #include -#ifdef HAVE_SECCOMP -#include -#endif #ifdef HAVE_SELINUX #include #endif @@ -82,15 +79,13 @@ #include "nspawn-settings.h" #include "nspawn-setuid.h" #include "nspawn-stub-pid1.h" +#include "nspawn-seccomp.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "ptyfwd.h" #include "random-util.h" #include "rm-rf.h" -#ifdef HAVE_SECCOMP -#include "seccomp-util.h" -#endif #include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" @@ -1667,99 +1662,6 @@ static int reset_audit_loginuid(void) { return 0; } -static int setup_seccomp(void) { - -#ifdef HAVE_SECCOMP - static const struct { - uint64_t capability; - int syscall_num; - } blacklist[] = { - { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, - { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, - { CAP_SYS_BOOT, SCMP_SYS(kexec_load) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapon) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapoff) }, - { CAP_SYS_ADMIN, SCMP_SYS(open_by_handle_at) }, - { CAP_SYS_MODULE, SCMP_SYS(init_module) }, - { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, - { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, - { CAP_SYSLOG, SCMP_SYS(syslog) }, - }; - - scmp_filter_ctx seccomp; - unsigned i; - int r; - - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return log_oom(); - - r = seccomp_add_secondary_archs(seccomp); - if (r < 0) { - log_error_errno(r, "Failed to add secondary archs to seccomp filter: %m"); - goto finish; - } - - for (i = 0; i < ELEMENTSOF(blacklist); i++) { - if (arg_retain & (1ULL << blacklist[i].capability)) - continue; - - r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0); - if (r == -EFAULT) - continue; /* unknown syscall */ - if (r < 0) { - log_error_errno(r, "Failed to block syscall: %m"); - goto finish; - } - } - - /* - Audit is broken in containers, much of the userspace audit - hookup will fail if running inside a container. We don't - care and just turn off creation of audit sockets. - - This will make socket(AF_NETLINK, *, NETLINK_AUDIT) fail - with EAFNOSUPPORT which audit userspace uses as indication - that audit is disabled in the kernel. - */ - - r = seccomp_rule_add( - seccomp, - SCMP_ACT_ERRNO(EAFNOSUPPORT), - SCMP_SYS(socket), - 2, - SCMP_A0(SCMP_CMP_EQ, AF_NETLINK), - SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT)); - if (r < 0) { - log_error_errno(r, "Failed to add audit seccomp rule: %m"); - goto finish; - } - - r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); - if (r < 0) { - log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m"); - goto finish; - } - - r = seccomp_load(seccomp); - if (r == -EINVAL) { - log_debug_errno(r, "Kernel is probably not configured with CONFIG_SECCOMP. Disabling seccomp audit filter: %m"); - r = 0; - goto finish; - } - if (r < 0) { - log_error_errno(r, "Failed to install seccomp audit filter: %m"); - goto finish; - } - -finish: - seccomp_release(seccomp); - return r; -#else - return 0; -#endif - -} static int setup_propagate(const char *root) { const char *p, *q; @@ -2988,7 +2890,7 @@ static int outer_child( if (r < 0) return r; - r = setup_seccomp(); + r = setup_seccomp(arg_retain); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 520e0d541f5617f2866c20eab011761e63d67017 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Thu, 26 May 2016 13:06:55 +0200 Subject: nspawn: rename arg_retain to arg_caps_retain The argument is about capabilities. --- src/nspawn/nspawn.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 646ef96f9b..b421c182ce 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -131,7 +131,7 @@ static StartMode arg_start_mode = START_PID1; static bool arg_ephemeral = false; static LinkJournal arg_link_journal = LINK_AUTO; static bool arg_link_journal_try = false; -static uint64_t arg_retain = +static uint64_t arg_caps_retain = (1ULL << CAP_CHOWN) | (1ULL << CAP_DAC_OVERRIDE) | (1ULL << CAP_DAC_READ_SEARCH) | @@ -1070,7 +1070,7 @@ static int parse_argv(int argc, char *argv[]) { if (mask_all_settings) arg_settings_mask = _SETTINGS_MASK_ALL; - arg_retain = (arg_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus; + arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus; r = detect_unified_cgroup_hierarchy(); if (r < 0) @@ -1627,7 +1627,7 @@ static int setup_journal(const char *directory) { } static int drop_capabilities(void) { - return capability_bounding_set_drop(arg_retain, false); + return capability_bounding_set_drop(arg_caps_retain, false); } static int reset_audit_loginuid(void) { @@ -2890,7 +2890,7 @@ static int outer_child( if (r < 0) return r; - r = setup_seccomp(arg_retain); + r = setup_seccomp(arg_caps_retain); if (r < 0) return r; @@ -3174,9 +3174,9 @@ static int load_settings(void) { if (settings->capability != 0) log_warning("Ignoring Capability= setting, file %s is not trusted.", p); } else - arg_retain |= plus; + arg_caps_retain |= plus; - arg_retain &= ~settings->drop_capability; + arg_caps_retain &= ~settings->drop_capability; } if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 && -- cgit v1.2.3-54-g00ecf From aa91232040fdd25c8405cce4dea7c0f142d96236 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Thu, 26 May 2016 23:32:25 +0200 Subject: resolve/test-dns-packet: Fix unaligned access in test_packet_from_file(). --- src/resolve/test-dns-packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index c232a69ce1..41e5c1caa5 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -29,6 +29,7 @@ #include "resolved-dns-rr.h" #include "string-util.h" #include "strv.h" +#include "unaligned.h" #define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) @@ -56,7 +57,7 @@ static void test_packet_from_file(const char* filename, bool canonical) { const char *s, *s2; uint64_t hash1, hash2; - packet_size = le64toh( *(uint64_t*)(data + offset) ); + packet_size = unaligned_read_le64(data + offset); assert_se(packet_size > 0); assert_se(offset + 8 + packet_size <= data_size); -- cgit v1.2.3-54-g00ecf From 7f30799adee958603ca52ed1ad6a4e298e7ca652 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 May 2016 09:21:02 +0200 Subject: systemctl: remove extra comma --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0500593d06..94c590130a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7466,7 +7466,7 @@ static int systemctl_main(int argc, char *argv[]) { { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root }, { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies }, { "set-default", 2, 2, 0, set_default }, - { "get-default", VERB_ANY, 1, 0, get_default, }, + { "get-default", VERB_ANY, 1, 0, get_default }, { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property }, { "is-system-running", VERB_ANY, 1, 0, is_system_running }, { "add-wants", 3, VERB_ANY, 0, add_dependency }, -- cgit v1.2.3-54-g00ecf From 5f056378b0ceffb6e6fba3513f7eae72e2d09dc8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 May 2016 09:32:41 +0200 Subject: systemctl: fix return values on success --- src/systemctl/systemctl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 94c590130a..f4cdfa956e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1439,6 +1439,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { assert(c <= n_units); hashmap_free(h); + + r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -2025,6 +2027,7 @@ static int get_default(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to get default target: %m"); path = _path; + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; @@ -2072,6 +2075,9 @@ static int set_default(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5676,6 +5682,9 @@ static int add_dependency(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5735,6 +5744,9 @@ static int preset_all(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5817,6 +5829,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { puts(unit_file_state_to_string(state)); } + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; -- cgit v1.2.3-54-g00ecf From 85b78539c994984a6cbcc1095f126a1302db7808 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 May 2016 09:33:27 +0200 Subject: systemctl: fix code path (and memory leak) on error --- src/systemctl/systemctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index f4cdfa956e..86feefcb65 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5514,7 +5514,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet); if (r < 0) - return r; + goto finish; r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; @@ -5606,7 +5606,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; /* Try to reload if enabled */ if (!arg_no_reload) -- cgit v1.2.3-54-g00ecf From 83afa09d97e47c746d840a5893d375052dd57523 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 May 2016 08:41:45 -0700 Subject: core: fix missing newline when writing drop-in for WorkingDirectory (#3337) --- src/core/dbus-execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 06943c6365..e21956def1 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -987,7 +987,7 @@ int bus_exec_context_set_transient_property( } c->working_directory_missing_ok = missing_ok; - unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s); + unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s\n", missing_ok ? "-" : "", s); } return 1; -- cgit v1.2.3-54-g00ecf From da4d897e75e574911cb73ac91fdeef7d4fce8fbe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 May 2016 09:10:18 -0700 Subject: core: add cgroup memory controller support on the unified hierarchy (#3315) On the unified hierarchy, memory controller implements three control knobs - low, high and max which enables more useable and versatile control over memory usage. This patch implements support for the three control knobs. * MemoryLow, MemoryHigh and MemoryMax are added for memory.low, memory.high and memory.max, respectively. * As all absolute limits on the unified hierarchy use "max" for no limit, make memory limit parse functions accept "max" in addition to "infinity" and document "max" for the new knobs. * Implement compatibility translation between MemoryMax and MemoryLimit. v2: - Fixed missing else's in config_parse_memory_limit(). - Fixed missing newline when writing out drop-ins. - Coding style updates to use "val > 0" instead of "val". - Minor updates to documentation. --- man/systemd.resource-control.xml | 71 +++++++++++++++++++++++++++++++++++ src/core/cgroup.c | 63 +++++++++++++++++++++++-------- src/core/cgroup.h | 4 ++ src/core/dbus-cgroup.c | 28 ++++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 3 ++ src/core/load-fragment.c | 25 +++++++----- src/shared/bus-unit-util.c | 6 +-- src/systemctl/systemctl.c | 39 +++++++++++++++++-- 8 files changed, 206 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 066f2cc19b..570619a743 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -114,6 +114,13 @@ prefixed ones. On unified hierarchy, IO resource control also applies to buffered writes. + + + + MemoryMax replaces MemoryLimit. MemoryLow + and MemoryHigh are effective only on unified hierarchy. + + @@ -212,6 +219,67 @@ + + MemoryLow=bytes + + + Specify the best-effort memory usage protection of the executed processes in this unit. If the memory + usages of this unit and all its ancestors are below their low boundaries, this unit's memory won't be + reclaimed as long as memory can be reclaimed from unprotected units. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. This controls the + memory.low control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. + + + + + MemoryHigh=bytes + + + Specify the high limit on memory usage of the executed processes in this unit. Memory usage may go + above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away + aggressively in such cases. This is the main mechanism to control memory usage of a unit. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + special value max, no memory limit is applied. This controls the + memory.high control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. + + + + + MemoryMax=bytes + + + Specify the absolute limit on memory usage of the executed processes in this unit. If memory usage + cannot be contained under the limit, out-of-memory killer is invoked inside the unit. It is recommended to + use MemoryHigh= as the main control mechanism and use MemoryMax= as the + last line of defense. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + special value max, no memory limit is applied. This controls the + memory.max control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. Use + MemoryLimit= on systems using the legacy control group hierarchy. + + + MemoryLimit=bytes @@ -230,6 +298,9 @@ url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt. Implies MemoryAccounting=true. + + This setting is supported only if the legacy control group hierarchy is used. Use + MemoryMax= on systems using the unified control group hierarchy. diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 0fb63b1bd1..fbe69df4e9 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -46,7 +46,10 @@ void cgroup_context_init(CGroupContext *c) { c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID; c->cpu_quota_per_sec_usec = USEC_INFINITY; - c->memory_limit = (uint64_t) -1; + c->memory_high = CGROUP_LIMIT_MAX; + c->memory_max = CGROUP_LIMIT_MAX; + + c->memory_limit = CGROUP_LIMIT_MAX; c->io_weight = CGROUP_WEIGHT_INVALID; c->startup_io_weight = CGROUP_WEIGHT_INVALID; @@ -147,6 +150,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" "%sStartupBlockIOWeight=%" PRIu64 "\n" + "%sMemoryLow=%" PRIu64 "\n" + "%sMemoryHigh=%" PRIu64 "\n" + "%sMemoryMax=%" PRIu64 "\n" "%sMemoryLimit=%" PRIu64 "\n" "%sTasksMax=%" PRIu64 "\n" "%sDevicePolicy=%s\n" @@ -163,6 +169,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, c->startup_io_weight, prefix, c->blockio_weight, prefix, c->startup_blockio_weight, + prefix, c->memory_low, + prefix, c->memory_high, + prefix, c->memory_max, prefix, c->memory_limit, prefix, c->tasks_max, prefix, cgroup_device_policy_to_string(c->device_policy), @@ -496,6 +505,23 @@ static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *de return n; } +static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { + return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX; +} + +static void cgroup_apply_unified_memory_limit(const char *path, const char *file, uint64_t v) { + char buf[DECIMAL_STR_MAX(uint64_t) + 1] = "max"; + int r; + + if (v != CGROUP_LIMIT_MAX) + xsprintf(buf, "%" PRIu64 "\n", v); + + r = cg_set_attribute("memory", path, file, buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set %s on %s: %m", file, path); +} + void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) { bool is_root; int r; @@ -662,26 +688,30 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } if ((mask & CGROUP_MASK_MEMORY) && !is_root) { - if (c->memory_limit != (uint64_t) -1) { - char buf[DECIMAL_STR_MAX(uint64_t) + 1]; - - sprintf(buf, "%" PRIu64 "\n", c->memory_limit); + if (cg_unified() > 0) { + uint64_t max = c->memory_max; - if (cg_unified() <= 0) - r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); + if (cgroup_context_has_unified_memory_config(c)) + max = c->memory_max; else - r = cg_set_attribute("memory", path, "memory.max", buf); + max = c->memory_limit; + cgroup_apply_unified_memory_limit(path, "memory.low", c->memory_low); + cgroup_apply_unified_memory_limit(path, "memory.high", c->memory_high); + cgroup_apply_unified_memory_limit(path, "memory.max", max); } else { - if (cg_unified() <= 0) - r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1"); + char buf[DECIMAL_STR_MAX(uint64_t) + 1]; + + if (c->memory_limit != CGROUP_LIMIT_MAX) + xsprintf(buf, "%" PRIu64 "\n", c->memory_limit); else - r = cg_set_attribute("memory", path, "memory.max", "max"); - } + xsprintf(buf, "%" PRIu64 "\n", c->memory_max); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path); + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set memory.limit_in_bytes on %s: %m", path); + } } if ((mask & CGROUP_MASK_DEVICES) && !is_root) { @@ -778,7 +808,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; if (c->memory_accounting || - c->memory_limit != (uint64_t) -1) + c->memory_limit != CGROUP_LIMIT_MAX || + cgroup_context_has_unified_memory_config(c)) mask |= CGROUP_MASK_MEMORY; if (c->device_allow || diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 2b1edbafc4..ff87adfba1 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -94,6 +94,10 @@ struct CGroupContext { LIST_HEAD(CGroupIODeviceWeight, io_device_weights); LIST_HEAD(CGroupIODeviceLimit, io_device_limits); + uint64_t memory_low; + uint64_t memory_high; + uint64_t memory_max; + /* For legacy hierarchies */ uint64_t cpu_shares; uint64_t startup_cpu_shares; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index d6053581f8..27050b4507 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -228,6 +228,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), + SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0), + SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0), + SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), @@ -826,6 +829,31 @@ int bus_cgroup_set_property( return 1; + } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) { + uint64_t v; + + r = sd_bus_message_read(message, "t", &v); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + if (streq(name, "MemoryLow")) + c->memory_low = v; + else if (streq(name, "MemoryHigh")) + c->memory_high = v; + else + c->memory_max = v; + + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + + if (v == CGROUP_LIMIT_MAX) + unit_write_drop_in_private_format(u, mode, name, "%s=max\n", name); + else + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, v); + } + + return 1; + } else if (streq(name, "MemoryLimit")) { uint64_t limit; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 8193418980..00bdc238ce 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -117,6 +117,9 @@ $1.CPUShares, config_parse_cpu_shares, 0, $1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares) $1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context) $1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) +$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context) $1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 86b4fb071b..09d3f65c77 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2793,21 +2793,26 @@ int config_parse_memory_limit( void *userdata) { CGroupContext *c = data; - uint64_t bytes; + uint64_t bytes = CGROUP_LIMIT_MAX; int r; - if (isempty(rvalue) || streq(rvalue, "infinity")) { - c->memory_limit = (uint64_t) -1; - return 0; + if (!isempty(rvalue) && !streq(rvalue, "infinity") && !streq(rvalue, "max")) { + r = parse_size(rvalue, 1024, &bytes); + if (r < 0 || bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } } - r = parse_size(rvalue, 1024, &bytes); - if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); - return 0; - } + if (streq(lvalue, "MemoryLow")) + c->memory_low = bytes; + else if (streq(lvalue, "MemoryHigh")) + c->memory_high = bytes; + else if (streq(lvalue, "MemoryMax")) + c->memory_max = bytes; + else + c->memory_limit = bytes; - c->memory_limit = bytes; return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f68c4a41ac..502e98d9dc 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -166,11 +166,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (streq(field, "MemoryLimit")) { + } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { uint64_t bytes; - if (isempty(eq) || streq(eq, "infinity")) - bytes = (uint64_t) -1; + if (isempty(eq) || streq(eq, "max") || streq(eq, "infinity")) + bytes = CGROUP_LIMIT_MAX; else { r = parse_size(eq, 1024, &bytes); if (r < 0) { diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0500593d06..b2ee00fab3 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3493,6 +3493,9 @@ typedef struct UnitStatusInfo { /* CGroup */ uint64_t memory_current; + uint64_t memory_low; + uint64_t memory_high; + uint64_t memory_max; uint64_t memory_limit; uint64_t cpu_usage_nsec; uint64_t tasks_current; @@ -3775,10 +3778,30 @@ static void print_status_info( printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); - if (i->memory_limit != (uint64_t) -1) - printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit)); - else - printf("\n"); + if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX || + i->memory_limit != CGROUP_LIMIT_MAX) { + const char *prefix = ""; + + printf(" ("); + if (i->memory_low > 0) { + printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low)); + prefix = " "; + } + if (i->memory_high != CGROUP_LIMIT_MAX) { + printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high)); + prefix = " "; + } + if (i->memory_max != CGROUP_LIMIT_MAX) { + printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max)); + prefix = " "; + } + if (i->memory_limit != CGROUP_LIMIT_MAX) { + printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit)); + prefix = " "; + } + printf(")"); + } + printf("\n"); } if (i->cpu_usage_nsec != (uint64_t) -1) { @@ -4007,6 +4030,12 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->assert_timestamp = (usec_t) u; else if (streq(name, "MemoryCurrent")) i->memory_current = u; + else if (streq(name, "MemoryLow")) + i->memory_low = u; + else if (streq(name, "MemoryHigh")) + i->memory_high = u; + else if (streq(name, "MemoryMax")) + i->memory_max = u; else if (streq(name, "MemoryLimit")) i->memory_limit = u; else if (streq(name, "TasksCurrent")) @@ -4500,6 +4529,8 @@ static int show_one( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; UnitStatusInfo info = { .memory_current = (uint64_t) -1, + .memory_high = CGROUP_LIMIT_MAX, + .memory_max = CGROUP_LIMIT_MAX, .memory_limit = (uint64_t) -1, .cpu_usage_nsec = (uint64_t) -1, .tasks_current = (uint64_t) -1, -- cgit v1.2.3-54-g00ecf From 9ae84244107ff4bf0f49d1c68e6d4eed3be99b6c Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Thu, 26 May 2016 23:48:04 +0200 Subject: networkd/sd-dhcp-server: Fix unaligned access in parse_request(). --- src/libsystemd-network/sd-dhcp-server.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index fb335337c4..a1af5da40f 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -29,6 +29,7 @@ #include "in-addr-util.h" #include "siphash24.h" #include "string-util.h" +#include "unaligned.h" #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) @@ -604,17 +605,17 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us switch(code) { case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: if (len == 4) - req->lifetime = be32toh(*(be32_t*)option); + req->lifetime = unaligned_read_be32(option); break; case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS: if (len == 4) - req->requested_ip = *(be32_t*)option; + memcpy(&req->requested_ip, option, sizeof(be32_t)); break; case SD_DHCP_OPTION_SERVER_IDENTIFIER: if (len == 4) - req->server_id = *(be32_t*)option; + memcpy(&req->server_id, option, sizeof(be32_t)); break; case SD_DHCP_OPTION_CLIENT_IDENTIFIER: @@ -633,8 +634,7 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us break; case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE: if (len == 2) - req->max_optlen = be16toh(*(be16_t*)option) - - - sizeof(DHCPPacket); + req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket); break; } -- cgit v1.2.3-54-g00ecf From 2b2d8603ce5b9cbe797745ab6339f6f5e0dfb4ad Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Sat, 28 May 2016 13:31:41 +0800 Subject: networkd: unset master if not enslaved with networkd When we manage an interface with networkd but not as a slave (i.e. no `Bridge=` or `Bond=` set in its .network), we do not want it to remain slaved. --- src/network/networkd-link.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 6e6f9618b0..377e6f52f4 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1568,6 +1568,13 @@ static int link_up(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); + /* set it free if not enslaved with networkd */ + if (!link->network->bridge && !link->network->bond) { + r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m"); + } + r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP); if (r < 0) return log_link_error_errno(link, r, "Could not set link flags: %m"); -- cgit v1.2.3-54-g00ecf From 2b00a4e03dc375465de7f60f3a6937cbe8ffdf31 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Sat, 28 May 2016 13:35:01 +0800 Subject: networkd: disable IPv6 for bridge slave If an interface is managed as a bridge slave, we don't want any IP configuration for it. Therefore, disable IPv6 in such case. --- src/network/networkd-link.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 377e6f52f4..0d9d228796 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -110,6 +110,9 @@ static bool link_ipv6_enabled(Link *link) { if (!socket_ipv6_is_supported()) return false; + if (link->network->bridge) + return false; + /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */ return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); } @@ -1586,7 +1589,7 @@ static int link_up(Link *link) { } /* If IPv6 not configured (no static IPv6 address and IPv6LL autoconfiguration is disabled) - for this interface then disable IPv6 else enable it. */ + for this interface, or if it is a bridge slave, then disable IPv6 else enable it. */ (void) link_enable_ipv6(link); if (link->network->mtu) { -- cgit v1.2.3-54-g00ecf From ac3608cdbc28a14acd4c087ca6cd80d396f15eec Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sat, 28 May 2016 11:03:03 +0200 Subject: login: Fix policy for org.freedesktop.login1.set-self-linger (#3365) (#3373) We need to explicitly define authorizations for allow_inactive and allow_active. Otherwise one is getting "Access denied" when run from a local console: $ loginctl enable-linger Could not enable linger: Access denied --- src/login/org.freedesktop.login1.policy.in | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in index 1fa6441629..66cbce393c 100644 --- a/src/login/org.freedesktop.login1.policy.in +++ b/src/login/org.freedesktop.login1.policy.in @@ -116,6 +116,8 @@ <_message>Explicit request is required to run programs as a non-logged-in user. yes + yes + yes -- cgit v1.2.3-54-g00ecf From be8386a3e51183738a61cf46dea698ef9d499bae Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 10:50:36 -0400 Subject: systemctl: remove empty line between comment and action It's harder to miss the comment without the newline ;) See https://github.com/systemd/systemd/pull/3336#issuecomment-221749423 for context. --- src/systemctl/systemctl.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c301c6a64f..9c8bfffc9b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7841,6 +7841,5 @@ finish: release_busses(); /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */ - return r < 0 ? EXIT_FAILURE : r; } -- cgit v1.2.3-54-g00ecf From 0053598f3615c9a069264d08180f0132da1ec73f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 11:50:37 -0400 Subject: Typo fix: s/advertisment/advertisement/ --- NEWS | 2 +- src/network/networkd-link.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index c299ed7180..33b55e9170 100644 --- a/NEWS +++ b/NEWS @@ -783,7 +783,7 @@ CHANGES WITH 227: * systemd-networkd gained support for: - - Setting the IPv6 Router Advertisment settings via + - Setting the IPv6 Router Advertisement settings via IPv6AcceptRouterAdvertisements= in .network files. - Configuring the HelloTimeSec=, MaxAgeSec= and diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a021fc886f..28becae354 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2146,7 +2146,7 @@ static int link_set_ipv6_accept_ra(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); - /* We handle router advertisments ourselves, tell the kernel to GTFO */ + /* We handle router advertisements ourselves, tell the kernel to GTFO */ r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE); if (r < 0) log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m"); -- cgit v1.2.3-54-g00ecf From 2a9a6f8ac04a69ca36d645f9305a33645f22a22b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 16:06:44 -0400 Subject: core/unit: append newline when writing drop ins unit_write_drop_in{,_private}{,_format} are all affected. We already append a header to the file (and section markers), so those functions can only be used to write a whole file at once. Including the newline at the end feels natural. After this commit newlines will be duplicated. They will be removed in subsequent commit. Also, rewrap the "autogenerated" header to fit within 80 columns. --- src/core/unit.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index 2fff3f2d8b..e98086a3f6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3355,7 +3355,7 @@ static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) { int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { _cleanup_free_ char *p = NULL, *q = NULL; - const char *dir, *prefixed; + const char *dir, *wrapped; int r; assert(u); @@ -3374,15 +3374,17 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co if (!dir) return -EINVAL; - prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n", - data); + wrapped = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\"\n" + "or an equivalent operation. Do not edit.\n", + data, + "\n"); r = drop_in_file(dir, u->id, 50, name, &p, &q); if (r < 0) return r; (void) mkdir_p(p, 0755); - r = write_string_file_atomic_label(q, prefixed); + r = write_string_file_atomic_label(q, wrapped); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From b27b4b51c6fa3963941da3b65312384be1aedd69 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 16:21:47 -0400 Subject: tree-wide: remove newlines from unit_write_drop_in This reverts part of #3329, but all for a good cause. --- src/core/dbus-cgroup.c | 52 ++++++++++++++++++++-------------------- src/core/dbus-execute.c | 64 ++++++++++++++++++++++++------------------------- src/core/dbus-kill.c | 8 +++---- src/core/dbus-scope.c | 2 +- src/core/dbus-service.c | 6 ++--- src/core/dbus-timer.c | 12 +++++----- src/core/dbus-unit.c | 8 +++---- 7 files changed, 76 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 27050b4507..8525fa1bf1 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -263,7 +263,7 @@ static int bus_cgroup_set_transient_property( if (mode != UNIT_CHECK) { c->delegate = b; - unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes\n" : "Delegate=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no"); } return 1; @@ -298,7 +298,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU); - unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes\n" : "CPUAccounting=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); } return 1; @@ -318,9 +318,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) - unit_write_drop_in_private(u, mode, name, "CPUShares=\n"); + unit_write_drop_in_private(u, mode, name, "CPUShares="); else - unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64 "\n", shares); + unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares); } return 1; @@ -340,9 +340,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupCPUShares=\n"); + unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); else - unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64 "\n", shares); + unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares); } return 1; @@ -360,7 +360,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_quota_per_sec_usec = u64; unit_invalidate_cgroup(u, CGROUP_MASK_CPU); - unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%\n", (double) (c->cpu_quota_per_sec_usec / 10000)); + unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000)); } return 1; @@ -375,7 +375,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->io_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_IO); - unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes\n" : "IOAccounting=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no"); } return 1; @@ -395,9 +395,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_IO); if (weight == CGROUP_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "IOWeight=\n"); + unit_write_drop_in_private(u, mode, name, "IOWeight="); else - unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64 "\n", weight); + unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight); } return 1; @@ -417,9 +417,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_IO); if (weight == CGROUP_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupIOWeight=\n"); + unit_write_drop_in_private(u, mode, name, "StartupIOWeight="); else - unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64 "\n", weight); + unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight); } return 1; @@ -592,7 +592,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->blockio_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); - unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes\n" : "BlockIOAccounting=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); } return 1; @@ -612,9 +612,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "BlockIOWeight=\n"); + unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); else - unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64 "\n", weight); + unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight); } return 1; @@ -634,9 +634,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) - unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=\n"); + unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); else - unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64 "\n", weight); + unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight); } return 1; @@ -824,7 +824,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->memory_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); - unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes\n" : "MemoryAccounting=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); } return 1; @@ -847,9 +847,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (v == CGROUP_LIMIT_MAX) - unit_write_drop_in_private_format(u, mode, name, "%s=max\n", name); + unit_write_drop_in_private_format(u, mode, name, "%s=max", name); else - unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, v); + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v); } return 1; @@ -866,9 +866,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (limit == (uint64_t) -1) - unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity\n"); + unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); else - unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64 "\n", limit); + unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit); } return 1; @@ -888,7 +888,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->device_policy = p; unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); - unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s\n", policy); + unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy); } return 1; @@ -992,7 +992,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->tasks_accounting = b; unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); - unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes\n" : "TasksAccounting=no\n"); + unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); } return 1; @@ -1009,9 +1009,9 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); if (limit == (uint64_t) -1) - unit_write_drop_in_private(u, mode, name, "TasksMax=infinity\n"); + unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); else - unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64 "\n", limit); + unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); } return 1; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index e21956def1..de29d5da04 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -842,7 +842,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->user, uu) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu); + unit_write_drop_in_private_format(u, mode, name, "User=%s", uu); } return 1; @@ -861,7 +861,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->group, gg) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg); + unit_write_drop_in_private_format(u, mode, name, "Group=%s", gg); } return 1; @@ -879,7 +879,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->syslog_identifier, id) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id); + unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s", id); } return 1; @@ -895,7 +895,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level; - unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level); + unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i", level); } return 1; @@ -911,7 +911,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority); - unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility); + unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i", facility); } return 1; @@ -927,7 +927,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->nice = n; - unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n); + unit_write_drop_in_private_format(u, mode, name, "Nice=%i", n); } return 1; @@ -952,7 +952,7 @@ int bus_exec_context_set_transient_property( if (r < 0) return r; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s); } return 1; @@ -987,7 +987,7 @@ int bus_exec_context_set_transient_property( } c->working_directory_missing_ok = missing_ok; - unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s\n", missing_ok ? "-" : "", s); + unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s); } return 1; @@ -1007,7 +1007,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->std_input = p; - unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p)); + unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s", exec_input_to_string(p)); } return 1; @@ -1028,7 +1028,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->std_output = p; - unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p)); + unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s", exec_output_to_string(p)); } return 1; @@ -1048,7 +1048,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->std_error = p; - unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p)); + unit_write_drop_in_private_format(u, mode, name, "StandardError=%s", exec_output_to_string(p)); } return 1; @@ -1081,7 +1081,7 @@ int bus_exec_context_set_transient_property( else if (streq(name, "SyslogLevelPrefix")) c->syslog_level_prefix = b; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b)); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } return 1; @@ -1099,7 +1099,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->utmp_id, id) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id)); + unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s", strempty(id)); } return 1; @@ -1119,7 +1119,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->utmp_mode = m; - unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s\n", exec_utmp_mode_to_string(m)); + unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s", exec_utmp_mode_to_string(m)); } return 1; @@ -1137,7 +1137,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->pam_name, n) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n)); + unit_write_drop_in_private_format(u, mode, name, "PAMName=%s", strempty(n)); } return 1; @@ -1159,7 +1159,7 @@ int bus_exec_context_set_transient_property( if (strv_length(l) == 0) { c->environment = strv_free(c->environment); - unit_write_drop_in_private_format(u, mode, name, "Environment=\n"); + unit_write_drop_in_private_format(u, mode, name, "Environment="); } else { e = strv_env_merge(2, c->environment, l); if (!e) @@ -1172,7 +1172,7 @@ int bus_exec_context_set_transient_property( if (!joined) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + unit_write_drop_in_private_format(u, mode, name, "Environment=%s", joined); } } @@ -1188,7 +1188,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->timer_slack_nsec = n; - unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n); + unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT, n); } return 1; @@ -1206,7 +1206,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->oom_score_adjust = oa; c->oom_score_adjust_set = true; - unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa); + unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i", oa); } return 1; @@ -1228,7 +1228,7 @@ int bus_exec_context_set_transient_property( return -ENOMEM; STRV_FOREACH(i, c->environment_files) - fprintf(f, "EnvironmentFile=%s\n", *i); + fprintf(f, "EnvironmentFile=%s", *i); while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) { const char *path; @@ -1252,7 +1252,7 @@ int bus_exec_context_set_transient_property( if (!buf) return -ENOMEM; - fprintf(f, "EnvironmentFile=%s\n", buf); + fprintf(f, "EnvironmentFile=%s", buf); r = strv_consume(&l, buf); if (r < 0) @@ -1273,7 +1273,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { if (strv_isempty(l)) { c->environment_files = strv_free(c->environment_files); - unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n"); + unit_write_drop_in_private(u, mode, name, "EnvironmentFile="); } else { r = strv_extend_strv(&c->environment_files, l, true); if (r < 0) @@ -1299,7 +1299,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { if (strv_isempty(l)) { c->pass_environment = strv_free(c->pass_environment); - unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n"); + unit_write_drop_in_private_format(u, mode, name, "PassEnvironment="); } else { _cleanup_free_ char *joined = NULL; @@ -1311,7 +1311,7 @@ int bus_exec_context_set_transient_property( if (!joined) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined); + unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s", joined); } } @@ -1349,7 +1349,7 @@ int bus_exec_context_set_transient_property( if (strv_length(l) == 0) { *dirs = strv_free(*dirs); - unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + unit_write_drop_in_private_format(u, mode, name, "%s=", name); } else { r = strv_extend_strv(dirs, l, true); @@ -1360,7 +1360,7 @@ int bus_exec_context_set_transient_property( if (!joined) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined); } } @@ -1388,7 +1388,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->protect_system = ps; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s); } return 1; @@ -1414,7 +1414,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->protect_home = ph; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s); } return 1; @@ -1437,7 +1437,7 @@ int bus_exec_context_set_transient_property( if (strv_isempty(l)) { c->runtime_directory = strv_free(c->runtime_directory); - unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + unit_write_drop_in_private_format(u, mode, name, "%s=", name); } else { r = strv_extend_strv(&c->runtime_directory, l, true); @@ -1448,7 +1448,7 @@ int bus_exec_context_set_transient_property( if (!joined) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined); } } @@ -1467,7 +1467,7 @@ int bus_exec_context_set_transient_property( else if (free_and_strdup(&c->selinux_context, s) < 0) return -ENOMEM; - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s)); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, strempty(s)); } return 1; @@ -1535,7 +1535,7 @@ int bus_exec_context_set_transient_property( return -ENOMEM; } - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, f); } return 1; diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index 0f54c6b84b..8c65be65fa 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -63,7 +63,7 @@ int bus_kill_context_set_transient_property( if (mode != UNIT_CHECK) { c->kill_mode = k; - unit_write_drop_in_private_format(u, mode, name, "KillMode=%s\n", kill_mode_to_string(k)); + unit_write_drop_in_private_format(u, mode, name, "KillMode=%s", kill_mode_to_string(k)); } return 1; @@ -81,7 +81,7 @@ int bus_kill_context_set_transient_property( if (mode != UNIT_CHECK) { c->kill_signal = sig; - unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s\n", signal_to_string(sig)); + unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s", signal_to_string(sig)); } return 1; @@ -96,7 +96,7 @@ int bus_kill_context_set_transient_property( if (mode != UNIT_CHECK) { c->send_sighup = b; - unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b)); + unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s", yes_no(b)); } return 1; @@ -111,7 +111,7 @@ int bus_kill_context_set_transient_property( if (mode != UNIT_CHECK) { c->send_sigkill = b; - unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b)); + unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s", yes_no(b)); } return 1; diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index 34ee9a8fa9..f557eedfc3 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -147,7 +147,7 @@ static int bus_scope_set_transient_property( if (r < 0) return r; - unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec); + unit_write_drop_in_private_format(UNIT(s), mode, name, "TimeoutStopSec="USEC_FMT"us", s->timeout_stop_usec); } else { r = sd_bus_message_skip(message, "t"); if (r < 0) diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 03eecca911..fab3677a01 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -102,7 +102,7 @@ static int bus_service_set_transient_property( if (mode != UNIT_CHECK) { s->remain_after_exit = b; - unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b)); + unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s", yes_no(b)); } return 1; @@ -121,7 +121,7 @@ static int bus_service_set_transient_property( if (mode != UNIT_CHECK) { s->type = k; - unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type)); + unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s", service_type_to_string(s->type)); } return 1; @@ -134,7 +134,7 @@ static int bus_service_set_transient_property( if (mode != UNIT_CHECK) { s->runtime_max_usec = u; - unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u); + unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us", u); } return 1; diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index a0e61b023e..efbb0e8915 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -220,7 +220,7 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { char time[FORMAT_TIMESPAN_MAX]; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); v = new0(TimerValue, 1); if (!v) @@ -249,7 +249,7 @@ static int bus_timer_set_transient_property( if (r < 0) return r; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str); + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, str); v = new0(TimerValue, 1); if (!v) { @@ -277,7 +277,7 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { t->accuracy_usec = u; - unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u); + unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us", u); } return 1; @@ -291,7 +291,7 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { t->random_usec = u; - unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u); + unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us", u); } return 1; @@ -305,7 +305,7 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { t->wake_system = b; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b)); + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b)); } return 1; @@ -319,7 +319,7 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { t->remain_after_elapse = b; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b)); + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b)); } return 1; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index e912fe2192..b55d2cf735 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1205,7 +1205,7 @@ static int bus_unit_set_transient_property( if (r < 0) return r; - unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d); + unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d); } return 1; @@ -1219,7 +1219,7 @@ static int bus_unit_set_transient_property( if (mode != UNIT_CHECK) { u->default_dependencies = b; - unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b)); + unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b)); } return 1; @@ -1257,7 +1257,7 @@ static int bus_unit_set_transient_property( if (r < 0) return r; - unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s); + unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s); } return 1; @@ -1305,7 +1305,7 @@ static int bus_unit_set_transient_property( if (!label) return -ENOMEM; - unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other); + unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other); } } -- cgit v1.2.3-54-g00ecf From 8c35b2ca15a9194412c95ba594712b0d5fe25a64 Mon Sep 17 00:00:00 2001 From: kpengboy Date: Sun, 29 May 2016 08:31:14 -0700 Subject: Fix FS_EXTENT_FL description (#3381) --- src/tmpfiles/tmpfiles.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 2053d35a67..79ccf9fad9 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -866,7 +866,7 @@ static int parse_attribute_from_arg(Item *item) { { 'a', FS_APPEND_FL }, /* writes to file may only append */ { 'c', FS_COMPR_FL }, /* Compress file */ { 'd', FS_NODUMP_FL }, /* do not dump file */ - { 'e', FS_EXTENT_FL }, /* Top of directory hierarchies*/ + { 'e', FS_EXTENT_FL }, /* Extents */ { 'i', FS_IMMUTABLE_FL }, /* Immutable file */ { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */ { 's', FS_SECRM_FL }, /* Secure deletion */ -- cgit v1.2.3-54-g00ecf From 8869a0b40b1cf82d264cabc2ff8052e8e35145a2 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Mon, 30 May 2016 02:03:51 +0200 Subject: util-lib: Add sparc64 support for process creation (#3348) The current raw_clone function takes two arguments, the cloning flags and a pointer to the stack for the cloned child. The raw cloning without passing a "thread main" function does not make sense if a new stack is specified, as it returns in both the parent and the child, which will fail in the child as the stack is virgin. All uses of raw_clone indeed pass NULL for the stack pointer which indicates that both processes should share the stack address (so you better don't pass CLONE_VM). This commit refactors the code to not require the caller to pass the stack address, as NULL is the only sensible option. It also adds the magic code needed to make raw_clone work on sparc64, which does not return 0 in %o0 for the child, but indicates the child process by setting %o1 to non-zero. This refactoring is not plain aesthetic, because non-NULL stack addresses need to get mangled before being passed to the clone syscall (you have to apply STACK_BIAS), whereas NULL must not be mangled. Implementing the conditional mangling of the stack address would needlessly complicate the code. raw_clone is moved to a separete header, because the burden of including the assert machinery and sched.h shouldn't be applied to every user of missing_syscalls.h --- Makefile.am | 1 + src/basic/missing_syscall.h | 12 ------- src/basic/process-util.c | 3 +- src/basic/raw-clone.h | 81 +++++++++++++++++++++++++++++++++++++++++++++ src/core/main.c | 5 +-- src/nspawn/nspawn.c | 6 ++-- src/test/test-util.c | 3 +- 7 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 src/basic/raw-clone.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index f8e1fac967..c31c30c051 100644 --- a/Makefile.am +++ b/Makefile.am @@ -746,6 +746,7 @@ noinst_LTLIBRARIES += \ libbasic_la_SOURCES = \ src/basic/missing.h \ src/basic/missing_syscall.h \ + src/basic/raw-clone.h \ src/basic/capability-util.c \ src/basic/capability-util.h \ src/basic/conf-files.c \ diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d502d3b9ca..e102083684 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -178,18 +178,6 @@ static inline int setns(int fd, int nstype) { /* ======================================================================= */ -static inline int raw_clone(unsigned long flags, void *child_stack) { -#if defined(__s390__) || defined(__CRIS__) - /* On s390 and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - return (int) syscall(__NR_clone, child_stack, flags); -#else - return (int) syscall(__NR_clone, flags, child_stack); -#endif -} - -/* ======================================================================= */ - static inline pid_t raw_getpid(void) { #if defined(__alpha__) return (pid_t) syscall(__NR_getxpid); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 1ad8816206..b991e7c6ba 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -48,6 +48,7 @@ #include "macro.h" #include "missing.h" #include "process-util.h" +#include "raw-clone.h" #include "signal-util.h" #include "stat-util.h" #include "string-table.h" @@ -726,7 +727,7 @@ void valgrind_summary_hack(void) { #ifdef HAVE_VALGRIND_VALGRIND_H if (getpid() == 1 && RUNNING_ON_VALGRIND) { pid_t pid; - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); else if (pid == 0) diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h new file mode 100644 index 0000000000..d473828999 --- /dev/null +++ b/src/basic/raw-clone.h @@ -0,0 +1,81 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 Michael Karcher + 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 . +***/ + +#include +#include + +#include "log.h" +#include "macro.h" + +/** + * raw_clone() - uses clone to create a new process with clone flags + * @flags: Flags to pass to the clone system call + * + * Uses the clone system call to create a new process with the cloning + * flags and termination signal passed in the flags parameter. Opposed + * to glibc's clone funtion, using this function does not set up a + * separate stack for the child, but relies on copy-on-write semantics + * on the one stack at a common virtual address, just as fork does. + * + * To obtain copy-on-write semantics, flags must not contain CLONE_VM, + * and thus CLONE_THREAD and CLONE_SIGHAND (which require CLONE_VM) are + * not usabale. + * Additionally, as this function does not pass the ptid, newtls and ctid + * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, + * CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS. + * + * Returns: 0 in the child process and the child process id in the parent. + */ +static inline int raw_clone(unsigned long flags) { + assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID| + CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0); +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall(__NR_clone, NULL, flags); +#elif defined(__sparc__) && defined(__arch64__) + { + /** + * sparc64 always returns the other process id in %o0, and + * a boolean flag whether this is the child or the parent in + * %o1. Inline assembly is needed to get the flag returned + * in %o1. + */ + int in_child; + int child_pid; + asm volatile("mov %2, %%g1\n\t" + "mov %3, %%o0\n\t" + "mov 0 , %%o1\n\t" + "t 0x6d\n\t" + "mov %%o1, %0\n\t" + "mov %%o0, %1" : + "=r"(in_child), "=r"(child_pid) : + "i"(__NR_clone), "r"(flags) : + "%o1", "%o0", "%g1" ); + if (in_child) + return 0; + else + return child_pid; + } +#else + return (int) syscall(__NR_clone, flags, NULL); +#endif +} diff --git a/src/core/main.c b/src/core/main.c index 6397aadc73..93098daa9b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -70,6 +70,7 @@ #include "parse-util.h" #include "proc-cmdline.h" #include "process-util.h" +#include "raw-clone.h" #include "rlimit-util.h" #include "selinux-setup.h" #include "selinux-util.h" @@ -162,7 +163,7 @@ noreturn static void crash(int sig) { /* We want to wait for the core process, hence let's enable SIGCHLD */ (void) sigaction(SIGCHLD, &sa, NULL); - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); else if (pid == 0) { @@ -221,7 +222,7 @@ noreturn static void crash(int sig) { log_notice("Executing crash shell in 10s..."); (void) sleep(10); - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b421c182ce..d1c65e8b0b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -85,6 +85,7 @@ #include "process-util.h" #include "ptyfwd.h" #include "random-util.h" +#include "raw-clone.h" #include "rm-rf.h" #include "selinux-util.h" #include "signal-util.h" @@ -2938,8 +2939,7 @@ static int outer_child( pid = raw_clone(SIGCHLD|CLONE_NEWNS| (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) | (arg_private_network ? CLONE_NEWNET : 0) | - (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0), - NULL); + (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0)); if (pid < 0) return log_error_errno(errno, "Failed to fork inner child: %m"); if (pid == 0) { @@ -3608,7 +3608,7 @@ int main(int argc, char *argv[]) { goto finish; } - pid = raw_clone(SIGCHLD|CLONE_NEWNS, NULL); + pid = raw_clone(SIGCHLD|CLONE_NEWNS); if (pid < 0) { if (errno == EINVAL) r = log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m"); diff --git a/src/test/test-util.c b/src/test/test-util.c index 05cb1eae76..9b6d2a7968 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -26,6 +26,7 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "raw-clone.h" #include "rm-rf.h" #include "string-util.h" #include "util.h" @@ -244,7 +245,7 @@ static void test_raw_clone(void) { log_info("before clone: getpid()→"PID_FMT, parent); assert_se(raw_getpid() == parent); - pid = raw_clone(0, NULL); + pid = raw_clone(0); assert_se(pid >= 0); pid2 = raw_getpid(); -- cgit v1.2.3-54-g00ecf From e95764ec91ace68e328bacae96a56195550d6c0e Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 30 May 2016 16:35:34 +0200 Subject: udevd: try close ctrl connection blocking socket only once when spawning a new worker (#3387) --- src/udev/udevd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/udev/udevd.c b/src/udev/udevd.c index e9dd2f47c7..a8ab208816 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -368,7 +368,6 @@ static void worker_spawn(Manager *manager, struct event *event) { manager->monitor = udev_monitor_unref(manager->monitor); manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking); manager->ctrl = udev_ctrl_unref(manager->ctrl); - manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking); manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); -- cgit v1.2.3-54-g00ecf From ca473d572f0d2d8f547ff787ae67afd489a3f15e Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 30 May 2016 20:23:15 +0530 Subject: systemctl: return diffrent error code if service exist or not (#3385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: [sus@maximus bz-1256858]$ systemctl status rsyslog.service;echo $? ● rsyslog.service - System Logging Service Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/rsyslog.service.d └─50-CPUShares.conf Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 26min ago Docs: man:rsyslogd(8) http://www.rsyslog.com/doc/ Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, status=0/SUCCESS) Main PID: 1159 (code=exited, status=0/SUCCESS) May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... May 30 11:07:50 maximus systemd[1]: Started System Logging Service. May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. 3 [sus@maximus bz-1256858]$ systemctl status hello.service;echo $? ● hello.service Loaded: not-found (Reason: No such file or directory) Active: inactive (dead) 3 After: $ ./systemctl status hello.service;echo $? Failed to dump process list, ignoring: Access denied ● hello.service Loaded: not-found (Reason: No such file or directory) Active: inactive (dead) 4 [sus@maximus bz-1256858]$ ./systemctl status rsyslog.service;echo $? Failed to dump process list, ignoring: Access denied ● rsyslog.service - System Logging Service Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/rsyslog.service.d └─50-CPUShares.conf Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 24min ago Docs: man:rsyslogd(8) http://www.rsyslog.com/doc/ Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, status=0/SUCCESS) Main PID: 1159 (code=exited, status=0/SUCCESS) May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... May 30 11:07:50 maximus systemd[1]: Started System Logging Service. May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. 3 Fixes: 1092 --- src/systemctl/systemctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9c8bfffc9b..58255ae453 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4633,6 +4633,8 @@ static int show_one( */ if (info.pid_file && access(info.pid_file, F_OK) == 0) r = 1; + else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) + r = 4; else r = 3; } -- cgit v1.2.3-54-g00ecf From c6f8d17de0c36f94213496e2c9fd013f113ebe08 Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Mon, 30 May 2016 17:00:16 +0200 Subject: networkd: bridge add support to configure VLAN filtering (#3344) This patch implements support for IFLA_BR_VLAN_FILTERING configuration. --- man/systemd.netdev.xml | 9 +++++++++ src/network/networkd-netdev-bridge.c | 7 +++++++ src/network/networkd-netdev-bridge.h | 1 + src/network/networkd-netdev-gperf.gperf | 1 + 4 files changed, 18 insertions(+) (limited to 'src') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 8d12c305d2..cde5d65949 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -330,6 +330,15 @@ + + VLANFiltering= + + A boolean. This setting controls the IFLA_BR_VLAN_FILTERING option in the kernel. + If enabled, the bridge will be started in VLAN-filtering mode. When unset, the kernel's + default setting applies. + + + diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 4cfd00413f..a5085d2b19 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -102,6 +102,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m"); } + if (b->vlan_filtering >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BR_VLAN_FILTERING, b->vlan_filtering); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); @@ -128,6 +134,7 @@ static void bridge_init(NetDev *n) { b->mcast_querier = -1; b->mcast_snooping = -1; + b->vlan_filtering = -1; } const NetDevVTable bridge_vtable = { diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index f2ae21fc50..a637aea0a3 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -26,6 +26,7 @@ typedef struct Bridge { int mcast_querier; int mcast_snooping; + int vlan_filtering; usec_t forward_delay; usec_t hello_time; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index ba04bb0165..adc64977b9 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -100,3 +100,4 @@ Bridge.MaxAgeSec, config_parse_sec, 0, Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay) Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) +Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering) -- cgit v1.2.3-54-g00ecf From 3c6f7c340237262b560586cf7cf06be957d4352f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 17:59:43 +0200 Subject: util-lib: make localed's nonempty() generic, rename it to empty_to_null() and make use of it everywhere --- src/basic/string-util.h | 4 ++++ src/hostname/hostnamed.c | 14 ++++++-------- src/locale/localed.c | 29 +++++++---------------------- src/machine/machine-dbus.c | 3 +-- src/resolve/resolve-tool.c | 12 ++++-------- src/systemctl/systemctl.c | 4 +--- src/sysv-generator/sysv-generator.c | 12 +++--------- 7 files changed, 26 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 139cc8c91b..1209e1e2e1 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -66,6 +66,10 @@ static inline bool isempty(const char *p) { return !p || !p[0]; } +static inline const char *empty_to_null(const char *p) { + return isempty(p) ? NULL : p; +} + static inline char *startswith(const char *s, const char *prefix) { size_t l; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index d11756e615..fe8bb62752 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -479,8 +479,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_ if (r < 0) return r; - if (isempty(name)) - name = NULL; + name = empty_to_null(name); if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME])) return sd_bus_reply_method_return(m, NULL); @@ -499,9 +498,9 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_ if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - if (isempty(name)) { + if (isempty(name)) c->data[PROP_STATIC_HOSTNAME] = mfree(c->data[PROP_STATIC_HOSTNAME]); - } else { + else { char *h; if (!hostname_is_valid(name, false)) @@ -546,8 +545,7 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess if (r < 0) return r; - if (isempty(name)) - name = NULL; + name = empty_to_null(name); if (streq_ptr(name, c->data[prop])) return sd_bus_reply_method_return(m, NULL); @@ -570,9 +568,9 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - if (isempty(name)) { + if (isempty(name)) c->data[prop] = mfree(c->data[prop]); - } else { + else { char *h; /* The icon name might ultimately be used as file diff --git a/src/locale/localed.c b/src/locale/localed.c index 3b22a582ac..6af59fc830 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -97,10 +97,6 @@ typedef struct Context { Hashmap *polkit_registry; } Context; -static const char* nonempty(const char *s) { - return isempty(s) ? NULL : s; -} - static bool startswith_comma(const char *s, const char *prefix) { const char *t; @@ -171,8 +167,7 @@ static int locale_read_data(Context *c) { for (p = 0; p < _LOCALE_MAX; p++) { assert(names[p]); - r = free_and_strdup(&c->locale[p], - nonempty(getenv(names[p]))); + r = free_and_strdup(&c->locale[p], empty_to_null(getenv(names[p]))); if (r < 0) return r; } @@ -1041,11 +1036,8 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro if (r < 0) return r; - if (isempty(keymap)) - keymap = NULL; - - if (isempty(keymap_toggle)) - keymap_toggle = NULL; + keymap = empty_to_null(keymap); + keymap_toggle = empty_to_null(keymap_toggle); if (!streq_ptr(keymap, c->vc_keymap) || !streq_ptr(keymap_toggle, c->vc_keymap_toggle)) { @@ -1214,17 +1206,10 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err if (r < 0) return r; - if (isempty(layout)) - layout = NULL; - - if (isempty(model)) - model = NULL; - - if (isempty(variant)) - variant = NULL; - - if (isempty(options)) - options = NULL; + layout = empty_to_null(layout); + model = empty_to_null(model); + variant = empty_to_null(variant); + options = empty_to_null(options); if (!streq_ptr(layout, c->x11_layout) || !streq_ptr(model, c->x11_model) || diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 7b9aa66d63..de5d98f23e 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -655,8 +655,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu r = sd_bus_message_read(message, "ss", &user, &path); if (r < 0) return r; - if (isempty(user)) - user = NULL; + user = empty_to_null(user); if (isempty(path)) path = "/bin/sh"; if (!path_is_absolute(path)) diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 14ee01c49d..7e145c64c4 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -658,10 +658,8 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons assert(bus); assert(domain); - if (isempty(name)) - name = NULL; - if (isempty(type)) - type = NULL; + name = empty_to_null(name); + type = empty_to_null(type); if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname)) return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex); @@ -820,10 +818,8 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons if (r < 0) return bus_log_parse_error(r); - if (isempty(canonical_name)) - canonical_name = NULL; - if (isempty(canonical_type)) - canonical_type = NULL; + canonical_name = empty_to_null(canonical_name); + canonical_type = empty_to_null(canonical_type); if (!streq_ptr(name, canonical_name) || !streq_ptr(type, canonical_type) || diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 58255ae453..e0fde8aa73 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5177,9 +5177,7 @@ static int switch_root(int argc, char *argv[], void *userdata) { init = cmdline_init; } - if (isempty(init)) - init = NULL; - + init = empty_to_null(init); if (init) { const char *root_systemd_path = NULL, *root_init_path = NULL; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index fe4bbeeb75..6a90ca562b 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -527,9 +527,7 @@ static int load_sysv(SysvStub *s) { t[k-1] = 0; } - j = strstrip(t+12); - if (isempty(j)) - j = NULL; + j = empty_to_null(strstrip(t+12)); r = free_and_strdup(&chkconfig_description, j); if (r < 0) @@ -605,9 +603,7 @@ static int load_sysv(SysvStub *s) { state = LSB_DESCRIPTION; - j = strstrip(t+12); - if (isempty(j)) - j = NULL; + j = empty_to_null(strstrip(t+12)); r = free_and_strdup(&long_description, j); if (r < 0) @@ -618,9 +614,7 @@ static int load_sysv(SysvStub *s) { state = LSB; - j = strstrip(t+18); - if (isempty(j)) - j = NULL; + j = empty_to_null(strstrip(t+18)); r = free_and_strdup(&short_description, j); if (r < 0) -- cgit v1.2.3-54-g00ecf From 788d2b088b13a2444b9eb2ea82c0cc57d9f0980f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 18:06:04 +0200 Subject: sysv-generator: don't create Conflicts= deps towards shutdown.target anymore This is redundant as SysV services get DefaultDependencides=yes anyway, and thus conflict with shutdown.target anyway. Hence, let's simplify our code here. --- src/sysv-generator/sysv-generator.c | 64 ++++++------------------------------- 1 file changed, 9 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 6a90ca562b..4e12071e93 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -42,32 +42,19 @@ #include "unit-name.h" #include "util.h" -typedef enum RunlevelType { - RUNLEVEL_UP, - RUNLEVEL_DOWN -} RunlevelType; - static const struct { const char *path; const char *target; - const RunlevelType type; } rcnd_table[] = { /* Standard SysV runlevels for start-up */ - { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP }, - { "rc2.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP }, - { "rc3.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP }, - { "rc4.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP }, - { "rc5.d", SPECIAL_GRAPHICAL_TARGET, RUNLEVEL_UP }, - - /* Standard SysV runlevels for shutdown */ - { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN }, - { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN } - - /* Note that the order here matters, as we read the - directories in this order, and we want to make sure that - sysv_start_priority is known when we first load the - unit. And that value we only know from S links. Hence - UP must be read before DOWN */ + { "rc1.d", SPECIAL_RESCUE_TARGET }, + { "rc2.d", SPECIAL_MULTI_USER_TARGET }, + { "rc3.d", SPECIAL_MULTI_USER_TARGET }, + { "rc4.d", SPECIAL_MULTI_USER_TARGET }, + { "rc5.d", SPECIAL_GRAPHICAL_TARGET }, + + /* We ignore the SysV runlevels for shutdown here, as SysV services get default dependencies anyway, and that + * means they are shut down anyway at system power off if running. */ }; static const char *arg_dest = "/tmp"; @@ -82,7 +69,6 @@ typedef struct SysvStub { char **after; char **wants; char **wanted_by; - char **conflicts; bool has_lsb; bool reload; bool loaded; @@ -100,7 +86,6 @@ static void free_sysvstub(SysvStub *s) { strv_free(s->after); strv_free(s->wants); strv_free(s->wanted_by); - strv_free(s->conflicts); free(s); } @@ -199,8 +184,6 @@ static int generate_unit_file(SysvStub *s) { fprintf(f, "After=%s\n", *p); STRV_FOREACH(p, s->wants) fprintf(f, "Wants=%s\n", *p); - STRV_FOREACH(p, s->conflicts) - fprintf(f, "Conflicts=%s\n", *p); fprintf(f, "\n[Service]\n" @@ -835,7 +818,6 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; - _cleanup_set_free_ Set *shutdown_services = NULL; _cleanup_strv_free_ char **sysvrcnd_path = NULL; SysvStub *service; unsigned i; @@ -906,8 +888,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic if (de->d_name[0] == 'S') { - if (rcnd_table[i].type == RUNLEVEL_UP) - service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); + service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); r = set_ensure_allocated(&runlevel_services[i], NULL); if (r < 0) { @@ -921,20 +902,6 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic goto finish; } - } else if (de->d_name[0] == 'K' && - (rcnd_table[i].type == RUNLEVEL_DOWN)) { - - r = set_ensure_allocated(&shutdown_services, NULL); - if (r < 0) { - log_oom(); - goto finish; - } - - r = set_put(shutdown_services, service); - if (r < 0) { - log_oom(); - goto finish; - } } } } @@ -955,19 +922,6 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic } } - SET_FOREACH(service, shutdown_services, j) { - r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) { - log_oom(); - goto finish; - } - r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) { - log_oom(); - goto finish; - } - } - r = 0; finish: -- cgit v1.2.3-54-g00ecf From 54f8c958f1ebff12b961a1029a2aec451587c206 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 18:22:16 +0200 Subject: tree-wide: use ansi_highlight() instead of ANSI_HIGHLIGHT where appropriate Let's make sure SYSTEMD_COLORS is honour by more tools --- src/analyze/analyze.c | 8 ++++---- src/journal/journalctl.c | 13 +++++++++---- src/timedate/timedatectl.c | 14 +++++++------- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index d621f66aec..cbf9354a7a 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -758,9 +758,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne if (times) { if (times->time) - printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED, name, + printf("%s%s @%s +%s%s", ansi_highlight_red(), name, format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC), - format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_NORMAL); + format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal()); else if (times->activated > boot->userspace_time) printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); else @@ -926,8 +926,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { if (times) { if (times->time) - printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED, id, - format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_NORMAL); + printf("%s%s +%s%s\n", ansi_highlight_red(), id, + format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ansi_normal()); else if (times->activated > boot->userspace_time) printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); else diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index f67c556783..8e4897831b 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1664,15 +1664,19 @@ static int setup_keys(void) { if (on_tty()) { fprintf(stderr, "\n" - "The new key pair has been generated. The " ANSI_HIGHLIGHT "secret sealing key" ANSI_NORMAL " has been written to\n" + "The new key pair has been generated. The %ssecret sealing key%s has been written to\n" "the following local file. This key file is automatically updated when the\n" "sealing key is advanced. It should not be used on multiple hosts.\n" "\n" "\t%s\n" "\n" - "Please write down the following " ANSI_HIGHLIGHT "secret verification key" ANSI_NORMAL ". It should be stored\n" + "Please write down the following %ssecret verification key%s. It should be stored\n" "at a safe location and should not be saved locally on disk.\n" - "\n\t" ANSI_HIGHLIGHT_RED, p); + "\n\t%s", + ansi_highlight(), ansi_normal(), + ansi_highlight(), ansi_normal(), + ansi_highlight_red(), + p); fflush(stderr); } for (i = 0; i < seed_size; i++) { @@ -1687,8 +1691,9 @@ static int setup_keys(void) { char tsb[FORMAT_TIMESPAN_MAX], *hn; fprintf(stderr, - ANSI_NORMAL "\n" + "%s\n" "The sealing key is automatically changed every %s.\n", + ansi_normal(), format_timespan(tsb, sizeof(tsb), arg_interval, 0)); hn = gethostname_malloc(); diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index a2270aff46..b7871f81aa 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -144,13 +144,13 @@ static void print_status_info(const StatusInfo *i) { yes_no(i->rtc_local)); if (i->rtc_local) - fputs("\n" ANSI_HIGHLIGHT - "Warning: The system is configured to read the RTC time in the local time zone.\n" - " This mode can not be fully supported. It will create various problems\n" - " with time zone changes and daylight saving time adjustments. The RTC\n" - " time is never updated, it relies on external facilities to maintain it.\n" - " If at all possible, use RTC in UTC by calling\n" - " 'timedatectl set-local-rtc 0'." ANSI_NORMAL "\n", stdout); + printf("\n%s" + "Warning: The system is configured to read the RTC time in the local time zone.\n" + " This mode can not be fully supported. It will create various problems\n" + " with time zone changes and daylight saving time adjustments. The RTC\n" + " time is never updated, it relies on external facilities to maintain it.\n" + " If at all possible, use RTC in UTC by calling\n" + " 'timedatectl set-local-rtc 0'.%s\n", ansi_highlight(), ansi_normal()); } static int show_status(sd_bus *bus, char **args, unsigned n) { -- cgit v1.2.3-54-g00ecf From 7565bb98a45c51c7a79cbeda9905e5364c49e374 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 18:23:08 +0200 Subject: tree-wide: check colors_enabled() before outputting ANSI color strings --- src/basic/terminal-util.c | 8 ++++---- src/journal/journal-verify.c | 9 +++++++-- src/shared/ask-password-api.c | 6 ++++-- 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 3189b8789d..2b90f2e5a1 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -155,14 +155,14 @@ int ask_char(char *ret, const char *replies, const char *text, ...) { char c; bool need_nl = true; - if (on_tty()) + if (colors_enabled()) fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (on_tty()) + if (colors_enabled()) fputs(ANSI_NORMAL, stdout); fflush(stdout); @@ -199,14 +199,14 @@ int ask_string(char **ret, const char *text, ...) { char line[LINE_MAX]; va_list ap; - if (on_tty()) + if (colors_enabled()) fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (on_tty()) + if (colors_enabled()) fputs(ANSI_NORMAL, stdout); fflush(stdout); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 26572ddd76..a37316b8f9 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -54,7 +54,9 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { j = (n * (unsigned) p) / 65535ULL; k = n - j; - fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout); + fputs("\r", stdout); + if (colors_enabled()) + fputs("\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout); for (i = 0; i < j; i++) fputs("\xe2\x96\x88", stdout); @@ -66,7 +68,10 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { printf(" %3"PRIu64"%%", 100U * p / 65535U); - fputs("\r\x1B[?25h", stdout); + fputs("\r", stdout); + if (colors_enabled()) + fputs("\x1B[?25h", stdout); + fflush(stdout); } diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 4a4bd8d3b8..a86b0db554 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -253,10 +253,12 @@ int ask_password_tty( goto finish; } - loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false); + if (colors_enabled()) + loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false); loop_write(ttyfd, message, strlen(message), false); loop_write(ttyfd, " ", 1, false); - loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false); + if (colors_enabled()) + loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false); new_termios = old_termios; new_termios.c_lflag &= ~(ICANON|ECHO); -- cgit v1.2.3-54-g00ecf From ac96418b4f16c2a0acd2e4981e533c00fe21bdf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 18:23:54 +0200 Subject: pager: don't start pager if the terminal is explicitly set to TERM=dumb As suggested here: https://bugs.freedesktop.org/show_bug.cgi?id=64737#c8 This adds a new call terminal_is_dumb() and makes use of this where appropriate. --- src/basic/terminal-util.c | 17 ++++++++++++++--- src/basic/terminal-util.h | 1 + src/cgtop/cgtop.c | 2 +- src/shared/pager.c | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 2b90f2e5a1..d8cca55378 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1193,6 +1193,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { return receive_one_fd(pair[0], 0); } +bool terminal_is_dumb(void) { + const char *e; + + if (!on_tty()) + return true; + + e = getenv("TERM"); + if (!e) + return true; + + return streq(e, "dumb"); +} + bool colors_enabled(void) { static int enabled = -1; @@ -1202,10 +1215,8 @@ bool colors_enabled(void) { colors = getenv("SYSTEMD_COLORS"); if (colors) enabled = parse_boolean(colors) != 0; - else if (streq_ptr(getenv("TERM"), "dumb")) - enabled = false; else - enabled = on_tty(); + enabled = !terminal_is_dumb(); } return enabled; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index b449370974..169ab772ff 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -80,6 +80,7 @@ unsigned lines(void); void columns_lines_cache_reset(int _unused_ signum); bool on_tty(void); +bool terminal_is_dumb(void); bool colors_enabled(void); static inline const char *ansi_underline(void) { diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index e088e4b197..33379eb9bd 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -558,7 +558,7 @@ static void display(Hashmap *a) { assert(a); - if (on_tty()) + if (!terminal_is_dumb()) fputs(ANSI_HOME_CLEAR, stdout); array = alloca(sizeof(Group*) * hashmap_size(a)); diff --git a/src/shared/pager.c b/src/shared/pager.c index c16bc027be..a2524d4420 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -63,7 +63,7 @@ int pager_open(bool no_pager, bool jump_to_end) { if (pager_pid > 0) return 1; - if (!on_tty()) + if (terminal_is_dumb()) return 0; pager = getenv("SYSTEMD_PAGER"); -- cgit v1.2.3-54-g00ecf From 76a9d0f1713a39471ea6c85e982fb0b447ef1315 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 18:28:51 +0200 Subject: dhcp-server: fix integer underflow Let's better ignore an invalid message size parameter, than assume ridiculously larger sizes. --- src/libsystemd-network/sd-dhcp-server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index a1af5da40f..ea4f03df1d 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -633,7 +633,8 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us break; case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE: - if (len == 2) + + if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket)) req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket); break; -- cgit v1.2.3-54-g00ecf From aa31ce181268bb577f58684ca3ef342700000ddf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 31 May 2016 13:00:54 +0200 Subject: network: fix wrong include of source file "ether-addr-util.c" (#3402) Fixes: 9ed8b06c9be4a5efae432d5cf4b1c47d03e6f107 --- src/libsystemd-network/network-internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 046b0f9393..bfaa75880b 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -27,7 +27,7 @@ #include "condition.h" #include "conf-parser.h" #include "dhcp-lease-internal.h" -#include "ether-addr-util.c" +#include "ether-addr-util.h" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" -- cgit v1.2.3-54-g00ecf From b613907ea988e2994c68be686b5e92cdc7d3fb68 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 31 May 2016 19:06:58 +0530 Subject: systemctl: Replace init script error codes with enum (#3400) Now we just using constants for the init script exit status codes. Replace those error codes with enum so that it's more meaningful and readable. --- src/systemctl/systemctl.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 58255ae453..e4b4e07ee7 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -85,6 +85,25 @@ #include "verbs.h" #include "virt.h" +/* The init script exit status codes + 0 program is running or service is OK + 1 program is dead and /var/run pid file exists + 2 program is dead and /var/lock lock file exists + 3 program is not running + 4 program or service status is unknown + 5-99 reserved for future LSB use + 100-149 reserved for distribution use + 150-199 reserved for application use + 200-254 reserved +*/ +enum { + EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0, + EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1, + EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2, + EXIT_PROGRAM_NOT_RUNNING = 3, + EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, +}; + static char **arg_types = NULL; static char **arg_states = NULL; static char **arg_properties = NULL; @@ -3291,12 +3310,12 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int static int check_unit_active(int argc, char *argv[], void *userdata) { const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING }; /* According to LSB: 3, "program is not running" */ - return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1)); + return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int check_unit_failed(int argc, char *argv[], void *userdata) { const UnitActiveState states[] = { UNIT_FAILED }; - return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1)); + return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int kill_unit(int argc, char *argv[], void *userdata) { @@ -4632,11 +4651,11 @@ static int show_one( * 4: program or service status is unknown */ if (info.pid_file && access(info.pid_file, F_OK) == 0) - r = 1; + r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) - r = 4; + r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; else - r = 3; + r = EXIT_PROGRAM_NOT_RUNNING; } while ((p = info.exec)) { -- cgit v1.2.3-54-g00ecf From e33a06a1eb7406ece8e35f6346ba0ea208c11cf1 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 31 May 2016 21:50:25 +0530 Subject: systemctl: systemctl show --property' needs verification of property (#3364) systemctl --property doesn't validate if a requested property is valid or not, and always returns with an exit code of 0, regardless of whether the requested property exists or not. How reproducible: This works fine: Id=multi-user.target But put in a non-existing property: Id=default.targets.service Id=default.targets.service 0 [root@shou18lkvm8 ~]# systemctl show --property Id this.is.rubbish; echo $? Id=this.is.rubbish.service 0 After: sus@maximus bz-95593]$ ./systemctl show --property Id this.is.rubbish; echo $? Can't display property this.is.rubbish. Unit this.is.rubbish.service does not exist. 4 fixes #2295 --- src/systemctl/systemctl.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e4b4e07ee7..e8f487e9f4 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4561,6 +4561,14 @@ static int show_one( .tasks_current = (uint64_t) -1, .tasks_max = (uint64_t) -1, }; + struct property_info { + const char *load_state, *active_state; + } property_info = {}; + static const struct bus_properties_map property_map[] = { + { "LoadState", "s", NULL, offsetof(struct property_info, load_state) }, + { "ActiveState", "s", NULL, offsetof(struct property_info, active_state) }, + {} + }; ExecStatusInfo *p; int r; @@ -4581,6 +4589,17 @@ static int show_one( if (r < 0) return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); + r = bus_message_map_all_properties(reply, property_map, &property_info); + if (r < 0) + return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); + + if (streq_ptr(property_info.load_state, "not-found") && streq_ptr(property_info.active_state, "inactive")) + return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + + r = sd_bus_message_rewind(reply, true); + if (r < 0) + return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); if (r < 0) return bus_log_parse_error(r); @@ -4889,6 +4908,9 @@ static int show(int argc, char *argv[], void *userdata) { return r; else if (r > 0 && ret == 0) ret = r; + + if (r == EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN) + log_error("Can't display property %s. Unit %s does not exist.", *patterns, *name); } } } -- cgit v1.2.3-54-g00ecf From 720bec40e94a65d7a63a0091773b2bab2934ee41 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Wed, 1 Jun 2016 14:54:46 +0800 Subject: networkd-dhcp6: generalize DHCPv6 client (re)starting dhcp6_request_address() was merely a function to switch the DHCPv6 client from "stateless" mode to "stateful" mode. It was also a one-way switch. Also, to (re)start the client, we would need to repeat separate function calls. In this patch, dhcp6_request_address() is made a general starter/manager of the DHCPv6 client. It now takes an extra parameter so we will be specifying which mode the DHCPv6 client should be started in. Also it will keep track of the current mode and compare with the newly requested mode, and only restart the client in case there is a difference between them. This also makes sure that the DHCPv6 client will be (re)started accordingly as per the Router Advertisement flags. --- src/network/networkd-dhcp6.c | 31 ++++++++++++++++++------------- src/network/networkd-link.c | 11 ++++------- src/network/networkd-link.h | 2 +- src/network/networkd-ndisc.c | 31 ++++++++++++++----------------- 4 files changed, 37 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index a44c9ea71d..50721b1c74 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -164,19 +164,13 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { link_check_ready(link); } -int dhcp6_request_address(Link *link) { +int dhcp6_request_address(Link *link, int ir) { int r, inf_req; bool running; assert(link); assert(link->dhcp6_client); - - r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req); - if (r < 0) - return r; - - if (!inf_req) - return 0; + assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); r = sd_dhcp6_client_is_running(link->dhcp6_client); if (r < 0) @@ -185,12 +179,27 @@ int dhcp6_request_address(Link *link) { running = !!r; if (running) { + r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req); + if (r < 0) + return r; + + if (inf_req == ir) + return 0; + r = sd_dhcp6_client_stop(link->dhcp6_client); if (r < 0) return r; + } else { + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0) + return r; } - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false); + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, ir); + if (r < 0) + return r; + + r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0) return r; @@ -215,10 +224,6 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - r = sd_dhcp6_client_set_information_request(client, true); - if (r < 0) - goto error; - r = sd_dhcp6_client_set_mac(client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9ac0b47d77..ba4147f875 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1444,15 +1444,12 @@ static int link_acquire_ipv6_conf(Link *link) { assert(link->dhcp6_client); assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); - log_link_debug(link, "Acquiring DHCPv6 lease"); - - r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); - if (r < 0 && r != -EBUSY) - return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); - - r = sd_dhcp6_client_start(link->dhcp6_client); + /* start DHCPv6 client in stateless mode */ + r = dhcp6_request_address(link, true); if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m"); + else + log_link_debug(link, "Acquiring DHCPv6 lease"); } if (link_ipv6_accept_ra_enabled(link)) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 14c4a02c7e..5efefd27d6 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -160,7 +160,7 @@ int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); int dhcp6_configure(Link *link); -int dhcp6_request_address(Link *link); +int dhcp6_request_address(Link *link, int ir); int ndisc_configure(Link *link); const char* link_state_to_string(LinkState s) _const_; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 3baca2e63c..db9be024e5 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -149,21 +149,19 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a assert(link); assert(link->network); assert(link->manager); + assert(link->dhcp6_client); + assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return; if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { - if (flags & ND_RA_FLAG_MANAGED) - dhcp6_request_address(link); - - r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); - if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); - - r = sd_dhcp6_client_start(link->dhcp6_client); + /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */ + r = dhcp6_request_address(link, flags & ND_RA_FLAG_MANAGED ? false : true); if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m"); + log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); + else + log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); } if (!gateway) @@ -199,21 +197,20 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { int r; assert(link); + assert(link->dhcp6_client); + assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return; switch (event) { case SD_NDISC_EVENT_TIMEOUT: - dhcp6_request_address(link); - - r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); - if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); - - r = sd_dhcp6_client_start(link->dhcp6_client); + /* (re)start DHCPv6 client in stateful mode */ + r = dhcp6_request_address(link, false); if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m"); + log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease after NDisc timeout: %m"); + else + log_link_debug(link, "Acquiring DHCPv6 lease after NDisc timeout"); link->ndisc_configured = true; link_check_ready(link); -- cgit v1.2.3-54-g00ecf From 201c1cc22a41df1f4ef7706bde41e2536bef433f Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Wed, 1 Jun 2016 09:56:01 +0000 Subject: core: add pre-defined syscall groups to SystemCallFilter= (#3053) (#3157) Implement sets of system calls to help constructing system call filters. A set starts with '@' to distinguish from a system call. Closes: #3053, #3157 --- man/systemd.exec.xml | 73 +++++++++++++++- src/core/load-fragment.c | 95 +++++++++++--------- src/shared/seccomp-util.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/seccomp-util.h | 7 ++ 4 files changed, 350 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4d52982b64..58f18f3a9e 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1193,7 +1193,78 @@ read and write, and right after it add a blacklisting of write, then write - will be removed from the set.) + will be removed from the set.) + + As the number of possible system + calls is large, predefined sets of system calls are provided. + A set starts with @ character, followed by + name of the set. + + + Currently predefined system call sets + + + + + + + Set + Description + + + + + @clock + System calls for changing the system clock (adjtimex(), + settimeofday()) + + + @io-event + Event loop use (poll(), select(), + epoll7, + eventfd()...) + + + @ipc + SysV IPC, POSIX Message Queues or other IPC (mq_overview7, + svipc7) + + + @module + Kernel module control (create_module(), init_module()...) + + + @mount + File system mounting and unmounting (chroot(), mount()...) + + + @network-io + Socket I/O (including local AF_UNIX): + socket7, + unix7 + + + @obsolete + Unusual, obsolete or unimplemented (fattach(), gtty(), vm86()...) + + + @privileged + All system calls which need superuser capabilities (capabilities7) + + + @process + Process control, execution, namespaces (execve(), kill(), namespaces7...) + + + @raw-io + Raw I/O ports (ioperm(), iopl(), pciconfig_read()...) + + + +
+ + Note, that as new system calls are added to the kernel, additional system calls might be added to the groups + above, so the contents of the sets may change between systemd versions.
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 09d3f65c77..50ff718aab 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2396,6 +2396,55 @@ int config_parse_documentation(const char *unit, } #ifdef HAVE_SECCOMP +static int syscall_filter_parse_one( + const char *unit, + const char *filename, + unsigned line, + ExecContext *c, + bool invert, + const char *t, + bool warn) { + int r; + + if (*t == '@') { + const SystemCallFilterSet *set; + + for (set = syscall_filter_sets; set->set_name; set++) + if (streq(set->set_name, t)) { + const char *sys; + + NULSTR_FOREACH(sys, set->value) { + r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false); + if (r < 0) + return r; + } + break; + } + } else { + int id; + + id = seccomp_syscall_resolve_name(t); + if (id < 0) { + if (warn) + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); + return 0; + } + + /* If we previously wanted to forbid a syscall and now + * we want to allow it, then remove it from the list + */ + if (!invert == c->syscall_whitelist) { + r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); + if (r == 0) + return 0; + if (r < 0) + return log_oom(); + } else + set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + } + return 0; +} + int config_parse_syscall_filter( const char *unit, const char *filename, @@ -2408,13 +2457,6 @@ int config_parse_syscall_filter( void *data, void *userdata) { - static const char default_syscalls[] = - "execve\0" - "exit\0" - "exit_group\0" - "rt_sigreturn\0" - "sigreturn\0"; - ExecContext *c = data; Unit *u = userdata; bool invert = false; @@ -2448,53 +2490,26 @@ int config_parse_syscall_filter( /* Allow everything but the ones listed */ c->syscall_whitelist = false; else { - const char *i; - /* Allow nothing but the ones listed */ c->syscall_whitelist = true; /* Accept default syscalls if we are on a whitelist */ - NULSTR_FOREACH(i, default_syscalls) { - int id; - - id = seccomp_syscall_resolve_name(i); - if (id < 0) - continue; - - r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); - if (r == 0) - continue; - if (r < 0) - return log_oom(); - } + r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false); + if (r < 0) + return r; } } FOREACH_WORD_QUOTED(word, l, rvalue, state) { _cleanup_free_ char *t = NULL; - int id; t = strndup(word, l); if (!t) return log_oom(); - id = seccomp_syscall_resolve_name(t); - if (id < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); - continue; - } - - /* If we previously wanted to forbid a syscall and now - * we want to allow it, then remove it from the list - */ - if (!invert == c->syscall_whitelist) { - r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); - if (r == 0) - continue; - if (r < 0) - return log_oom(); - } else - set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true); + if (r < 0) + return r; } if (!isempty(state)) log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index cebe0fce2a..30d22d2242 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -88,3 +88,219 @@ int seccomp_add_secondary_archs(scmp_filter_ctx *c) { return 0; } + +const SystemCallFilterSet syscall_filter_sets[] = { + { + /* Clock */ + .set_name = "@clock", + .value = + "adjtimex\0" + "settimeofday\0" + }, { + /* Default list */ + .set_name = "@default", + .value = + "execve\0" + "exit\0" + "exit_group\0" + "rt_sigreturn\0" + "sigreturn\0" + }, { + /* Event loop use */ + .set_name = "@io-event", + .value = + "_newselect\0" + "epoll_create1\0" + "epoll_create\0" + "epoll_ctl\0" + "epoll_ctl_old\0" + "epoll_pwait\0" + "epoll_wait\0" + "epoll_wait_old\0" + "eventfd2\0" + "eventfd\0" + "poll\0" + "ppoll\0" + "pselect6\0" + "select\0" + }, { + /* Message queues, SYSV IPC or other IPC: unusual */ + .set_name = "@ipc", + .value = "ipc\0" + "mq_getsetattr\0" + "mq_notify\0" + "mq_open\0" + "mq_timedreceive\0" + "mq_timedsend\0" + "mq_unlink\0" + "msgctl\0" + "msgget\0" + "msgrcv\0" + "msgsnd\0" + "process_vm_readv\0" + "process_vm_writev\0" + "semctl\0" + "semget\0" + "semop\0" + "semtimedop\0" + "shmat\0" + "shmctl\0" + "shmdt\0" + "shmget\0" + }, { + /* Kernel module control */ + .set_name = "@module", + .value = + "create_module\0" + "delete_module\0" + "finit_module\0" + "init_module\0" + }, { + /* Mounting */ + .set_name = "@mount", + .value = + "chroot\0" + "mount\0" + "oldumount\0" + "pivot_root\0" + "umount2\0" + "umount\0" + }, { + /* Network or Unix socket IO, should not be needed if not network facing */ + .set_name = "@network-io", + .value = + "accept4\0" + "accept\0" + "bind\0" + "connect\0" + "getpeername\0" + "getsockname\0" + "getsockopt\0" + "listen\0" + "recv\0" + "recvfrom\0" + "recvmmsg\0" + "recvmsg\0" + "send\0" + "sendmmsg\0" + "sendmsg\0" + "sendto\0" + "setsockopt\0" + "shutdown\0" + "socket\0" + "socketcall\0" + "socketpair\0" + }, { + /* Unusual, obsolete or unimplemented, some unknown even to libseccomp */ + .set_name = "@obsolete", + .value = + "_sysctl\0" + "afs_syscall\0" + "break\0" + "fattach\0" + "fdetach\0" + "ftime\0" + "get_kernel_syms\0" + "get_mempolicy\0" + "getmsg\0" + "getpmsg\0" + "gtty\0" + "isastream\0" + "lock\0" + "madvise1\0" + "modify_ldt\0" + "mpx\0" + "pciconfig_iobase\0" + "perf_event_open\0" + "prof\0" + "profil\0" + "putmsg\0" + "putpmsg\0" + "query_module\0" + "rtas\0" + "s390_runtime_instr\0" + "security\0" + "sgetmask\0" + "ssetmask\0" + "stty\0" + "subpage_prot\0" + "switch_endian\0" + "sys_debug_setcontext\0" + "tuxcall\0" + "ulimit\0" + "uselib\0" + "vm86\0" + "vm86old\0" + "vserver\0" + }, { + /* Nice grab-bag of all system calls which need superuser capabilities */ + .set_name = "@privileged", + .value = + "@clock\0" + "@module\0" + "@raw-io\0" + "acct\0" + "bdflush\0" + "bpf\0" + "chown32\0" + "chown\0" + "chroot\0" + "fchown32\0" + "fchown\0" + "fchownat\0" + "kexec_file_load\0" + "kexec_load\0" + "lchown32\0" + "lchown\0" + "nfsservctl\0" + "pivot_root\0" + "quotactl\0" + "reboot\0" + "setdomainname\0" + "setfsuid32\0" + "setfsuid\0" + "setgroups32\0" + "setgroups\0" + "sethostname\0" + "setresuid32\0" + "setresuid\0" + "setreuid32\0" + "setreuid\0" + "setuid32\0" + "setuid\0" + "stime\0" + "swapoff\0" + "swapon\0" + "sysctl\0" + "vhangup\0" + }, { + /* Process control, execution, namespaces */ + .set_name = "@process", + .value = + "arch_prctl\0" + "clone\0" + "execve\0" + "execveat\0" + "fork\0" + "kill\0" + "prctl\0" + "setns\0" + "tgkill\0" + "tkill\0" + "unshare\0" + "vfork\0" + }, { + /* Raw I/O ports */ + .set_name = "@raw-io", + .value = + "ioperm\0" + "iopl\0" + "pciconfig_read\0" + "pciconfig_write\0" + "s390_pci_mmio_read\0" + "s390_pci_mmio_write\0" + }, { + .set_name = NULL, + .value = NULL + } +}; diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 4ed2afc1b2..be33eecb85 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -26,3 +26,10 @@ const char* seccomp_arch_to_string(uint32_t c); int seccomp_arch_from_string(const char *n, uint32_t *ret); int seccomp_add_secondary_archs(scmp_filter_ctx *c); + +typedef struct SystemCallFilterSet { + const char *set_name; + const char *value; +} SystemCallFilterSet; + +extern const SystemCallFilterSet syscall_filter_sets[]; -- cgit v1.2.3-54-g00ecf From acac5b2f512e03830df06df3fc30aff28d01d6b3 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Thu, 2 Jun 2016 01:05:50 +0800 Subject: networkd-ndisc: do not start DHCPv6 when after NDISC timeout For it's silly and unnecessary. Although it was apparently mandated by RFC 2462 in [5.5.2. Absence of Router Advertisements], that has been changed in the same section of RFC 4862, which obsoleted the former RFC. --- src/network/networkd-ndisc.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index db9be024e5..7359cc2b67 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -197,21 +197,12 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { int r; assert(link); - assert(link->dhcp6_client); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return; switch (event) { case SD_NDISC_EVENT_TIMEOUT: - /* (re)start DHCPv6 client in stateful mode */ - r = dhcp6_request_address(link, false); - if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease after NDisc timeout: %m"); - else - log_link_debug(link, "Acquiring DHCPv6 lease after NDisc timeout"); - link->ndisc_configured = true; link_check_ready(link); -- cgit v1.2.3-54-g00ecf From f29ff1159cf40c59d3611e02356985c791830795 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Jun 2016 13:02:49 -0400 Subject: core: pass Unit into cgroup_context_apply() and use log_unit*() cgroup_context_apply() and friends take CGroupContext and cgroup path as input and has no way of getting back to the associated Unit and thus uses raw cgroup path for logging. This makes the log messages difficult to track down. There's no reason to avoid passing in Unit into these functions. Pass in Unit and use log_unit*() instead. While at it, make cgroup_context_apply(), which has no outside users, static. Also, drop cgroup path from log messages where the path itself isn't too interesting and can be easily obtained from the unit. --- src/core/cgroup.c | 115 +++++++++++++++++++++++++++++------------------------- src/core/cgroup.h | 1 - 2 files changed, 61 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index fbe69df4e9..d1fb405e9a 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -413,7 +413,7 @@ static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) { CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX); } -static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) { +static void cgroup_apply_io_device_weight(Unit *u, const char *dev_path, uint64_t io_weight) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; int r; @@ -423,13 +423,13 @@ static void cgroup_apply_io_device_weight(const char *path, const char *dev_path return; xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight); - r = cg_set_attribute("io", path, "io.weight", buf); + r = cg_set_attribute("io", u->cgroup_path, "io.weight", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set io.weight on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight: %m"); } -static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) { +static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint64_t blkio_weight) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; int r; @@ -439,13 +439,13 @@ static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_p return; xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight); - r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); + r = cg_set_attribute("blkio", u->cgroup_path, "blkio.weight_device", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.weight_device on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.weight_device: %m"); } -static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) { +static unsigned cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) { char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4]; CGroupIOLimitType type; @@ -469,14 +469,14 @@ static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_p xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev), limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX], limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]); - r = cg_set_attribute("io", path, "io.max", buf); + r = cg_set_attribute("io", u->cgroup_path, "io.max", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set io.max on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.max: %m"); return n; } -static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) { +static unsigned cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint64_t rbps, uint64_t wbps) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; unsigned n = 0; @@ -489,18 +489,18 @@ static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *de if (rbps != CGROUP_LIMIT_MAX) n++; sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps); - r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf); + r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.read_bps_device", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.throttle.read_bps_device on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.throttle.read_bps_device: %m"); if (wbps != CGROUP_LIMIT_MAX) n++; sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps); - r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf); + r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.write_bps_device", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.throttle.write_bps_device on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.throttle.write_bps_device: %m"); return n; } @@ -509,23 +509,30 @@ static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX; } -static void cgroup_apply_unified_memory_limit(const char *path, const char *file, uint64_t v) { +static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) { char buf[DECIMAL_STR_MAX(uint64_t) + 1] = "max"; int r; if (v != CGROUP_LIMIT_MAX) xsprintf(buf, "%" PRIu64 "\n", v); - r = cg_set_attribute("memory", path, file, buf); + r = cg_set_attribute("memory", u->cgroup_path, file, buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set %s on %s: %m", file, path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set %s: %m", file); } -void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) { +static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { + const char *path; + CGroupContext *c; bool is_root; int r; + assert(u); + + c = unit_get_cgroup_context(u); + path = u->cgroup_path; + assert(c); assert(path); @@ -551,14 +558,14 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT); r = cg_set_attribute("cpu", path, "cpu.shares", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set cpu.shares on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set cpu.shares: %m"); sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC); r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set cpu.cfs_period_us on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set cpu.cfs_period_us: %m"); if (c->cpu_quota_per_sec_usec != USEC_INFINITY) { sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC); @@ -566,8 +573,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } else r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set cpu.cfs_quota_us on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set cpu.cfs_quota_us: %m"); } if (mask & CGROUP_MASK_IO) { @@ -588,21 +595,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M xsprintf(buf, "default %" PRIu64 "\n", weight); r = cg_set_attribute("io", path, "io.weight", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set io.weight on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight: %m"); if (has_io) { CGroupIODeviceWeight *w; /* FIXME: no way to reset this list */ LIST_FOREACH(device_weights, w, c->io_device_weights) - cgroup_apply_io_device_weight(path, w->path, w->weight); + cgroup_apply_io_device_weight(u, w->path, w->weight); } else if (has_blockio) { CGroupBlockIODeviceWeight *w; /* FIXME: no way to reset this list */ LIST_FOREACH(device_weights, w, c->blockio_device_weights) - cgroup_apply_io_device_weight(path, w->path, cgroup_weight_blkio_to_io(w->weight)); + cgroup_apply_io_device_weight(u, w->path, cgroup_weight_blkio_to_io(w->weight)); } } @@ -611,7 +618,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M CGroupIODeviceLimit *l, *next; LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { - if (!cgroup_apply_io_device_limit(path, l->path, l->limits)) + if (!cgroup_apply_io_device_limit(u, l->path, l->limits)) cgroup_context_free_io_device_limit(c, l); } } else if (has_blockio) { @@ -627,7 +634,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M limits[CGROUP_IO_RBPS_MAX] = b->rbps; limits[CGROUP_IO_WBPS_MAX] = b->wbps; - if (!cgroup_apply_io_device_limit(path, b->path, limits)) + if (!cgroup_apply_io_device_limit(u, b->path, limits)) cgroup_context_free_blockio_device_bandwidth(c, b); } } @@ -651,21 +658,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M xsprintf(buf, "%" PRIu64 "\n", weight); r = cg_set_attribute("blkio", path, "blkio.weight", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.weight on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.weight: %m"); if (has_blockio) { CGroupBlockIODeviceWeight *w; /* FIXME: no way to reset this list */ LIST_FOREACH(device_weights, w, c->blockio_device_weights) - cgroup_apply_blkio_device_weight(path, w->path, w->weight); + cgroup_apply_blkio_device_weight(u, w->path, w->weight); } else if (has_io) { CGroupIODeviceWeight *w; /* FIXME: no way to reset this list */ LIST_FOREACH(device_weights, w, c->io_device_weights) - cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight)); + cgroup_apply_blkio_device_weight(u, w->path, cgroup_weight_io_to_blkio(w->weight)); } } @@ -674,14 +681,14 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M CGroupBlockIODeviceBandwidth *b, *next; LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { - if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps)) + if (!cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps)) cgroup_context_free_blockio_device_bandwidth(c, b); } } else if (has_io) { CGroupIODeviceLimit *l, *next; LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { - if (!cgroup_apply_blkio_device_limit(path, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX])) + if (!cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX])) cgroup_context_free_io_device_limit(c, l); } } @@ -696,9 +703,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M else max = c->memory_limit; - cgroup_apply_unified_memory_limit(path, "memory.low", c->memory_low); - cgroup_apply_unified_memory_limit(path, "memory.high", c->memory_high); - cgroup_apply_unified_memory_limit(path, "memory.max", max); + cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low); + cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); + cgroup_apply_unified_memory_limit(u, "memory.max", max); } else { char buf[DECIMAL_STR_MAX(uint64_t) + 1]; @@ -709,8 +716,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set memory.limit_in_bytes on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set memory.limit_in_bytes: %m"); } } @@ -726,8 +733,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M else r = cg_set_attribute("devices", path, "devices.allow", "a"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to reset devices.list on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to reset devices.list: %m"); if (c->device_policy == CGROUP_CLOSED || (c->device_policy == CGROUP_AUTO && c->device_allow)) { @@ -773,7 +780,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M else if (startswith(a->path, "char-")) whitelist_major(path, a->path + 5, 'c', acc); else - log_debug("Ignoring device %s while writing cgroup attribute.", a->path); + log_unit_debug(u, "Ignoring device %s while writing cgroup attribute.", a->path); } } @@ -788,8 +795,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M r = cg_set_attribute("pids", path, "pids.max", "max"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set pids.max on %s: %m", path); + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set pids.max: %m"); } } @@ -1224,7 +1231,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) { return r; /* Finally, apply the necessary attributes. */ - cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state); + cgroup_context_apply(u, target_mask, state); return 0; } @@ -1355,7 +1362,7 @@ void unit_prune_cgroup(Unit *u) { r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice); if (r < 0) { - log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path); + log_unit_debug_errno(u, r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path); return; } diff --git a/src/core/cgroup.h b/src/core/cgroup.h index ff87adfba1..f21409bd5d 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -125,7 +125,6 @@ struct CGroupContext { void cgroup_context_init(CGroupContext *c); void cgroup_context_done(CGroupContext *c); void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix); -void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state); CGroupMask cgroup_context_get_mask(CGroupContext *c); -- cgit v1.2.3-54-g00ecf From 128fadc927b6662671c091e2b25ba6517080e7e7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Jun 2016 13:02:53 -0400 Subject: core: log cgroup legacy and unified hierarchy setting translations To accommodate changes in kernel interface, cgroup unified hierarchy support added several configuration items which overlap with the existing resource control settings and there is simple config translation between the overlapping settings to ease the transition. As why certain cgroup knobs are being configured can become confusing, this patch adds a master warning message which is printed once when such translation is first used and logs each translation with a debug message. v2: - Switched to log_unit*(). --- src/core/cgroup.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index d1fb405e9a..f3e0c54b76 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -36,6 +36,22 @@ #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC) +static void cgroup_compat_warn(void) +{ + static bool cgroup_compat_warned = false; + + if (cgroup_compat_warned) + return; + + log_warning("cgroup compatibility translation between legacy and unified hierarchy settings activated. See cgroup-compat debug messages for details."); + cgroup_compat_warned = true; +} + +#define log_cgroup_compat(unit, fmt, ...) do { \ + cgroup_compat_warn(); \ + log_unit_debug(unit, "cgroup-compat: " fmt, ##__VA_ARGS__); \ + } while (0) + void cgroup_context_init(CGroupContext *c) { assert(c); @@ -587,9 +603,14 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { if (has_io) weight = cgroup_context_io_weight(c, state); - else if (has_blockio) - weight = cgroup_weight_blkio_to_io(cgroup_context_blkio_weight(c, state)); - else + else if (has_blockio) { + uint64_t blkio_weight = cgroup_context_blkio_weight(c, state); + + weight = cgroup_weight_blkio_to_io(blkio_weight); + + log_cgroup_compat(u, "Applying [Startup]BlockIOWeight %" PRIu64 " as [Startup]IOWeight %" PRIu64, + blkio_weight, weight); + } else weight = CGROUP_WEIGHT_DEFAULT; xsprintf(buf, "default %" PRIu64 "\n", weight); @@ -608,8 +629,14 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { CGroupBlockIODeviceWeight *w; /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->blockio_device_weights) - cgroup_apply_io_device_weight(u, w->path, cgroup_weight_blkio_to_io(w->weight)); + LIST_FOREACH(device_weights, w, c->blockio_device_weights) { + weight = cgroup_weight_blkio_to_io(w->weight); + + log_cgroup_compat(u, "Applying BlockIODeviceWeight %" PRIu64 " as IODeviceWeight %" PRIu64 " for %s", + w->weight, weight, w->path); + + cgroup_apply_io_device_weight(u, w->path, weight); + } } } @@ -634,6 +661,9 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { limits[CGROUP_IO_RBPS_MAX] = b->rbps; limits[CGROUP_IO_WBPS_MAX] = b->wbps; + log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax for %s", + b->rbps, b->wbps, b->path); + if (!cgroup_apply_io_device_limit(u, b->path, limits)) cgroup_context_free_blockio_device_bandwidth(c, b); } @@ -650,9 +680,14 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { if (has_blockio) weight = cgroup_context_blkio_weight(c, state); - else if (has_io) + else if (has_io) { + uint64_t io_weight = cgroup_context_io_weight(c, state); + weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state)); - else + + log_cgroup_compat(u, "Applying [Startup]IOWeight %" PRIu64 " as [Startup]BlockIOWeight %" PRIu64, + io_weight, weight); + } else weight = CGROUP_BLKIO_WEIGHT_DEFAULT; xsprintf(buf, "%" PRIu64 "\n", weight); @@ -671,8 +706,14 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { CGroupIODeviceWeight *w; /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->io_device_weights) - cgroup_apply_blkio_device_weight(u, w->path, cgroup_weight_io_to_blkio(w->weight)); + LIST_FOREACH(device_weights, w, c->io_device_weights) { + weight = cgroup_weight_io_to_blkio(w->weight); + + log_cgroup_compat(u, "Applying IODeviceWeight %" PRIu64 " as BlockIODeviceWeight %" PRIu64 " for %s", + w->weight, weight, w->path); + + cgroup_apply_blkio_device_weight(u, w->path, weight); + } } } @@ -688,6 +729,9 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { CGroupIODeviceLimit *l, *next; LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { + log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax for %s", + l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX], l->path); + if (!cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX])) cgroup_context_free_io_device_limit(c, l); } @@ -700,9 +744,13 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { if (cgroup_context_has_unified_memory_config(c)) max = c->memory_max; - else + else { max = c->memory_limit; + if (max != CGROUP_LIMIT_MAX) + log_cgroup_compat(u, "Applying MemoryLimit %" PRIu64 " as MemoryMax", max); + } + cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low); cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); cgroup_apply_unified_memory_limit(u, "memory.max", max); @@ -711,9 +759,13 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { if (c->memory_limit != CGROUP_LIMIT_MAX) xsprintf(buf, "%" PRIu64 "\n", c->memory_limit); - else + else { xsprintf(buf, "%" PRIu64 "\n", c->memory_max); + if (c->memory_max != CGROUP_LIMIT_MAX) + log_cgroup_compat(u, "Applying MemoryMax %" PRIu64 " as MemoryLimit", c->memory_max); + } + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); if (r < 0) log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, -- cgit v1.2.3-54-g00ecf From d2bc1251320c9e69c5fc6953f01aba80cafd5029 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 3 Jun 2016 11:15:44 +0200 Subject: resolved: fix comments in resolve.conf for search domain overflows (#3422) Write comments about "too many search domains" and "Total length of all search domains is too long" just once. Also put it on a separate line, as resolv.conf(5) only specifies comments in a line by themselves. This is ugly to do if write_resolv_conf_search() gets called once for every search domain. So change it to receive the complete OrderedSet instead and do the iteration by itself. Add test cases to networkd-test.py. https://launchpad.net/bugs/1588229 --- src/resolve/resolved-resolv-conf.c | 49 ++++++++++++-------------- test/networkd-test.py | 71 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index ff03acc772..fa89de4c21 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -164,30 +164,32 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { } static void write_resolv_conf_search( - const char *domain, - FILE *f, - unsigned *count, - unsigned *length) { + OrderedSet *domains, + FILE *f) { + unsigned length = 0, count = 0; + Iterator i; + char *domain; - assert(domain); + assert(domains); assert(f); - assert(length); - if (*count >= MAXDNSRCH || - *length + strlen(domain) > 256) { - if (*count == MAXDNSRCH) - fputs(" # Too many search domains configured, remaining ones ignored.", f); - if (*length <= 256) - fputs(" # Total length of all search domains is too long, remaining ones ignored.", f); + fputs("search", f); - return; + ORDERED_SET_FOREACH(domain, domains, i) { + if (++count > MAXDNSRCH) { + fputs("\n# Too many search domains configured, remaining ones ignored.", f); + break; + } + length += strlen(domain) + 1; + if (length > 256) { + fputs("\n# Total length of all search domains is too long, remaining ones ignored.", f); + break; + } + fputc(' ', f); + fputs(domain, f); } - (*length) += strlen(domain); - (*count)++; - - fputc(' ', f); - fputs(domain, f); + fputs("\n", f); } static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { @@ -209,15 +211,8 @@ static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *doma write_resolv_conf_server(s, f, &count); } - if (!ordered_set_isempty(domains)) { - unsigned length = 0, count = 0; - char *domain; - - fputs("search", f); - ORDERED_SET_FOREACH(domain, domains, i) - write_resolv_conf_search(domain, f, &count, &length); - fputs("\n", f); - } + if (!ordered_set_isempty(domains)) + write_resolv_conf_search(domains, f); return fflush_and_check(f); } diff --git a/test/networkd-test.py b/test/networkd-test.py index d4de5adf1a..f94224cce2 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -370,6 +370,77 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=// def test_coldplug_dhcp_ip6(self): pass + def test_search_domains(self): + + # we don't use this interface for this test + self.if_router = None + + with open('/run/systemd/network/test.netdev', 'w') as f: + f.write('''[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + with open('/run/systemd/network/test.network', 'w') as f: + f.write('''[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains= one two three four five six seven eight nine ten''') + self.addCleanup(os.remove, '/run/systemd/network/test.netdev') + self.addCleanup(os.remove, '/run/systemd/network/test.network') + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + + if os.path.islink('/etc/resolv.conf'): + for timeout in range(50): + with open('/etc/resolv.conf') as f: + contents = f.read() + if 'search one\n' in contents: + break + time.sleep(0.1) + self.assertIn('search one two three four five six\n' + '# Too many search domains configured, remaining ones ignored.\n', + contents) + + def test_search_domains_too_long(self): + + # we don't use this interface for this test + self.if_router = None + + name_prefix = 'a' * 60 + + with open('/run/systemd/network/test.netdev', 'w') as f: + f.write('''[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + with open('/run/systemd/network/test.network', 'w') as f: + f.write('''[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains=''') + for i in range(5): + f.write('%s%i ' % (name_prefix, i)) + + self.addCleanup(os.remove, '/run/systemd/network/test.netdev') + self.addCleanup(os.remove, '/run/systemd/network/test.network') + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + + if os.path.islink('/etc/resolv.conf'): + for timeout in range(50): + with open('/etc/resolv.conf') as f: + contents = f.read() + if 'search one\n' in contents: + break + time.sleep(0.1) + self.assertIn('search %(p)s0 %(p)s1 %(p)s2 %(p)s3\n' + '# Total length of all search domains is too long, remaining ones ignored.' % {'p': name_prefix}, + contents) + if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, -- cgit v1.2.3-54-g00ecf From ac9b215d0cf4b74f2ba1afe341817553a67fe2bb Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Fri, 3 Jun 2016 12:33:12 +0200 Subject: missing include added for build with -DDEBUG (#3424) --- src/basic/siphash24.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 060e8ba387..8c1cdc3db6 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -17,6 +17,8 @@ coding style) */ +#include + #include "macro.h" #include "siphash24.h" #include "unaligned.h" -- cgit v1.2.3-54-g00ecf From e57c9ce169a135c0461108075a72bc2bedb299c7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 3 Jun 2016 08:49:05 -0700 Subject: core: always use "infinity" for no upper limit instead of "max" (#3417) Recently added cgroup unified hierarchy support uses "max" in configurations for no upper limit. While consistent with what the kernel uses for no upper limit, it is inconsistent with what systemd uses for other controllers such as memory or pids. There's no point in introducing another term. Update cgroup unified hierarchy support so that "infinity" is the only term that systemd uses for no upper limit. --- man/systemd.resource-control.xml | 4 ++-- src/core/load-fragment.c | 4 ++-- src/shared/bus-unit-util.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 570619a743..d4c8fa7091 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -248,7 +248,7 @@ Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value max, no memory limit is applied. This controls the + special value infinity, no memory limit is applied. This controls the memory.high control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -269,7 +269,7 @@ Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value max, no memory limit is applied. This controls the + special value infinity, no memory limit is applied. This controls the memory.max control group attribute. For details about this control group attribute, see cgroup-v2.txt. diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 50ff718aab..b53301a147 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2811,7 +2811,7 @@ int config_parse_memory_limit( uint64_t bytes = CGROUP_LIMIT_MAX; int r; - if (!isempty(rvalue) && !streq(rvalue, "infinity") && !streq(rvalue, "max")) { + if (!isempty(rvalue) && !streq(rvalue, "infinity")) { r = parse_size(rvalue, 1024, &bytes); if (r < 0 || bytes < 1) { log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); @@ -3080,7 +3080,7 @@ int config_parse_io_limit( return 0; } - if (streq("max", limit)) { + if (streq("infinity", limit)) { num = CGROUP_LIMIT_MAX; } else { r = parse_size(limit, 1000, &num); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 502e98d9dc..bf0b2e89e3 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -169,7 +169,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { uint64_t bytes; - if (isempty(eq) || streq(eq, "max") || streq(eq, "infinity")) + if (isempty(eq) || streq(eq, "infinity")) bytes = CGROUP_LIMIT_MAX; else { r = parse_size(eq, 1024, &bytes); @@ -306,7 +306,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - if (streq(bandwidth, "max")) { + if (streq(bandwidth, "infinity")) { bytes = CGROUP_LIMIT_MAX; } else { r = parse_size(bandwidth, 1000, &bytes); -- cgit v1.2.3-54-g00ecf From f3e43635932c14f8f0aea078adf3bfe09a9ba683 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Fri, 3 Jun 2016 15:58:18 +0000 Subject: core: Restrict mmap and mprotect with PAGE_WRITE|PAGE_EXEC (#3319) (#3379) New exec boolean MemoryDenyWriteExecute, when set, installs a seccomp filter to reject mmap(2) with PAGE_WRITE|PAGE_EXEC and mprotect(2) with PAGE_EXEC. --- man/systemd.exec.xml | 16 +++++++++++ src/core/dbus-execute.c | 5 +++- src/core/execute.c | 53 +++++++++++++++++++++++++++++++++-- src/core/execute.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/shared/bus-unit-util.c | 2 +- 6 files changed, 75 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 58f18f3a9e..4a3dd14c39 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1388,6 +1388,22 @@ tmpfiles.d5. + + MemoryDenyWriteExecute= + + Takes a boolean argument. If set, attempts to create memory mappings that are writable and + executable at the same time, or to change existing memory mappings to become executable are prohibited. + Specifically, a system call filter is added that rejects + mmap2 + system calls with both PROT_EXEC and PROT_WRITE set + and mprotect2 + system calls with PROT_EXEC set. Note that this option is incompatible with programs + that generate program code dynamically at runtime, such as JIT execution engines, or programs compiled making + use of the code "trampoline" feature of various C compilers. This option improves service security, as it makes + harder for software exploits to change running code dynamically. + + + diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index de29d5da04..4c88c41127 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -719,6 +719,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -1056,7 +1057,7 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "PrivateTmp", "PrivateDevices", "PrivateNetwork", - "NoNewPrivileges", "SyslogLevelPrefix")) { + "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -1080,6 +1081,8 @@ int bus_exec_context_set_transient_property( c->no_new_privileges = b; else if (streq(name, "SyslogLevelPrefix")) c->syslog_level_prefix = b; + else if (streq(name, "MemoryDenyWriteExecute")) + c->memory_deny_write_execute = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } diff --git a/src/core/execute.c b/src/core/execute.c index 5eb3f13695..2cef70e668 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1190,6 +1191,45 @@ finish: return r; } +static int apply_memory_deny_write_execute(const ExecContext *c) { + scmp_filter_ctx *seccomp; + int r; + + assert(c); + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_KILL, + SCMP_SYS(mmap), + 1, + SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC|PROT_WRITE, PROT_EXEC|PROT_WRITE)); + if (r < 0) + goto finish; + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_KILL, + SCMP_SYS(mprotect), + 1, + SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC)); + if (r < 0) + goto finish; + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; +} + #endif static void do_idle_pipe_dance(int idle_pipe[4]) { @@ -1912,6 +1952,13 @@ static int exec_child( } } + if (context->memory_deny_write_execute) { + r = apply_memory_deny_write_execute(context); + if (r < 0) { + *exit_status = EXIT_SECCOMP; + return r; + } + } if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { @@ -2371,7 +2418,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sPrivateDevices: %s\n" "%sProtectHome: %s\n" "%sProtectSystem: %s\n" - "%sIgnoreSIGPIPE: %s\n", + "%sIgnoreSIGPIPE: %s\n" + "%sMemoryDenyWriteExecute: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", @@ -2381,7 +2429,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->private_devices), prefix, protect_home_to_string(c->protect_home), prefix, protect_system_to_string(c->protect_system), - prefix, yes_no(c->ignore_sigpipe)); + prefix, yes_no(c->ignore_sigpipe), + prefix, yes_no(c->memory_deny_write_execute)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); diff --git a/src/core/execute.h b/src/core/execute.h index 41148bcea2..464869d226 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -197,6 +197,7 @@ struct ExecContext { bool ioprio_set:1; bool cpu_sched_set:1; bool no_new_privileges_set:1; + bool memory_deny_write_execute; }; #include "cgroup-util.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 00bdc238ce..eb58586523 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -55,10 +55,12 @@ m4_ifdef(`HAVE_SECCOMP', `$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context) $1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs) $1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context) +$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute) $1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)', `$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 +$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bf0b2e89e3..8f4f93ee0c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -158,7 +158,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", - "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) { + "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute")) { r = parse_boolean(eq); if (r < 0) -- cgit v1.2.3-54-g00ecf From 8c34b963076a1ce7c9102802a13502be82a02cc7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 19:14:12 +0200 Subject: networkd: enforce a limit on the number of statically assigned addresses/routes/fdb entries We should put a limit on everything, hence also on these resources. --- src/network/networkd-address.c | 17 +++++++++++++---- src/network/networkd-fdb.c | 25 +++++++++++++++++-------- src/network/networkd-network.h | 4 ++++ src/network/networkd-route.c | 15 +++++++++++++-- 4 files changed, 47 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 367c340e08..4cdb500bd6 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -32,6 +32,8 @@ #include "utf8.h" #include "util.h" +#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U + int address_new(Address **ret) { _cleanup_address_free_ Address *address = NULL; @@ -54,6 +56,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) { _cleanup_address_free_ Address *address = NULL; int r; + assert(network); + assert(ret); + if (section) { address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section)); if (address) { @@ -64,18 +69,21 @@ int address_new_static(Network *network, unsigned section, Address **ret) { } } + if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX) + return -E2BIG; + r = address_new(&address); if (r < 0) return r; if (section) { address->section = section; - hashmap_put(network->addresses_by_section, - UINT_TO_PTR(address->section), address); + hashmap_put(network->addresses_by_section, UINT_TO_PTR(address->section), address); } address->network = network; LIST_APPEND(addresses, network->static_addresses, address); + network->n_static_addresses++; *ret = address; address = NULL; @@ -89,10 +97,11 @@ void address_free(Address *address) { if (address->network) { LIST_REMOVE(addresses, address->network->static_addresses, address); + assert(address->network->n_static_addresses > 0); + address->network->n_static_addresses--; if (address->section) - hashmap_remove(address->network->addresses_by_section, - UINT_TO_PTR(address->section)); + hashmap_remove(address->network->addresses_by_section, UINT_TO_PTR(address->section)); } if (address->link) { diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 241f486211..4d51fa41e2 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -27,14 +27,19 @@ #include "networkd.h" #include "util.h" +#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U + /* create a new FDB entry or get an existing one. */ -int fdb_entry_new_static(Network *const network, - const unsigned section, - FdbEntry **ret) { +int fdb_entry_new_static( + Network *network, + const unsigned section, + FdbEntry **ret) { + _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL; struct ether_addr *mac_addr = NULL; assert(network); + assert(ret); /* search entry in hashmap first. */ if (section) { @@ -47,6 +52,9 @@ int fdb_entry_new_static(Network *const network, } } + if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX) + return -E2BIG; + /* allocate space for MAC address. */ mac_addr = new0(struct ether_addr, 1); if (!mac_addr) @@ -54,7 +62,6 @@ int fdb_entry_new_static(Network *const network, /* allocate space for and FDB entry. */ fdb_entry = new0(FdbEntry, 1); - if (!fdb_entry) { /* free previously allocated space for mac_addr. */ free(mac_addr); @@ -66,6 +73,7 @@ int fdb_entry_new_static(Network *const network, fdb_entry->mac_addr = mac_addr; LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry); + network->n_static_fdb_entries++; if (section) { fdb_entry->section = section; @@ -145,12 +153,13 @@ void fdb_entry_free(FdbEntry *fdb_entry) { return; if (fdb_entry->network) { - LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, - fdb_entry); + LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry); + + assert(fdb_entry->network->n_static_fdb_entries > 0); + fdb_entry->network->n_static_fdb_entries--; if (fdb_entry->section) - hashmap_remove(fdb_entry->network->fdb_entries_by_section, - UINT_TO_PTR(fdb_entry->section)); + hashmap_remove(fdb_entry->network->fdb_entries_by_section, UINT_TO_PTR(fdb_entry->section)); } free(fdb_entry->mac_addr); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 91099161ce..248a427e8d 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -169,6 +169,10 @@ struct Network { LIST_HEAD(Route, static_routes); LIST_HEAD(FdbEntry, static_fdb_entries); + unsigned n_static_addresses; + unsigned n_static_routes; + unsigned n_static_fdb_entries; + Hashmap *addresses_by_section; Hashmap *routes_by_section; Hashmap *fdb_entries_by_section; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index f001de772a..1b480385c6 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -28,6 +28,8 @@ #include "string-util.h" #include "util.h" +#define STATIC_ROUTES_PER_NETWORK_MAX 1024U + int route_new(Route **ret) { _cleanup_route_free_ Route *route = NULL; @@ -51,6 +53,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; int r; + assert(network); + assert(ret); + if (section) { route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section)); if (route) { @@ -61,6 +66,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) { } } + if (network->n_static_routes >= STATIC_ROUTES_PER_NETWORK_MAX) + return -E2BIG; + r = route_new(&route); if (r < 0) return r; @@ -77,6 +85,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) { route->network = network; LIST_PREPEND(routes, network->static_routes, route); + network->n_static_routes++; *ret = route; route = NULL; @@ -91,9 +100,11 @@ void route_free(Route *route) { if (route->network) { LIST_REMOVE(routes, route->network->static_routes, route); + assert(route->network->n_static_routes > 0); + route->network->n_static_routes--; + if (route->section) - hashmap_remove(route->network->routes_by_section, - UINT_TO_PTR(route->section)); + hashmap_remove(route->network->routes_by_section, UINT_TO_PTR(route->section)); } if (route->link) { -- cgit v1.2.3-54-g00ecf From 75f8a779fdd433366643b905caa005c14e1a8331 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 19:20:00 +0200 Subject: sd-netlink: fix sd_netlink_inc_rcvbuf() prototype Drop weird "const" usage, and use size_t for sizes. --- src/libsystemd/sd-netlink/sd-netlink.c | 5 ++++- src/systemd/sd-netlink.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 91701405a5..43114eb825 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -144,7 +144,10 @@ int sd_netlink_open(sd_netlink **ret) { return 0; } -int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) { +int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) { + assert_return(rtnl, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + return fd_inc_rcvbuf(rtnl->fd, size); } diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 3ae110c080..7efa8ebe5a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -43,7 +43,7 @@ typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message * int sd_netlink_new_from_netlink(sd_netlink **nl, int fd); int sd_netlink_open(sd_netlink **nl); int sd_netlink_open_fd(sd_netlink **nl, int fd); -int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size); +int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size); sd_netlink *sd_netlink_ref(sd_netlink *nl); sd_netlink *sd_netlink_unref(sd_netlink *nl); -- cgit v1.2.3-54-g00ecf From a60a720c7e67b77911e4130a5eef41f652375ce3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 19:20:46 +0200 Subject: networkd: drop weird "const" usage in function parameters We generally only use "const" to constify the destination of pointers, but not the pointers themselves, as they are copied anyway during C function invocation. Hence, drop this usage of "const". --- src/network/networkd-fdb.c | 4 ++-- src/network/networkd-fdb.h | 4 ++-- src/network/networkd-link.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 4d51fa41e2..9829438ba2 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -32,7 +32,7 @@ /* create a new FDB entry or get an existing one. */ int fdb_entry_new_static( Network *network, - const unsigned section, + unsigned section, FdbEntry **ret) { _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL; @@ -102,7 +102,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda } /* send a request to the kernel to add a FDB entry in its static MAC table. */ -int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) { +int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; sd_netlink *rtnl; int r; diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h index 84410714f5..2d7d28735c 100644 --- a/src/network/networkd-fdb.h +++ b/src/network/networkd-fdb.h @@ -36,9 +36,9 @@ struct FdbEntry { LIST_FIELDS(FdbEntry, static_fdb_entries); }; -int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret); +int fdb_entry_new_static(Network *network, unsigned section, FdbEntry **ret); void fdb_entry_free(FdbEntry *fdb_entry); -int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry); +int fdb_entry_configure(Link *link, FdbEntry *fdb_entry); DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free); #define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ba4147f875..5bf98765c6 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1092,7 +1092,7 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u return 1; } -static int link_set_bridge_fdb(Link *const link) { +static int link_set_bridge_fdb(Link *link) { FdbEntry *fdb_entry; int r = 0; @@ -1107,7 +1107,7 @@ static int link_set_bridge_fdb(Link *const link) { return r; } -static int link_set_proxy_arp(Link *const link) { +static int link_set_proxy_arp(Link *link) { const char *p = NULL; int r; -- cgit v1.2.3-54-g00ecf From 1b566071577fabd45f7e2b449ac583814d522759 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 19:51:48 +0200 Subject: networkd: also enforce limit on total number of address/routes This covers the address/routers acquire dynamically. --- src/network/networkd-address.c | 48 +++++++++++++++++++++++++++++------------- src/network/networkd-route.c | 47 +++++++++++++++++++++++++---------------- src/network/networkd-route.h | 2 +- 3 files changed, 63 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 4cdb500bd6..9275ccf9a9 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -32,6 +32,7 @@ #include "utf8.h" #include "util.h" +#define ADDRESSES_PER_LINK_MAX 2048U #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U int address_new(Address **ret) { @@ -392,31 +393,38 @@ int address_drop(Address *address) { return 0; } -int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { - Address address = {}, *existing; +int address_get(Link *link, + int family, + const union in_addr_union *in_addr, + unsigned char prefixlen, + Address **ret) { + + Address address, *existing; assert(link); assert(in_addr); - assert(ret); - address.family = family; - address.in_addr = *in_addr; - address.prefixlen = prefixlen; + address = (Address) { + .family = family, + .in_addr = *in_addr, + .prefixlen = prefixlen, + }; existing = set_get(link->addresses, &address); if (existing) { - *ret = existing; - + if (ret) + *ret = existing; return 1; - } else { - existing = set_get(link->addresses_foreign, &address); - if (!existing) - return -ENOENT; } - *ret = existing; + existing = set_get(link->addresses_foreign, &address); + if (existing) { + if (ret) + *ret = existing; + return 0; + } - return 0; + return -ENOENT; } int address_remove( @@ -518,7 +526,12 @@ static int address_acquire(Link *link, Address *original, Address **ret) { return 0; } -int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) { +int address_configure( + Address *address, + Link *link, + sd_netlink_message_handler_t callback, + bool update) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -529,6 +542,11 @@ int address_configure(Address *address, Link *link, sd_netlink_message_handler_t assert(link->manager); assert(link->manager->rtnl); + /* If this is a new address, then refuse adding more than the limit */ + if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 && + set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX) + return -E2BIG; + r = address_acquire(link, address, &address); if (r < 0) return r; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 1b480385c6..0d2a5bb83d 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -28,6 +28,7 @@ #include "string-util.h" #include "util.h" +#define ROUTES_PER_LINK_MAX 2048U #define STATIC_ROUTES_PER_NETWORK_MAX 1024U int route_new(Route **ret) { @@ -187,39 +188,42 @@ static const struct hash_ops route_hash_ops = { int route_get(Link *link, int family, - union in_addr_union *dst, + const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret) { - Route route = { + + Route route, *existing; + + assert(link); + assert(dst); + + route = (Route) { .family = family, + .dst = *dst, .dst_prefixlen = dst_prefixlen, .tos = tos, .priority = priority, .table = table, - }, *existing; - - assert(link); - assert(dst); - assert(ret); - - route.dst = *dst; + }; existing = set_get(link->routes, &route); if (existing) { - *ret = existing; + if (ret) + *ret = existing; return 1; - } else { - existing = set_get(link->routes_foreign, &route); - if (!existing) - return -ENOENT; } - *ret = existing; + existing = set_get(link->routes_foreign, &route); + if (existing) { + if (ret) + *ret = existing; + return 0; + } - return 0; + return -ENOENT; } static int route_add_internal(Link *link, Set **routes, @@ -460,8 +464,11 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { return 1; } -int route_configure(Route *route, Link *link, - sd_netlink_message_handler_t callback) { +int route_configure( + Route *route, + Link *link, + sd_netlink_message_handler_t callback) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; usec_t lifetime; @@ -473,6 +480,10 @@ int route_configure(Route *route, Link *link, assert(link->ifindex > 0); assert(route->family == AF_INET || route->family == AF_INET6); + if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 && + set_size(route->link->routes) >= ROUTES_PER_LINK_MAX) + return -E2BIG; + r = sd_rtnl_message_new_route(link->manager->rtnl, &req, RTM_NEWROUTE, route->family, route->protocol); diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 39de8363ed..ddc3e1da57 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -57,7 +57,7 @@ void route_free(Route *route); int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback); -int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); -- cgit v1.2.3-54-g00ecf From 889b550f2dc27b7696781d3d9d91e8de28fd8fee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 19:54:35 +0200 Subject: networkd: constify more things --- src/network/networkd-address.c | 7 +++++- src/network/networkd-address.h | 2 +- src/network/networkd-route.c | 51 +++++++++++++++++++++++++----------------- src/network/networkd-route.h | 6 ++--- 4 files changed, 41 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 9275ccf9a9..5498e352d8 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -338,7 +338,12 @@ static int address_release(Address *address) { return 0; } -int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) { +int address_update( + Address *address, + unsigned char flags, + unsigned char scope, + const struct ifa_cacheinfo *cinfo) { + bool ready; int r; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 784ab18b27..03c4bea7c6 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -63,7 +63,7 @@ void address_free(Address *address); int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); -int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo); +int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo); int address_drop(Address *address); int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update); int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback); diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 0d2a5bb83d..6359f967a2 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -226,13 +226,17 @@ int route_get(Link *link, return -ENOENT; } -static int route_add_internal(Link *link, Set **routes, - int family, - union in_addr_union *dst, - unsigned char dst_prefixlen, - unsigned char tos, - uint32_t priority, - unsigned char table, Route **ret) { +static int route_add_internal( + Link *link, + Set **routes, + int family, + const union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, + Route **ret) { + _cleanup_route_free_ Route *route = NULL; int r; @@ -269,23 +273,29 @@ static int route_add_internal(Link *link, Set **routes, return 0; } -int route_add_foreign(Link *link, - int family, - union in_addr_union *dst, - unsigned char dst_prefixlen, - unsigned char tos, - uint32_t priority, - unsigned char table, Route **ret) { +int route_add_foreign( + Link *link, + int family, + const union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, + Route **ret) { + return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret); } -int route_add(Link *link, +int route_add( + Link *link, int family, - union in_addr_union *dst, + const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, - unsigned char table, Route **ret) { + unsigned char table, + Route **ret) { + Route *route; int r; @@ -318,12 +328,13 @@ int route_add(Link *link, } int route_update(Route *route, - union in_addr_union *src, + const union in_addr_union *src, unsigned char src_prefixlen, - union in_addr_union *gw, - union in_addr_union *prefsrc, + const union in_addr_union *gw, + const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol) { + assert(route); assert(src); assert(gw); diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index ddc3e1da57..d4e4dbac0b 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -58,9 +58,9 @@ int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callb int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback); int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); -int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); -int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); -int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); +int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); -- cgit v1.2.3-54-g00ecf From 3fb1ac5d57954bb0d881a68777e996b46ed44ce3 Mon Sep 17 00:00:00 2001 From: tomty89 Date: Sat, 4 Jun 2016 18:31:07 +0800 Subject: networkd-link: fix handler typo for route_remove() (#3433) Obviously we've been using the wrong handler here. Fixes #3352. --- src/network/networkd-link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ba4147f875..ee52b1ce1e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2252,7 +2252,7 @@ static int link_drop_foreign_config(Link *link) { if (route->protocol == RTPROT_KERNEL) continue; - r = route_remove(route, link, link_address_remove_handler); + r = route_remove(route, link, link_route_remove_handler); if (r < 0) return r; } -- cgit v1.2.3-54-g00ecf From 592705f2f708b313ef3e07677463fe676cdd774a Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 5 Jun 2016 02:24:20 +0300 Subject: systemctl: install sigbus handler (#3435) This makes systemctl robust regarding journal truncation. This is a follow-up for 2cf4172a71860c6e44 Fixes: Core was generated by `./systemctl status systemd-journald'. Program terminated with signal SIGBUS, Bus error. PID 8569 - core TID 8569: #0 0x00007f246cc89ed6 __memcmp_sse4_1 #1 0x0000557ebbc6f42c journal_file_init_header #2 0x0000557ebbc77262 journal_file_open #3 0x0000557ebbc42999 file_type_wanted #4 0x0000557ebbc42e08 add_any_file #5 0x0000557ebbc43832 add_directory #6 0x0000557ebbc4401c add_root_directory #7 0x0000557ebbc442e9 add_root_directory #8 0x0000557ebbc446fc add_search_paths #9 0x0000557ebbbacb5e show_journal_by_unit #10 0x0000557ebbb8376d print_status_info #11 0x0000557ebbb86a0b show_one #12 0x0000557ebbb87954 show #13 0x0000557ebbc20b1f dispatch_verb #14 0x0000557ebbb90615 systemctl_main #15 0x0000557ebbb9159f main #16 0x00007f246cb3e731 __libc_start_main #17 0x0000557ebbb75ae9 _start --- src/systemctl/systemctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e6ff299dd4..df41182529 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -70,6 +70,7 @@ #include "process-util.h" #include "rlimit-util.h" #include "set.h" +#include "sigbus.h" #include "signal-util.h" #include "socket-util.h" #include "spawn-ask-password-agent.h" @@ -7807,6 +7808,7 @@ int main(int argc, char*argv[]) { setlocale(LC_ALL, ""); log_parse_environment(); log_open(); + sigbus_install(); /* Explicitly not on_tty() to avoid setting cached value. * This becomes relevant for piping output which might be -- cgit v1.2.3-54-g00ecf From 0a62f81045dd810c8f1223cccbac4d706ea2cb45 Mon Sep 17 00:00:00 2001 From: michaelolbrich Date: Sun, 5 Jun 2016 17:25:14 +0200 Subject: automount: handle expire_tokens when the mount unit changes its state (#3434) This basically reverts 7b2fd9d51259f6cf350791434e640ac3519acc6c ("core: remove duplicate code in automount_update_mount()"). This was not duplicate code. The expire_tokens need to be handled as well: Send 0 == success for MOUNT_DEAD (umount successful), do nothing for MOUNT_UNMOUNTING (not yet done) and an error for everything else. Otherwise the automount logic will assume unmounting is not done and will not send any new requests for mounting. As a result, the corresponding mount unit is never mounted. Without this, automounts with TimeoutIdleSec= are broken. Once the idle timeout triggered a umount, any access to the corresponding filesystem hangs forever. Fixes #3332. --- src/core/automount.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index f06d837e30..85803a9c4a 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -502,6 +502,20 @@ static void automount_trigger_notify(Unit *u, Unit *other) { automount_set_state(a, AUTOMOUNT_RUNNING); } + if (IN_SET(MOUNT(other)->state, + MOUNT_MOUNTING, MOUNT_MOUNTING_DONE, + MOUNT_MOUNTED, MOUNT_REMOUNTING, + MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED)) { + + (void) automount_send_ready(a, a->expire_tokens, -ENODEV); + } + + if (MOUNT(other)->state == MOUNT_DEAD) + (void) automount_send_ready(a, a->expire_tokens, 0); + /* The mount is in some unhappy state now, let's unfreeze any waiting clients */ if (IN_SET(MOUNT(other)->state, MOUNT_DEAD, MOUNT_UNMOUNTING, -- cgit v1.2.3-54-g00ecf From 308253c5a2b146fc18e3789725c092ac55b10ce7 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Sun, 5 Jun 2016 19:42:37 +0200 Subject: cgtop: add option to show a single cgroup subtree (#3413) When many services are running, it was difficult to see only the interesting ones. This patch allows to show only the subtree of interest. --- man/systemd-cgtop.xml | 8 ++++++-- src/cgtop/cgtop.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index c76f646984..be13631239 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -52,6 +52,7 @@ systemd-cgtop OPTIONS + GROUP @@ -62,7 +63,9 @@ groups of the local Linux control group hierarchy, ordered by their CPU, memory, or disk I/O load. The display is refreshed in regular intervals (by default every 1s), similar in style to - top1. + top1. + If a control group path is specified, shows only the services of + the specified control group. If systemd-cgtop is not connected to a tty, no column headers are printed and the default is to only run @@ -252,7 +255,8 @@ Limit control groups shown to the part corresponding to the container - MACHINE. + MACHINE. + This option may not be used when a control group path is specified. diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 33379eb9bd..b4a982ce38 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -72,6 +72,7 @@ static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; static char* arg_machine = NULL; +static char* arg_root = NULL; static bool arg_recursive = true; static enum { @@ -653,7 +654,7 @@ static void display(Hashmap *a) { } static void help(void) { - printf("%s [OPTIONS...]\n\n" + printf("%s [OPTIONS...] [CGROUP]\n\n" "Show top control groups by their resource usage.\n\n" " -h --help Show this help\n" " --version Show package version\n" @@ -835,7 +836,13 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (optind < argc) { + if (optind == argc-1) { + if (arg_machine) { + log_error("Specifying a control group path together with the -M option is not allowed"); + return -EINVAL; + } + arg_root = argv[optind]; + } else if (optind < argc) { log_error("Too many arguments."); return -EINVAL; } @@ -864,6 +871,13 @@ static int get_cgroup_root(char **ret) { const char *m; int r; + if (arg_root) { + *ret = strdup(arg_root); + if (!*ret) + return log_oom(); + return 0; + } + if (!arg_machine) { r = cg_get_root_path(ret); if (r < 0) -- cgit v1.2.3-54-g00ecf From 0738b927a1ec80549e92bc70ded6959b4c6a8c57 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Mon, 6 Jun 2016 12:38:23 +0200 Subject: cgtop: fix ret pointer usage (#3443) --- src/cgtop/cgtop.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index b4a982ce38..6bd2288897 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -868,13 +868,15 @@ static int get_cgroup_root(char **ret) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *unit = NULL, *path = NULL; + char *aux; const char *m; int r; if (arg_root) { - *ret = strdup(arg_root); - if (!*ret) + aux = strdup(arg_root); + if (!aux) return log_oom(); + *ret = aux; return 0; } -- cgit v1.2.3-54-g00ecf From 45819e7cbfe5bd9044faca0f1e6e1145d7c0cfaa Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Mon, 6 Jun 2016 14:03:07 +0200 Subject: networkd: remove unused variable (#3447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this patch solves the following waring: ../src/network/networkd-ndisc.c:197:13: warning: unused variable ‘r’ [-Wunused-variable] int r; fixes acac5b2f --- src/network/networkd-ndisc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 7359cc2b67..a0d4fa77d8 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -194,7 +194,6 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { Link *link = userdata; - int r; assert(link); -- cgit v1.2.3-54-g00ecf From 78c97cbe74f844bd3b8e855e7ba7184e05078f89 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 26 May 2016 13:46:56 -0400 Subject: localed: get rid of duplicated enum and string table --- src/locale/localed.c | 153 +++++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/locale/localed.c b/src/locale/localed.c index 6af59fc830..4995cbc23d 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -46,45 +46,8 @@ #include "user-util.h" #include "util.h" -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - LOCALE_LANG, - LOCALE_LANGUAGE, - LOCALE_LC_CTYPE, - LOCALE_LC_NUMERIC, - LOCALE_LC_TIME, - LOCALE_LC_COLLATE, - LOCALE_LC_MONETARY, - LOCALE_LC_MESSAGES, - LOCALE_LC_PAPER, - LOCALE_LC_NAME, - LOCALE_LC_ADDRESS, - LOCALE_LC_TELEPHONE, - LOCALE_LC_MEASUREMENT, - LOCALE_LC_IDENTIFICATION, - _LOCALE_MAX -}; - -static const char * const names[_LOCALE_MAX] = { - [LOCALE_LANG] = "LANG", - [LOCALE_LANGUAGE] = "LANGUAGE", - [LOCALE_LC_CTYPE] = "LC_CTYPE", - [LOCALE_LC_NUMERIC] = "LC_NUMERIC", - [LOCALE_LC_TIME] = "LC_TIME", - [LOCALE_LC_COLLATE] = "LC_COLLATE", - [LOCALE_LC_MONETARY] = "LC_MONETARY", - [LOCALE_LC_MESSAGES] = "LC_MESSAGES", - [LOCALE_LC_PAPER] = "LC_PAPER", - [LOCALE_LC_NAME] = "LC_NAME", - [LOCALE_LC_ADDRESS] = "LC_ADDRESS", - [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE", - [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT", - [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; - typedef struct Context { - char *locale[_LOCALE_MAX]; + char *locale[_VARIABLE_LC_MAX]; char *x11_layout; char *x11_model; @@ -118,7 +81,7 @@ static void context_free_vconsole(Context *c) { static void context_free_locale(Context *c) { int p; - for (p = 0; p < _LOCALE_MAX; p++) + for (p = 0; p < _VARIABLE_LC_MAX; p++) c->locale[p] = mfree(c->locale[p]); } @@ -133,8 +96,8 @@ static void context_free(Context *c) { static void locale_simplify(Context *c) { int p; - for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) - if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) + for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) + if (isempty(c->locale[p]) || streq_ptr(c->locale[VARIABLE_LANG], c->locale[p])) c->locale[p] = mfree(c->locale[p]); } @@ -144,30 +107,33 @@ static int locale_read_data(Context *c) { context_free_locale(c); r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &c->locale[LOCALE_LANG], - "LANGUAGE", &c->locale[LOCALE_LANGUAGE], - "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE], - "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC], - "LC_TIME", &c->locale[LOCALE_LC_TIME], - "LC_COLLATE", &c->locale[LOCALE_LC_COLLATE], - "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY], - "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES], - "LC_PAPER", &c->locale[LOCALE_LC_PAPER], - "LC_NAME", &c->locale[LOCALE_LC_NAME], - "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS], - "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE], - "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION], + "LANG", &c->locale[VARIABLE_LANG], + "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], + "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], + "LC_TIME", &c->locale[VARIABLE_LC_TIME], + "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], + "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], + "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], + "LC_NAME", &c->locale[VARIABLE_LC_NAME], + "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], NULL); if (r == -ENOENT) { int p; /* Fill in what we got passed from systemd. */ - for (p = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name; + + name = locale_variable_to_string(p); + assert(name); - r = free_and_strdup(&c->locale[p], empty_to_null(getenv(names[p]))); + r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); if (r < 0) return r; } @@ -279,18 +245,20 @@ static int locale_write_data(Context *c, char ***settings) { if (r < 0 && r != -ENOENT) return r; - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { _cleanup_free_ char *t = NULL; char **u; + const char *name; - assert(names[p]); + name = locale_variable_to_string(p); + assert(name); if (isempty(c->locale[p])) { - l = strv_env_unset(l, names[p]); + l = strv_env_unset(l, name); continue; } - if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) + if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) return -ENOMEM; u = strv_env_set(l, t); @@ -327,30 +295,33 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { assert(bus); - l_unset = new0(char*, _LOCALE_MAX); + l_unset = new0(char*, _VARIABLE_LC_MAX); if (!l_unset) return -ENOMEM; - l_set = new0(char*, _LOCALE_MAX); + l_set = new0(char*, _VARIABLE_LC_MAX); if (!l_set) return -ENOMEM; - for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); + for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name; + + name = locale_variable_to_string(p); + assert(name); if (isempty(c->locale[p])) - l_unset[c_set++] = (char*) names[p]; + l_unset[c_set++] = (char*) name; else { char *s; - if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0) + if (asprintf(&s, "%s=%s", name, c->locale[p]) < 0) return -ENOMEM; l_set[c_unset++] = s; } } - assert(c_set + c_unset == _LOCALE_MAX); + assert(c_set + c_unset == _VARIABLE_LC_MAX); r = sd_bus_message_new_method_call(bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -858,17 +829,21 @@ static int property_get_locale( _cleanup_strv_free_ char **l = NULL; int p, q; - l = new0(char*, _LOCALE_MAX+1); + l = new0(char*, _VARIABLE_LC_MAX+1); if (!l) return -ENOMEM; - for (p = 0, q = 0; p < _LOCALE_MAX; p++) { + for (p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) { char *t; + const char *name; + + name = locale_variable_to_string(p); + assert(name); if (isempty(c->locale[p])) continue; - if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) + if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) return -ENOMEM; l[q++] = t; @@ -884,7 +859,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er const char *lang = NULL; int interactive; bool modified = false; - bool have[_LOCALE_MAX] = {}; + bool have[_VARIABLE_LC_MAX] = {}; int p; int r; @@ -903,17 +878,21 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er STRV_FOREACH(i, l) { bool valid = false; - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { size_t k; + const char *name; - k = strlen(names[p]); - if (startswith(*i, names[p]) && + name = locale_variable_to_string(p); + assert(name); + + k = strlen(name); + if (startswith(*i, name) && (*i)[k] == '=' && locale_is_valid((*i) + k + 1)) { valid = true; have[p] = true; - if (p == LOCALE_LANG) + if (p == VARIABLE_LANG) lang = (*i) + k + 1; if (!streq_ptr(*i + k + 1, c->locale[p])) @@ -929,7 +908,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* If LANG was specified, but not LANGUAGE, check if we should * set it based on the language fallback table. */ - if (have[LOCALE_LANG] && !have[LOCALE_LANGUAGE]) { + if (have[VARIABLE_LANG] && !have[VARIABLE_LANGUAGE]) { _cleanup_free_ char *language = NULL; assert(lang); @@ -937,12 +916,12 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er (void) find_language_fallback(lang, &language); if (language) { log_debug("Converted LANG=%s to LANGUAGE=%s", lang, language); - if (!streq_ptr(language, c->locale[LOCALE_LANGUAGE])) { + if (!streq_ptr(language, c->locale[VARIABLE_LANGUAGE])) { r = strv_extendf(&l, "LANGUAGE=%s", language); if (r < 0) return r; - have[LOCALE_LANGUAGE] = true; + have[VARIABLE_LANGUAGE] = true; modified = true; } } @@ -950,7 +929,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* Check whether a variable is unset */ if (!modified) - for (p = 0; p < _LOCALE_MAX; p++) + for (p = 0; p < _VARIABLE_LC_MAX; p++) if (!isempty(c->locale[p]) && !have[p]) { modified = true; break; @@ -974,11 +953,15 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ STRV_FOREACH(i, l) - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { size_t k; + const char *name; + + name = locale_variable_to_string(p); + assert(name); - k = strlen(names[p]); - if (startswith(*i, names[p]) && (*i)[k] == '=') { + k = strlen(name); + if (startswith(*i, name) && (*i)[k] == '=') { r = free_and_strdup(&c->locale[p], *i + k + 1); if (r < 0) return r; @@ -986,7 +969,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er } } - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { if (have[p]) continue; -- cgit v1.2.3-54-g00ecf From 4897d1dc0f00f1571b0cc78ec4a20cd78c6c3ade Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 26 May 2016 13:35:20 -0400 Subject: localed: split out keymap parsing to a separate file This way the dbus and management logic is seperated from the business logic and we can write test cases for the mapping functionality. --- Makefile.am | 5 +- src/locale/keymap-util.c | 684 ++++++++++++++++++++++++++++++++++++++++++++ src/locale/keymap-util.h | 45 +++ src/locale/localed.c | 725 +++-------------------------------------------- 4 files changed, 772 insertions(+), 687 deletions(-) create mode 100644 src/locale/keymap-util.c create mode 100644 src/locale/keymap-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c31c30c051..4ff39987ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -213,6 +213,7 @@ AM_CPPFLAGS = \ -I $(top_srcdir)/src/shared \ -I $(top_builddir)/src/shared \ -I $(top_srcdir)/src/network \ + -I $(top_srcdir)/src/locale \ -I $(top_srcdir)/src/login \ -I $(top_srcdir)/src/journal \ -I $(top_builddir)/src/journal \ @@ -4741,7 +4742,9 @@ BUSNAMES_TARGET_WANTS += \ # ------------------------------------------------------------------------------ if ENABLE_LOCALED systemd_localed_SOURCES = \ - src/locale/localed.c + src/locale/localed.c \ + src/locale/keymap-util.c \ + src/locale/keymap-util.h systemd_localed_LDADD = \ libshared.la \ diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c new file mode 100644 index 0000000000..1827014b89 --- /dev/null +++ b/src/locale/keymap-util.c @@ -0,0 +1,684 @@ +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2013 Kay Sievers + + 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 . +***/ + +#include +#include +#include + +#include "def.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio-label.h" +#include "fileio.h" +#include "keymap-util.h" +#include "locale-util.h" +#include "macro.h" +#include "mkdir.h" +#include "string-util.h" +#include "strv.h" + +static bool startswith_comma(const char *s, const char *prefix) { + const char *t; + + return s && (t = startswith(s, prefix)) && (*t == ','); +} + +static const char* strnulldash(const char *s) { + return isempty(s) || streq(s, "-") ? NULL : s; +} + +static void context_free_x11(Context *c) { + c->x11_layout = mfree(c->x11_layout); + c->x11_options = mfree(c->x11_options); + c->x11_model = mfree(c->x11_model); + c->x11_variant = mfree(c->x11_variant); +} + +static void context_free_vconsole(Context *c) { + c->vc_keymap = mfree(c->vc_keymap); + c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); +} + +static void context_free_locale(Context *c) { + int p; + + for (p = 0; p < _VARIABLE_LC_MAX; p++) + c->locale[p] = mfree(c->locale[p]); +} + +void context_free(Context *c) { + context_free_locale(c); + context_free_x11(c); + context_free_vconsole(c); +}; + +void locale_simplify(Context *c) { + int p; + + for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) + if (isempty(c->locale[p]) || streq_ptr(c->locale[VARIABLE_LANG], c->locale[p])) + c->locale[p] = mfree(c->locale[p]); +} + +static int locale_read_data(Context *c) { + int r; + + context_free_locale(c); + + r = parse_env_file("/etc/locale.conf", NEWLINE, + "LANG", &c->locale[VARIABLE_LANG], + "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], + "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], + "LC_TIME", &c->locale[VARIABLE_LC_TIME], + "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], + "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], + "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], + "LC_NAME", &c->locale[VARIABLE_LC_NAME], + "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r == -ENOENT) { + int p; + + /* Fill in what we got passed from systemd. */ + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name; + + name = locale_variable_to_string(p); + assert(name); + + r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); + if (r < 0) + return r; + } + + r = 0; + } + + locale_simplify(c); + return r; +} + +static int vconsole_read_data(Context *c) { + int r; + + context_free_vconsole(c); + + r = parse_env_file("/etc/vconsole.conf", NEWLINE, + "KEYMAP", &c->vc_keymap, + "KEYMAP_TOGGLE", &c->vc_keymap_toggle, + NULL); + + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static int x11_read_data(Context *c) { + _cleanup_fclose_ FILE *f; + char line[LINE_MAX]; + bool in_section = false; + int r; + + context_free_x11(c); + + f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); + if (!f) + return errno == ENOENT ? 0 : -errno; + + while (fgets(line, sizeof(line), f)) { + char *l; + + char_array_0(line); + l = strstrip(line); + + if (l[0] == 0 || l[0] == '#') + continue; + + if (in_section && first_word(l, "Option")) { + _cleanup_strv_free_ char **a = NULL; + + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return r; + + if (strv_length(a) == 3) { + char **p = NULL; + + if (streq(a[1], "XkbLayout")) + p = &c->x11_layout; + else if (streq(a[1], "XkbModel")) + p = &c->x11_model; + else if (streq(a[1], "XkbVariant")) + p = &c->x11_variant; + else if (streq(a[1], "XkbOptions")) + p = &c->x11_options; + + if (p) { + free(*p); + *p = a[2]; + a[2] = NULL; + } + } + + } else if (!in_section && first_word(l, "Section")) { + _cleanup_strv_free_ char **a = NULL; + + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return -ENOMEM; + + if (strv_length(a) == 2 && streq(a[1], "InputClass")) + in_section = true; + + } else if (in_section && first_word(l, "EndSection")) + in_section = false; + } + + return 0; +} + +int context_read_data(Context *c) { + int r, q, p; + + r = locale_read_data(c); + q = vconsole_read_data(c); + p = x11_read_data(c); + + return r < 0 ? r : q < 0 ? q : p; +} + +int locale_write_data(Context *c, char ***settings) { + int r, p; + _cleanup_strv_free_ char **l = NULL; + + /* Set values will be returned as strv in *settings on success. */ + + r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + _cleanup_free_ char *t = NULL; + char **u; + const char *name; + + name = locale_variable_to_string(p); + assert(name); + + if (isempty(c->locale[p])) { + l = strv_env_unset(l, name); + continue; + } + + if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) + return -ENOMEM; + + u = strv_env_set(l, t); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (strv_isempty(l)) { + if (unlink("/etc/locale.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file_label("/etc/locale.conf", l); + if (r < 0) + return r; + + *settings = l; + l = NULL; + return 0; +} + +int vconsole_write_data(Context *c) { + int r; + _cleanup_strv_free_ char **l = NULL; + + r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + if (isempty(c->vc_keymap)) + l = strv_env_unset(l, "KEYMAP"); + else { + _cleanup_free_ char *s = NULL; + char **u; + + s = strappend("KEYMAP=", c->vc_keymap); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (isempty(c->vc_keymap_toggle)) + l = strv_env_unset(l, "KEYMAP_TOGGLE"); + else { + _cleanup_free_ char *s = NULL; + char **u; + + s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (strv_isempty(l)) { + if (unlink("/etc/vconsole.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + return write_env_file_label("/etc/vconsole.conf", l); +} + +int x11_write_data(Context *c) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *temp_path = NULL; + int r; + + if (isempty(c->x11_layout) && + isempty(c->x11_model) && + isempty(c->x11_variant) && + isempty(c->x11_options)) { + + if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + mkdir_p_label("/etc/X11/xorg.conf.d", 0755); + + r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" + "# manually too freely.\n" + "Section \"InputClass\"\n" + " Identifier \"system-keyboard\"\n" + " MatchIsKeyboard \"on\"\n", f); + + if (!isempty(c->x11_layout)) + fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); + + if (!isempty(c->x11_model)) + fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); + + if (!isempty(c->x11_variant)) + fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); + + if (!isempty(c->x11_options)) + fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); + + fputs("EndSection\n", f); + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); + + if (temp_path) + (void) unlink(temp_path); + + return r; +} + +static int read_next_mapping(const char* filename, + unsigned min_fields, unsigned max_fields, + FILE *f, unsigned *n, char ***a) { + assert(f); + assert(n); + assert(a); + + for (;;) { + char line[LINE_MAX]; + char *l, **b; + int r; + size_t length; + + errno = 0; + if (!fgets(line, sizeof(line), f)) { + + if (ferror(f)) + return errno > 0 ? -errno : -EIO; + + return 0; + } + + (*n)++; + + l = strstrip(line); + if (l[0] == 0 || l[0] == '#') + continue; + + r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return r; + + length = strv_length(b); + if (length < min_fields || length > max_fields) { + log_error("Invalid line %s:%u, ignoring.", filename, *n); + strv_free(b); + continue; + + } + + *a = b; + return 1; + } +} + +int vconsole_convert_to_x11(Context *c) { + bool modified = false; + + if (isempty(c->vc_keymap)) { + + modified = + !isempty(c->x11_layout) || + !isempty(c->x11_model) || + !isempty(c->x11_variant) || + !isempty(c->x11_options); + + context_free_x11(c); + } else { + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + int r; + + r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + if (!streq(c->vc_keymap, a[0])) + continue; + + if (!streq_ptr(c->x11_layout, strnulldash(a[1])) || + !streq_ptr(c->x11_model, strnulldash(a[2])) || + !streq_ptr(c->x11_variant, strnulldash(a[3])) || + !streq_ptr(c->x11_options, strnulldash(a[4]))) { + + if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || + free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || + free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || + free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) + return -ENOMEM; + + modified = true; + } + + break; + } + } + + if (modified) + log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", + strempty(c->x11_layout), + strempty(c->x11_model), + strempty(c->x11_variant), + strempty(c->x11_options)); + + else + log_debug("X11 keyboard layout was not modified."); + + return modified; +} + +int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + + if (x11_variant) + n = strjoin(x11_layout, "-", x11_variant, NULL); + else + n = strdup(x11_layout); + if (!n) + return -ENOMEM; + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; + bool uncompressed; + + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; + + uncompressed = access(p, F_OK) == 0; + if (uncompressed || access(pz, F_OK) == 0) { + log_debug("Found converted keymap %s at %s", + n, uncompressed ? p : pz); + + *new_keymap = n; + n = NULL; + return 1; + } + } + + return 0; +} + +static int find_legacy_keymap(Context *c, char **new_keymap) { + _cleanup_fclose_ FILE *f; + unsigned n = 0; + unsigned best_matching = 0; + int r; + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; + + r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + /* Determine how well matching this entry is */ + if (streq_ptr(c->x11_layout, a[1])) + /* If we got an exact match, this is best */ + matching = 10; + else { + /* We have multiple X layouts, look for an + * entry that matches our key with everything + * but the first layout stripped off. */ + if (startswith_comma(c->x11_layout, a[1])) + matching = 5; + else { + char *x; + + /* If that didn't work, strip off the + * other layouts from the entry, too */ + x = strndupa(a[1], strcspn(a[1], ",")); + if (startswith_comma(c->x11_layout, x)) + matching = 1; + } + } + + if (matching > 0) { + if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) { + matching++; + + if (streq_ptr(c->x11_variant, a[3])) { + matching++; + + if (streq_ptr(c->x11_options, a[4])) + matching++; + } + } + } + + /* The best matching entry so far, then let's save that */ + if (matching >= MAX(best_matching, 1u)) { + log_debug("Found legacy keymap %s with score %u", + a[0], matching); + + if (matching > best_matching) { + best_matching = matching; + + r = free_and_strdup(new_keymap, a[0]); + if (r < 0) + return r; + } + } + } + + if (best_matching < 10 && c->x11_layout) { + /* The best match is only the first part of the X11 + * keymap. Check if we have a converted map which + * matches just the first layout. + */ + char *l, *v = NULL, *converted; + + l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); + if (c->x11_variant) + v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); + r = find_converted_keymap(l, v, &converted); + if (r < 0) + return r; + if (r > 0) { + free(*new_keymap); + *new_keymap = converted; + } + } + + return 0; +} + +int find_language_fallback(const char *lang, char **language) { + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + + assert(language); + + f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + int r; + + r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a); + if (r <= 0) + return r; + + if (streq(lang, a[0])) { + assert(strv_length(a) == 2); + *language = a[1]; + a[1] = NULL; + return 1; + } + } + + assert_not_reached("should not be here"); +} + +int x11_convert_to_vconsole(Context *c) { + bool modified = false; + + if (isempty(c->x11_layout)) { + + modified = + !isempty(c->vc_keymap) || + !isempty(c->vc_keymap_toggle); + + context_free_x11(c); + } else { + char *new_keymap = NULL; + int r; + + r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); + if (r < 0) + return r; + else if (r == 0) { + r = find_legacy_keymap(c, &new_keymap); + if (r < 0) + return r; + } + + if (!streq_ptr(c->vc_keymap, new_keymap)) { + free(c->vc_keymap); + c->vc_keymap = new_keymap; + c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); + modified = true; + } else + free(new_keymap); + } + + if (modified) + log_info("Changing virtual console keymap to '%s' toggle '%s'", + strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); + else + log_debug("Virtual console keymap was not modified."); + + return modified; +} diff --git a/src/locale/keymap-util.h b/src/locale/keymap-util.h new file mode 100644 index 0000000000..244dd62563 --- /dev/null +++ b/src/locale/keymap-util.h @@ -0,0 +1,45 @@ +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2013 Kay Sievers + + 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 . +***/ + +#include "locale-util.h" + +typedef struct Context { + char *locale[_VARIABLE_LC_MAX]; + + char *x11_layout; + char *x11_model; + char *x11_variant; + char *x11_options; + + char *vc_keymap; + char *vc_keymap_toggle; +} Context; + +int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap); +int find_language_fallback(const char *lang, char **language); + +int context_read_data(Context *c); +void context_free(Context *c); +int vconsole_convert_to_x11(Context *c); +int vconsole_write_data(Context *c); +int x11_convert_to_vconsole(Context *c); +int x11_write_data(Context *c); +void locale_simplify(Context *c); +int locale_write_data(Context *c, char ***settings); diff --git a/src/locale/localed.c b/src/locale/localed.c index 4995cbc23d..298f176e40 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -34,256 +34,16 @@ #include "bus-message.h" #include "bus-util.h" #include "def.h" -#include "env-util.h" -#include "fd-util.h" -#include "fileio-label.h" -#include "fileio.h" +#include "keymap-util.h" #include "locale-util.h" -#include "mkdir.h" +#include "macro.h" #include "path-util.h" #include "selinux-util.h" +#include "string-util.h" #include "strv.h" #include "user-util.h" -#include "util.h" -typedef struct Context { - char *locale[_VARIABLE_LC_MAX]; - - char *x11_layout; - char *x11_model; - char *x11_variant; - char *x11_options; - - char *vc_keymap; - char *vc_keymap_toggle; - - Hashmap *polkit_registry; -} Context; - -static bool startswith_comma(const char *s, const char *prefix) { - const char *t; - - return s && (t = startswith(s, prefix)) && (*t == ','); -} - -static void context_free_x11(Context *c) { - c->x11_layout = mfree(c->x11_layout); - c->x11_options = mfree(c->x11_options); - c->x11_model = mfree(c->x11_model); - c->x11_variant = mfree(c->x11_variant); -} - -static void context_free_vconsole(Context *c) { - c->vc_keymap = mfree(c->vc_keymap); - c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); -} - -static void context_free_locale(Context *c) { - int p; - - for (p = 0; p < _VARIABLE_LC_MAX; p++) - c->locale[p] = mfree(c->locale[p]); -} - -static void context_free(Context *c) { - context_free_locale(c); - context_free_x11(c); - context_free_vconsole(c); - - bus_verify_polkit_async_registry_free(c->polkit_registry); -}; - -static void locale_simplify(Context *c) { - int p; - - for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) - if (isempty(c->locale[p]) || streq_ptr(c->locale[VARIABLE_LANG], c->locale[p])) - c->locale[p] = mfree(c->locale[p]); -} - -static int locale_read_data(Context *c) { - int r; - - context_free_locale(c); - - r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &c->locale[VARIABLE_LANG], - "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], - "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], - "LC_TIME", &c->locale[VARIABLE_LC_TIME], - "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], - "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], - "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], - "LC_NAME", &c->locale[VARIABLE_LC_NAME], - "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r == -ENOENT) { - int p; - - /* Fill in what we got passed from systemd. */ - for (p = 0; p < _VARIABLE_LC_MAX; p++) { - const char *name; - - name = locale_variable_to_string(p); - assert(name); - - r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); - if (r < 0) - return r; - } - - r = 0; - } - - locale_simplify(c); - return r; -} - -static int vconsole_read_data(Context *c) { - int r; - - context_free_vconsole(c); - - r = parse_env_file("/etc/vconsole.conf", NEWLINE, - "KEYMAP", &c->vc_keymap, - "KEYMAP_TOGGLE", &c->vc_keymap_toggle, - NULL); - - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static int x11_read_data(Context *c) { - _cleanup_fclose_ FILE *f; - char line[LINE_MAX]; - bool in_section = false; - int r; - - context_free_x11(c); - - f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); - if (!f) - return errno == ENOENT ? 0 : -errno; - - while (fgets(line, sizeof(line), f)) { - char *l; - - char_array_0(line); - l = strstrip(line); - - if (l[0] == 0 || l[0] == '#') - continue; - - if (in_section && first_word(l, "Option")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return r; - - if (strv_length(a) == 3) { - char **p = NULL; - - if (streq(a[1], "XkbLayout")) - p = &c->x11_layout; - else if (streq(a[1], "XkbModel")) - p = &c->x11_model; - else if (streq(a[1], "XkbVariant")) - p = &c->x11_variant; - else if (streq(a[1], "XkbOptions")) - p = &c->x11_options; - - if (p) { - free(*p); - *p = a[2]; - a[2] = NULL; - } - } - - } else if (!in_section && first_word(l, "Section")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return -ENOMEM; - - if (strv_length(a) == 2 && streq(a[1], "InputClass")) - in_section = true; - - } else if (in_section && first_word(l, "EndSection")) - in_section = false; - } - - return 0; -} - -static int context_read_data(Context *c) { - int r, q, p; - - r = locale_read_data(c); - q = vconsole_read_data(c); - p = x11_read_data(c); - - return r < 0 ? r : q < 0 ? q : p; -} - -static int locale_write_data(Context *c, char ***settings) { - int r, p; - _cleanup_strv_free_ char **l = NULL; - - /* Set values will be returned as strv in *settings on success. */ - - r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 0; p < _VARIABLE_LC_MAX; p++) { - _cleanup_free_ char *t = NULL; - char **u; - const char *name; - - name = locale_variable_to_string(p); - assert(name); - - if (isempty(c->locale[p])) { - l = strv_env_unset(l, name); - continue; - } - - if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) - return -ENOMEM; - - u = strv_env_set(l, t); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/locale.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file_label("/etc/locale.conf", l); - if (r < 0) - return r; - - *settings = l; - l = NULL; - return 0; -} +static Hashmap *polkit_registry = NULL; static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_free_ char **l_unset = NULL; @@ -345,124 +105,6 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { return 0; } -static int vconsole_write_data(Context *c) { - int r; - _cleanup_strv_free_ char **l = NULL; - - r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - if (isempty(c->vc_keymap)) - l = strv_env_unset(l, "KEYMAP"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP=", c->vc_keymap); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (isempty(c->vc_keymap_toggle)) - l = strv_env_unset(l, "KEYMAP_TOGGLE"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/vconsole.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - return write_env_file_label("/etc/vconsole.conf", l); -} - -static int x11_write_data(Context *c) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *temp_path = NULL; - int r; - - if (isempty(c->x11_layout) && - isempty(c->x11_model) && - isempty(c->x11_variant) && - isempty(c->x11_options)) { - - if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - mkdir_p_label("/etc/X11/xorg.conf.d", 0755); - - r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); - if (r < 0) - return r; - - fchmod(fileno(f), 0644); - - fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" - "# manually too freely.\n" - "Section \"InputClass\"\n" - " Identifier \"system-keyboard\"\n" - " MatchIsKeyboard \"on\"\n", f); - - if (!isempty(c->x11_layout)) - fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); - - if (!isempty(c->x11_model)) - fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); - - if (!isempty(c->x11_variant)) - fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); - - if (!isempty(c->x11_options)) - fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); - - fputs("EndSection\n", f); - - r = fflush_and_check(f); - if (r < 0) - goto fail; - - if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { - r = -errno; - goto fail; - } - - return 0; - -fail: - (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); - - if (temp_path) - (void) unlink(temp_path); - - return r; -} - static int vconsole_reload(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -483,337 +125,48 @@ static int vconsole_reload(sd_bus *bus) { return r; } -static const char* strnulldash(const char *s) { - return isempty(s) || streq(s, "-") ? NULL : s; -} - -static int read_next_mapping(const char* filename, - unsigned min_fields, unsigned max_fields, - FILE *f, unsigned *n, char ***a) { - assert(f); - assert(n); - assert(a); - - for (;;) { - char line[LINE_MAX]; - char *l, **b; - int r; - size_t length; - - errno = 0; - if (!fgets(line, sizeof(line), f)) { - - if (ferror(f)) - return errno > 0 ? -errno : -EIO; - - return 0; - } - - (*n)++; - - l = strstrip(line); - if (l[0] == 0 || l[0] == '#') - continue; - - r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return r; - - length = strv_length(b); - if (length < min_fields || length > max_fields) { - log_error("Invalid line %s:%u, ignoring.", filename, *n); - strv_free(b); - continue; - - } - - *a = b; - return 1; - } -} - -static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { - bool modified = false; - - assert(bus); - - if (isempty(c->vc_keymap)) { - - modified = - !isempty(c->x11_layout) || - !isempty(c->x11_model) || - !isempty(c->x11_variant) || - !isempty(c->x11_options); - - context_free_x11(c); - } else { - _cleanup_fclose_ FILE *f = NULL; - unsigned n = 0; - - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - _cleanup_strv_free_ char **a = NULL; - int r; - - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); - if (r < 0) - return r; - if (r == 0) - break; - - if (!streq(c->vc_keymap, a[0])) - continue; - - if (!streq_ptr(c->x11_layout, strnulldash(a[1])) || - !streq_ptr(c->x11_model, strnulldash(a[2])) || - !streq_ptr(c->x11_variant, strnulldash(a[3])) || - !streq_ptr(c->x11_options, strnulldash(a[4]))) { - - if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || - free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || - free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || - free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) - return -ENOMEM; - - modified = true; - } - - break; - } - } - - if (modified) { - int r; - - r = x11_write_data(c); - if (r < 0) - return log_error_errno(r, "Failed to set X11 keyboard layout: %m"); - - log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", - strempty(c->x11_layout), - strempty(c->x11_model), - strempty(c->x11_variant), - strempty(c->x11_options)); - - sd_bus_emit_properties_changed(bus, - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); - } else - log_debug("X11 keyboard layout was not modified."); - - return 0; -} - -static int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { - const char *dir; - _cleanup_free_ char *n; - - if (x11_variant) - n = strjoin(x11_layout, "-", x11_variant, NULL); - else - n = strdup(x11_layout); - if (!n) - return -ENOMEM; - - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { - _cleanup_free_ char *p = NULL, *pz = NULL; - bool uncompressed; - - p = strjoin(dir, "xkb/", n, ".map", NULL); - pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); - if (!p || !pz) - return -ENOMEM; - - uncompressed = access(p, F_OK) == 0; - if (uncompressed || access(pz, F_OK) == 0) { - log_debug("Found converted keymap %s at %s", - n, uncompressed ? p : pz); - - *new_keymap = n; - n = NULL; - return 1; - } - } - - return 0; -} - -static int find_legacy_keymap(Context *c, char **new_keymap) { - _cleanup_fclose_ FILE *f; - unsigned n = 0; - unsigned best_matching = 0; +static int vconsole_convert_to_x11_and_emit(Context *c, sd_bus *bus) { int r; - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - _cleanup_strv_free_ char **a = NULL; - unsigned matching = 0; - - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); - if (r < 0) - return r; - if (r == 0) - break; - - /* Determine how well matching this entry is */ - if (streq_ptr(c->x11_layout, a[1])) - /* If we got an exact match, this is best */ - matching = 10; - else { - /* We have multiple X layouts, look for an - * entry that matches our key with everything - * but the first layout stripped off. */ - if (startswith_comma(c->x11_layout, a[1])) - matching = 5; - else { - char *x; - - /* If that didn't work, strip off the - * other layouts from the entry, too */ - x = strndupa(a[1], strcspn(a[1], ",")); - if (startswith_comma(c->x11_layout, x)) - matching = 1; - } - } - - if (matching > 0) { - if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) { - matching++; - - if (streq_ptr(c->x11_variant, a[3])) { - matching++; - - if (streq_ptr(c->x11_options, a[4])) - matching++; - } - } - } - - /* The best matching entry so far, then let's save that */ - if (matching >= MAX(best_matching, 1u)) { - log_debug("Found legacy keymap %s with score %u", - a[0], matching); - - if (matching > best_matching) { - best_matching = matching; - - r = free_and_strdup(new_keymap, a[0]); - if (r < 0) - return r; - } - } - } - - if (best_matching < 10 && c->x11_layout) { - /* The best match is only the first part of the X11 - * keymap. Check if we have a converted map which - * matches just the first layout. - */ - char *l, *v = NULL, *converted; - - l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); - if (c->x11_variant) - v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); - r = find_converted_keymap(l, v, &converted); - if (r < 0) - return r; - if (r > 0) { - free(*new_keymap); - *new_keymap = converted; - } - } - - return 0; -} - -static int find_language_fallback(const char *lang, char **language) { - _cleanup_fclose_ FILE *f = NULL; - unsigned n = 0; - - assert(language); - - f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re"); - if (!f) - return -errno; + assert(bus); - for (;;) { - _cleanup_strv_free_ char **a = NULL; - int r; + r = vconsole_convert_to_x11(c); + if (r <= 0) + return r; - r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a); - if (r <= 0) - return r; + /* modified */ + r = x11_write_data(c); + if (r < 0) + return log_error_errno(r, "Failed to write X11 keyboard layout: %m"); - if (streq(lang, a[0])) { - assert(strv_length(a) == 2); - *language = a[1]; - a[1] = NULL; - return 1; - } - } + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); - assert_not_reached("should not be here"); + return 1; } -static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { - bool modified = false; +static int x11_convert_to_vconsole_and_emit(Context *c, sd_bus *bus) { int r; assert(bus); - if (isempty(c->x11_layout)) { - - modified = - !isempty(c->vc_keymap) || - !isempty(c->vc_keymap_toggle); - - context_free_x11(c); - } else { - char *new_keymap = NULL; - - r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); - if (r < 0) - return r; - else if (r == 0) { - r = find_legacy_keymap(c, &new_keymap); - if (r < 0) - return r; - } - - if (!streq_ptr(c->vc_keymap, new_keymap)) { - free(c->vc_keymap); - c->vc_keymap = new_keymap; - c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); - modified = true; - } else - free(new_keymap); - } - - if (modified) { - r = vconsole_write_data(c); - if (r < 0) - log_error_errno(r, "Failed to set virtual console keymap: %m"); - - log_info("Changed virtual console keymap to '%s' toggle '%s'", - strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); + r = x11_convert_to_vconsole(c); + if (r <= 0) + return r; - sd_bus_emit_properties_changed(bus, - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "VConsoleKeymap", "VConsoleKeymapToggle", NULL); + /* modified */ + r = vconsole_write_data(c); + if (r < 0) + log_error_errno(r, "Failed to save virtual console keymap: %m"); - return vconsole_reload(bus); - } else - log_debug("Virtual console keymap was not modified."); + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "VConsoleKeymap", "VConsoleKeymapToggle", NULL); - return 0; + return vconsole_reload(bus); } static int property_get_locale( @@ -945,7 +298,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -1036,7 +389,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -1067,7 +420,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro "VConsoleKeymap", "VConsoleKeymapToggle", NULL); if (convert) { - r = vconsole_convert_to_x11(c, sd_bus_message_get_bus(m)); + r = vconsole_convert_to_x11_and_emit(c, sd_bus_message_get_bus(m)); if (r < 0) log_error_errno(r, "Failed to convert keymap data: %m"); } @@ -1212,7 +565,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -1255,7 +608,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); if (convert) { - r = x11_convert_to_vconsole(c, sd_bus_message_get_bus(m)); + r = x11_convert_to_vconsole_and_emit(c, sd_bus_message_get_bus(m)); if (r < 0) log_error_errno(r, "Failed to convert keymap data: %m"); } @@ -1347,11 +700,11 @@ int main(int argc, char *argv[]) { } r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL); - if (r < 0) { + if (r < 0) log_error_errno(r, "Failed to run event loop: %m"); - goto finish; - } finish: + bus_verify_polkit_async_registry_free(polkit_registry); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From aa63b56f5f56c9aa9b0ed00b4213c258c629c614 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 17:53:00 -0400 Subject: keymap-util: add tests and fix one small bug When converting an empty x11 variant, we would not delete vconsole mapping properly. find_legacy_keymap() is made non-static. I think it's important to be able to test it. In principle we could also test it through the higher-level interface of x11_convert_to_vconsole, but x11_convert_to_vconsole also uses find_converted_keymap, and it's better to test at this lower level. Note that find_legacy_keymap might be a bit of a misnomer, because we'd probably want to keep kbd-model-map even if the "legacy" layouts went away. So we might want to change this name, but I'm leaving that for another commit. --- .gitignore | 1 + Makefile.am | 12 +++ src/locale/keymap-util.c | 5 +- src/locale/keymap-util.h | 1 + src/locale/test-keymap-util.c | 216 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 src/locale/test-keymap-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 091b400182..f7db68b4a6 100644 --- a/.gitignore +++ b/.gitignore @@ -217,6 +217,7 @@ /test-journal-stream /test-journal-syslog /test-journal-verify +/test-keymap-util /test-libsystemd-sym* /test-libudev /test-libudev-sym* diff --git a/Makefile.am b/Makefile.am index 4ff39987ac..fc6f3bf6d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4782,6 +4782,18 @@ dist_pkgdata_DATA = \ src/locale/kbd-model-map \ src/locale/language-fallback-map +test_keymap_util_SOURCES = \ + src/locale/test-keymap-util.c \ + src/locale/keymap-util.c \ + src/locale/keymap-util.h + +test_keymap_util_LDADD = \ + libshared.la \ + -ldl + +tests += \ + test-keymap-util + localectl_SOURCES = \ src/locale/localectl.c diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index 1827014b89..68b80a4801 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -522,7 +522,7 @@ int find_converted_keymap(const char *x11_layout, const char *x11_variant, char return 0; } -static int find_legacy_keymap(Context *c, char **new_keymap) { +int find_legacy_keymap(Context *c, char **new_keymap) { _cleanup_fclose_ FILE *f; unsigned n = 0; unsigned best_matching = 0; @@ -617,6 +617,7 @@ int find_language_fallback(const char *lang, char **language) { _cleanup_fclose_ FILE *f = NULL; unsigned n = 0; + assert(lang); assert(language); f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re"); @@ -651,7 +652,7 @@ int x11_convert_to_vconsole(Context *c) { !isempty(c->vc_keymap) || !isempty(c->vc_keymap_toggle); - context_free_x11(c); + context_free_vconsole(c); } else { char *new_keymap = NULL; int r; diff --git a/src/locale/keymap-util.h b/src/locale/keymap-util.h index 244dd62563..20ef2a4a34 100644 --- a/src/locale/keymap-util.h +++ b/src/locale/keymap-util.h @@ -33,6 +33,7 @@ typedef struct Context { } Context; int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap); +int find_legacy_keymap(Context *c, char **new_keymap); int find_language_fallback(const char *lang, char **language); int context_read_data(Context *c); diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c new file mode 100644 index 0000000000..680aae6228 --- /dev/null +++ b/src/locale/test-keymap-util.c @@ -0,0 +1,216 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + 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 . +***/ + +#include "alloc-util.h" +#include "keymap-util.h" +#include "log.h" +#include "string-util.h" + +static void test_find_language_fallback(void) { + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + int r; + + log_info("/* %s */", __func__); + + r = find_language_fallback("foobar", &ans); + if (r == -ENOENT) { + log_info_errno(r, "Skipping language fallback tests: %m"); + return; + } + assert_se(r == 0); + assert_se(ans == NULL); + + assert_se(find_language_fallback("csb", &ans) == 0); + assert_se(ans == NULL); + + assert_se(find_language_fallback("csb_PL", &ans) == 1); + assert_se(streq(ans, "csb:pl")); + + assert_se(find_language_fallback("szl_PL", &ans2) == 1); + assert_se(streq(ans2, "szl:pl")); +} + +static void test_find_converted_keymap(void) { + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + int r; + + log_info("/* %s */", __func__); + + assert_se(find_converted_keymap("pl", "foobar", &ans) == 0); + assert_se(ans == NULL); + + r = find_converted_keymap("pl", NULL, &ans); + if (r == 0) { + log_info_errno(r, "Skipping find_converted_keymap tests: %m"); + return; + } + assert_se(r == 1); + assert_se(streq(ans, "pl")); + + assert_se(find_converted_keymap("pl", "dvorak", &ans) == 1); + assert_se(streq(ans, "pl-dvorak")); +} + +static void test_find_legacy_keymap(void) { + Context c = {}; + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + int r; + + log_info("/* %s */", __func__); + + c.x11_layout = (char*) "foobar"; + r = find_legacy_keymap(&c, &ans); + if (r == -ENOENT) { + log_info_errno(r, "Skipping test_legacy_keymap tests: %m"); + return; + } + assert_se(r == 0); + assert_se(ans == NULL); + + c.x11_layout = (char*) "pl"; + assert_se(find_legacy_keymap(&c, &ans) == 0); /* should this be 1? */ + assert_se(streq(ans, "pl2")); + + c.x11_layout = (char*) "pl,ru"; + assert_se(find_legacy_keymap(&c, &ans2) == 0); /* should this be 1? */ + assert_se(streq(ans, "pl2")); +} + +static void test_vconsole_convert_to_x11(void) { + _cleanup_(context_free) Context c = {}; + + log_info("/* %s */", __func__); + + log_info("/* test emptying first (:) */"); + assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0); + assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0); + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(c.x11_layout == NULL); + assert_se(c.x11_variant == NULL); + + log_info("/* test emptying second (:) */"); + + assert_se(vconsole_convert_to_x11(&c) == 0); + assert_se(c.x11_layout == NULL); + assert_se(c.x11_variant == NULL); + + log_info("/* test without variant, new mapping (es:) */"); + assert_se(free_and_strdup(&c.vc_keymap, "es") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "es")); + assert_se(c.x11_variant == NULL); + + log_info("/* test with known variant, new mapping (es:dvorak) */"); + assert_se(free_and_strdup(&c.vc_keymap, "es-dvorak") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 0); // FIXME + assert_se(streq(c.x11_layout, "es")); + assert_se(c.x11_variant == NULL); // FIXME: "dvorak" + + log_info("/* test with old mapping (fr:latin9) */"); + assert_se(free_and_strdup(&c.vc_keymap, "fr-latin9") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "fr")); + assert_se(streq(c.x11_variant, "latin9")); + + log_info("/* test with a compound mapping (ru,us) */"); + assert_se(free_and_strdup(&c.vc_keymap, "ru") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "ru,us")); + assert_se(c.x11_variant == NULL); + + log_info("/* test with a simple mapping (us) */"); + assert_se(free_and_strdup(&c.vc_keymap, "us") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "us")); + assert_se(c.x11_variant == NULL); +} + +static void test_x11_convert_to_vconsole(void) { + _cleanup_(context_free) Context c = {}; + + log_info("/* %s */", __func__); + + log_info("/* test emptying first (:) */"); + assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0); + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(c.vc_keymap == NULL); + + log_info("/* test emptying second (:) */"); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(c.vc_keymap == NULL); + + log_info("/* test without variant, new mapping (es:) */"); + assert_se(free_and_strdup(&c.x11_layout, "es") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "es")); + + log_info("/* test with unknown variant, new mapping (es:foobar) */"); + assert_se(free_and_strdup(&c.x11_variant, "foobar") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(streq(c.vc_keymap, "es")); + + log_info("/* test with known variant, new mapping (es:dvorak) */"); + assert_se(free_and_strdup(&c.x11_variant, "dvorak") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "es-dvorak")); + + log_info("/* test with old mapping (fr:latin9) */"); + assert_se(free_and_strdup(&c.x11_layout, "fr") >= 0); + assert_se(free_and_strdup(&c.x11_variant, "latin9") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "fr-latin9")); + + log_info("/* test with a compound mapping (us,ru:) */"); + assert_se(free_and_strdup(&c.x11_layout, "us,ru") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "us")); + + log_info("/* test with a compound mapping (ru,us:) */"); + assert_se(free_and_strdup(&c.x11_layout, "ru,us") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "ru")); +} + +int main(int argc, char **argv) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_find_language_fallback(); + test_find_converted_keymap(); + test_find_legacy_keymap(); + + test_vconsole_convert_to_x11(); + test_x11_convert_to_vconsole(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From 6f3287b346fdcef4e1b5dd4aaeae1ee47e49e94d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 22 May 2016 22:25:09 -0400 Subject: localed: be more verbose when keymap conversion to X11 fails I was puzzled why "localectl set-keymap pl" does not change the X11 keymap. Output a message at notice level, becuase not converting the X11 keymap is most likely an error. We usually do not output non-debug messages from "library" code, but this isn't really library code, it's split out to a separate file only to allow it to be called from tests. (pl is not converted because we only have a mapping for pl2. This is intentional, even though we might want to change this. In any case, the conversion code works correctly.) --- src/locale/keymap-util.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index 68b80a4801..b6cbf12c7e 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -425,10 +425,9 @@ static int read_next_mapping(const char* filename, } int vconsole_convert_to_x11(Context *c) { - bool modified = false; + int modified = -1; if (isempty(c->vc_keymap)) { - modified = !isempty(c->x11_layout) || !isempty(c->x11_model) || @@ -475,17 +474,19 @@ int vconsole_convert_to_x11(Context *c) { } } - if (modified) + if (modified > 0) log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", strempty(c->x11_layout), strempty(c->x11_model), strempty(c->x11_variant), strempty(c->x11_options)); - + else if (modified < 0) + log_notice("X11 keyboard layout was not modified: no conversion found for \"%s\".", + c->vc_keymap); else - log_debug("X11 keyboard layout was not modified."); + log_debug("X11 keyboard layout did not need to be modified."); - return modified; + return modified > 0; } int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { -- cgit v1.2.3-54-g00ecf From 5ad327dda2b863697cf5cdc0b1724aed96c5397a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 22 May 2016 22:43:12 -0400 Subject: localed: also report when we couldn't convert X11→console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the code a bit where find_converted_keymap cannot (and should not) be called with a null layout, so streq can be used instead of streq_ptr, etc. Note that the behaviour of vconsole_convert_to_x11 and x11_convert_to_vconsole is not symmetrical. When the latter cannot find a match, it simply makes the vconsole mapping empty. But vconsole_convert_to_x11 leaves the x11 layout unchanged. I don't know what the proper solution is here, so I'm just adding more verbose logging without changing the logic. --- src/locale/keymap-util.c | 19 ++++++++++++++----- src/locale/test-keymap-util.c | 4 ++-- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index b6cbf12c7e..fe29594ccc 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -35,9 +35,11 @@ #include "strv.h" static bool startswith_comma(const char *s, const char *prefix) { - const char *t; + s = startswith(s, prefix); + if (!s) + return false; - return s && (t = startswith(s, prefix)) && (*t == ','); + return *s == ','; } static const char* strnulldash(const char *s) { @@ -529,6 +531,8 @@ int find_legacy_keymap(Context *c, char **new_keymap) { unsigned best_matching = 0; int r; + assert(!isempty(c->x11_layout)); + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); if (!f) return -errno; @@ -544,7 +548,7 @@ int find_legacy_keymap(Context *c, char **new_keymap) { break; /* Determine how well matching this entry is */ - if (streq_ptr(c->x11_layout, a[1])) + if (streq(c->x11_layout, a[1])) /* If we got an exact match, this is best */ matching = 10; else { @@ -611,7 +615,7 @@ int find_legacy_keymap(Context *c, char **new_keymap) { } } - return 0; + return (bool) *new_keymap; } int find_language_fallback(const char *lang, char **language) { @@ -648,7 +652,6 @@ int x11_convert_to_vconsole(Context *c) { bool modified = false; if (isempty(c->x11_layout)) { - modified = !isempty(c->vc_keymap) || !isempty(c->vc_keymap_toggle); @@ -666,6 +669,12 @@ int x11_convert_to_vconsole(Context *c) { if (r < 0) return r; } + if (r == 0) + /* We search for layout-variant match first, but then we also look + * for anything which matches just the layout. So it's accurate to say + * that we couldn't find anything which matches the layout. */ + log_notice("No conversion to virtual console map found for \"%s\".", + c->x11_layout); if (!streq_ptr(c->vc_keymap, new_keymap)) { free(c->vc_keymap); diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c index 680aae6228..8dde764a50 100644 --- a/src/locale/test-keymap-util.c +++ b/src/locale/test-keymap-util.c @@ -84,11 +84,11 @@ static void test_find_legacy_keymap(void) { assert_se(ans == NULL); c.x11_layout = (char*) "pl"; - assert_se(find_legacy_keymap(&c, &ans) == 0); /* should this be 1? */ + assert_se(find_legacy_keymap(&c, &ans) == 1); assert_se(streq(ans, "pl2")); c.x11_layout = (char*) "pl,ru"; - assert_se(find_legacy_keymap(&c, &ans2) == 0); /* should this be 1? */ + assert_se(find_legacy_keymap(&c, &ans2) == 1); assert_se(streq(ans, "pl2")); } -- cgit v1.2.3-54-g00ecf From 03a44125b8af43df6ef8f4af63a8e48607de1a0d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 29 May 2016 22:02:57 -0400 Subject: keymap-util: also "convert" 'ru' to 'ru' As discovered by Adam Williamson in https://bugzilla.redhat.com/show_bug.cgi?id=1333998#c32, after the changes in 81fd105a5f9 we would only match compound layouts, i.e. a comma would be required after 'ru' to match. This seems wrong, and we should match single layouts like too. So 'ru', 'ru,us' now both match. startswith_comma is changed to not require a comma, i.e. check that the prefix matches until a comma or the end of the string. Note that startswith_comma is called twice. At the first site, we check that strings are not equal beforehand, so this change to startswith_comma has no effect. At the second site, it does have an effect, as described above. --- src/locale/keymap-util.c | 2 +- src/locale/test-keymap-util.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index fe29594ccc..17bef9e481 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -39,7 +39,7 @@ static bool startswith_comma(const char *s, const char *prefix) { if (!s) return false; - return *s == ','; + return *s == ',' || *s == '\0'; } static const char* strnulldash(const char *s) { diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c index 8dde764a50..1e30fa4cb0 100644 --- a/src/locale/test-keymap-util.c +++ b/src/locale/test-keymap-util.c @@ -199,6 +199,14 @@ static void test_x11_convert_to_vconsole(void) { assert_se(x11_convert_to_vconsole(&c) == 1); assert_se(streq(c.vc_keymap, "ru")); + + /* https://bugzilla.redhat.com/show_bug.cgi?id=1333998 */ + log_info("/* test with a simple new mapping (ru:) */"); + assert_se(free_and_strdup(&c.x11_layout, "ru") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(streq(c.vc_keymap, "ru")); } int main(int argc, char **argv) { -- cgit v1.2.3-54-g00ecf From b2bb19bbda8f5ab3ab497165bc52a0ef952348c4 Mon Sep 17 00:00:00 2001 From: Christian Rebischke Date: Mon, 6 Jun 2016 17:06:20 +0200 Subject: machinectl: Added stop as alias for poweroff (#3406) --- man/machinectl.xml | 7 +++---- shell-completion/bash/machinectl | 2 +- shell-completion/zsh/_machinectl | 1 + src/machine/machinectl.c | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/man/machinectl.xml b/man/machinectl.xml index 4b7f9a0391..d3891332e4 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -373,8 +373,7 @@ To interactively start a container on the command line with full access to the container's console, please invoke systemd-nspawn directly. To stop a running - container use machinectl poweroff, see - below. + container use machinectl poweroff. @@ -461,8 +460,8 @@ Power off one or more containers. This will trigger a reboot by sending SIGRTMIN+4 to the container's init process, which causes systemd-compatible init systems to shut - down cleanly. This operation does not work on containers that - do not run a + down cleanly. Use stop as alias for poweroff. + This operation does not work on containers that do not run a systemd1-compatible init system, such as sysvinit. Use terminate (see below) to immediately diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index e7829ca968..aebe48304d 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -41,7 +41,7 @@ _machinectl() { local -A VERBS=( [STANDALONE]='list list-images pull-tar pull-raw import-tar import-raw export-tar export-raw list-transfers cancel-transfer' - [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' + [MACHINES]='status show start stop login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' ) _init_completion || return diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl index 198fa28f7b..92d77109a5 100644 --- a/shell-completion/zsh/_machinectl +++ b/shell-completion/zsh/_machinectl @@ -23,6 +23,7 @@ _available_machines() { "status:Show VM/container status" "show:Show properties of one or more VMs/containers" "start:Start container as a service" + "stop:Stop container (equal to poweroff)" "login:Get a login prompt on a VM/container" "enable:Enable automatic container start at boot" "disable:Disable automatic container start at boot" diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 8e4ffa9a39..afe5026373 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2720,6 +2720,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "terminate", 2, VERB_ANY, 0, terminate_machine }, { "reboot", 2, VERB_ANY, 0, reboot_machine }, { "poweroff", 2, VERB_ANY, 0, poweroff_machine }, + { "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */ { "kill", 2, VERB_ANY, 0, kill_machine }, { "login", VERB_ANY, 2, 0, login_machine }, { "shell", VERB_ANY, VERB_ANY, 0, shell_machine }, -- cgit v1.2.3-54-g00ecf From 2817157bb705e0f3e9ad4a83246a80d026866be3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Jun 2016 21:29:14 +0200 Subject: resolved: support IPv6 DNS servers on the local link Make sure we can parse DNS server addresses that use the "zone id" syntax for local link addresses, i.e. "fe80::c256:27ff:febb:12f%wlp3s0", when reading /etc/resolv.conf. Also make sure we spit this out correctly again when writing /etc/resolv.conf and via the bus. Fixes: #3359 --- src/basic/in-addr-util.c | 85 ++++++++++++++++++++++++++++++++++++++ src/basic/in-addr-util.h | 2 + src/resolve/resolved-bus.c | 2 +- src/resolve/resolved-conf.c | 12 +++--- src/resolve/resolved-dns-scope.c | 15 ++++--- src/resolve/resolved-dns-server.c | 36 +++++++++++++--- src/resolve/resolved-dns-server.h | 7 +++- src/resolve/resolved-link-bus.c | 4 +- src/resolve/resolved-link.c | 4 +- src/resolve/resolved-manager.c | 2 +- src/resolve/resolved-resolv-conf.c | 8 ++-- src/test/test-socket-util.c | 51 +++++++++++++++++++++++ 12 files changed, 198 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 245107ebb8..e5a9daeab8 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -20,12 +20,14 @@ #include #include #include +#include #include #include #include "alloc-util.h" #include "in-addr-util.h" #include "macro.h" +#include "parse-util.h" #include "util.h" int in_addr_is_null(int family, const union in_addr_union *u) { @@ -224,6 +226,48 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { return 0; } +int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { + size_t l; + char *x; + int r; + + assert(u); + assert(ret); + + /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly + * handle IPv6 link-local addresses. */ + + if (family != AF_INET6) + goto fallback; + if (ifindex <= 0) + goto fallback; + + r = in_addr_is_link_local(family, u); + if (r < 0) + return r; + if (r == 0) + goto fallback; + + l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1; + x = new(char, l); + if (!x) + return -ENOMEM; + + errno = 0; + if (!inet_ntop(family, u, x, l)) { + free(x); + return errno > 0 ? -errno : -EINVAL; + } + + sprintf(strchr(x, 0), "%%%i", ifindex); + *ret = x; + + return 0; + +fallback: + return in_addr_to_string(family, u, ret); +} + int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { assert(s); @@ -261,6 +305,47 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re return -EINVAL; } +int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { + const char *suffix; + int r, ifi = 0; + + assert(s); + assert(family); + assert(ret); + + /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id") + * if one is found. */ + + suffix = strchr(s, '%'); + if (suffix) { + + if (ifindex) { + /* If we shall return the interface index, try to parse it */ + r = parse_ifindex(suffix + 1, &ifi); + if (r < 0) { + unsigned u; + + u = if_nametoindex(suffix + 1); + if (u <= 0) + return -errno; + + ifi = (int) u; + } + } + + s = strndupa(s, suffix - s); + } + + r = in_addr_from_string_auto(s, family, ret); + if (r < 0) + return r; + + if (ifindex) + *ifindex = ifi; + + return r; +} + unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) { assert(addr); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 17798ce816..7fdf3a15fc 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -43,8 +43,10 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); 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_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, 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); +int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex); 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); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 33f7c61557..6d4e5746f7 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1221,7 +1221,7 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex return r; if (with_ifindex) { - r = sd_bus_message_append(reply, "i", s->link ? s->link->ifindex : 0); + r = sd_bus_message_append(reply, "i", dns_server_ifindex(s)); if (r < 0) return r; } diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 990dc03b60..fecf7ecccf 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -27,18 +27,18 @@ int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) { union in_addr_union address; - int family, r; + int family, r, ifindex = 0; DnsServer *s; assert(m); assert(word); - r = in_addr_from_string_auto(word, &family, &address); + r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex); if (r < 0) return r; /* Filter out duplicates */ - s = dns_server_find(manager_get_first_dns_server(m, type), family, &address); + s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex); if (s) { /* * Drop the marker. This is used to find the servers @@ -50,7 +50,7 @@ int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char return 0; } - return dns_server_new(m, NULL, type, NULL, family, &address); + return dns_server_new(m, NULL, type, NULL, family, &address, ifindex); } int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) { @@ -70,7 +70,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con r = manager_add_dns_server_by_string(m, type, word); if (r < 0) - log_warning_errno(r, "Failed to add DNS server address '%s', ignoring.", word); + log_warning_errno(r, "Failed to add DNS server address '%s', ignoring: %m", word); } return 0; @@ -125,7 +125,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) { r = manager_add_search_domain_by_string(m, word); if (r < 0) - log_warning_errno(r, "Failed to add search domain '%s', ignoring.", word); + log_warning_errno(r, "Failed to add search domain '%s', ignoring: %m", word); } return 0; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 66e4585c18..6a69d7b7c2 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -307,7 +307,7 @@ static int dns_scope_socket( union sockaddr_union sa = {}; socklen_t salen; static const int one = 1; - int ret, r; + int ret, r, ifindex; assert(s); @@ -315,6 +315,8 @@ static int dns_scope_socket( assert(family == AF_UNSPEC); assert(!address); + ifindex = dns_server_ifindex(server); + sa.sa.sa_family = server->family; if (server->family == AF_INET) { sa.in.sin_port = htobe16(port); @@ -323,7 +325,7 @@ static int dns_scope_socket( } else if (server->family == AF_INET6) { sa.in6.sin6_port = htobe16(port); sa.in6.sin6_addr = server->address.in6; - sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0; + sa.in6.sin6_scope_id = ifindex; salen = sizeof(sa.in6); } else return -EAFNOSUPPORT; @@ -332,6 +334,7 @@ static int dns_scope_socket( assert(address); sa.sa.sa_family = family; + ifindex = s->link ? s->link->ifindex : 0; if (family == AF_INET) { sa.in.sin_port = htobe16(port); @@ -340,7 +343,7 @@ static int dns_scope_socket( } else if (family == AF_INET6) { sa.in6.sin6_port = htobe16(port); sa.in6.sin6_addr = address->in6; - sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0; + sa.in6.sin6_scope_id = ifindex; salen = sizeof(sa.in6); } else return -EAFNOSUPPORT; @@ -357,14 +360,14 @@ static int dns_scope_socket( } if (s->link) { - uint32_t ifindex = htobe32(s->link->ifindex); + be32_t ifindex_be = htobe32(ifindex); if (sa.sa.sa_family == AF_INET) { - r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex)); + r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)); if (r < 0) return -errno; } else if (sa.sa.sa_family == AF_INET6) { - r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex)); + r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)); if (r < 0) return -errno; } diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 3095c042db..5acfcb4239 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -43,7 +43,8 @@ int dns_server_new( DnsServerType type, Link *l, int family, - const union in_addr_union *in_addr) { + const union in_addr_union *in_addr, + int ifindex) { DnsServer *s; @@ -75,6 +76,7 @@ int dns_server_new( s->type = type; s->family = family; s->address = *in_addr; + s->ifindex = ifindex; s->resend_timeout = DNS_TIMEOUT_MIN_USEC; switch (type) { @@ -518,11 +520,24 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature return dns_packet_append_opt(packet, packet_size, edns_do, NULL); } +int dns_server_ifindex(const DnsServer *s) { + assert(s); + + /* The link ifindex always takes precedence */ + if (s->link) + return s->link->ifindex; + + if (s->ifindex > 0) + return s->ifindex; + + return 0; +} + const char *dns_server_string(DnsServer *server) { assert(server); if (!server->server_string) - (void) in_addr_to_string(server->family, &server->address, &server->server_string); + (void) in_addr_ifindex_to_string(server->family, &server->address, dns_server_ifindex(server), &server->server_string); return strna(server->server_string); } @@ -571,17 +586,28 @@ static void dns_server_hash_func(const void *p, struct siphash *state) { siphash24_compress(&s->family, sizeof(s->family), state); siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state); + siphash24_compress(&s->ifindex, sizeof(s->ifindex), state); } static int dns_server_compare_func(const void *a, const void *b) { const DnsServer *x = a, *y = b; + int r; if (x->family < y->family) return -1; if (x->family > y->family) return 1; - return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); + r = memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); + if (r != 0) + return r; + + if (x->ifindex < y->ifindex) + return -1; + if (x->ifindex > y->ifindex) + return 1; + + return 0; } const struct hash_ops dns_server_hash_ops = { @@ -623,11 +649,11 @@ void dns_server_mark_all(DnsServer *first) { dns_server_mark_all(first->servers_next); } -DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) { +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex) { DnsServer *s; LIST_FOREACH(servers, s, first) - if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0) + if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0 && s->ifindex == ifindex) return s; return NULL; diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 9f4a69c37a..463c5724a7 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -62,6 +62,7 @@ struct DnsServer { int family; union in_addr_union address; + int ifindex; /* for IPv6 link-local DNS servers */ char *server_string; @@ -101,7 +102,8 @@ int dns_server_new( DnsServerType type, Link *link, int family, - const union in_addr_union *address); + const union in_addr_union *address, + int ifindex); DnsServer* dns_server_ref(DnsServer *s); DnsServer* dns_server_unref(DnsServer *s); @@ -121,12 +123,13 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s); int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level); const char *dns_server_string(DnsServer *server); +int dns_server_ifindex(const DnsServer *s); bool dns_server_dnssec_supported(DnsServer *server); void dns_server_warn_downgrade(DnsServer *server); -DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr); +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex); void dns_server_unlink_all(DnsServer *first); void dns_server_unlink_marked(DnsServer *first); diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 7f21891819..2d5cd4a20d 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -218,11 +218,11 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ for (i = 0; i < n; i++) { DnsServer *s; - s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address); + s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0); if (s) dns_server_move_back_and_unmark(s); else { - r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address); + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0); if (r < 0) goto clear; } diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index b0dc65036d..b189c21920 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -216,11 +216,11 @@ static int link_update_dns_servers(Link *l) { if (r < 0) goto clear; - s = dns_server_find(l->dns_servers, family, &a); + s = dns_server_find(l->dns_servers, family, &a, 0); if (s) dns_server_move_back_and_unmark(s); else { - r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a); + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0); if (r < 0) goto clear; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 9600bde1e9..1be0fd289b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -903,7 +903,7 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add if (family == AF_INET) return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p); - else if (family == AF_INET6) + if (family == AF_INET6) return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p); return -EAFNOSUPPORT; diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index fa89de4c21..df738e31ef 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -92,7 +92,7 @@ int manager_read_resolv_conf(Manager *m) { a = first_word(l, "nameserver"); if (a) { - r = manager_add_dns_server_by_string(m, DNS_SERVER_SYSTEM, a); + r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_SYSTEM, a); if (r < 0) log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a); @@ -149,9 +149,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { assert(f); assert(count); - (void) dns_server_string(s); - - if (!s->server_string) { + if (!dns_server_string(s)) { log_warning("Our of memory, or invalid DNS address. Ignoring server."); return; } @@ -160,7 +158,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); (*count)++; - fprintf(f, "nameserver %s\n", s->server_string); + fprintf(f, "nameserver %s\n", dns_server_string(s)); } static void write_resolv_conf_search( diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index b480fdaa9c..1a439bd0d4 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -286,6 +286,55 @@ static void test_in_addr_to_string(void) { test_in_addr_to_string_one(AF_INET6, "fe80::"); } +static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) { + _cleanup_free_ char *r = NULL; + union in_addr_union ua, uuaa; + int ff, ifindex2; + + assert_se(in_addr_from_string(f, a, &ua) >= 0); + assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0); + printf("test_in_addr_ifindex_to_string_one: %s == %s\n", b, r); + assert_se(streq(b, r)); + + assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0); + assert_se(ff == f); + assert_se(in_addr_equal(f, &ua, &uuaa)); + assert_se(ifindex2 == ifindex || ifindex2 == 0); +} + +static void test_in_addr_ifindex_to_string(void) { + test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1"); + test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13"); + test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + test_in_addr_ifindex_to_string_one(AF_INET6, "::1", 11, "::1"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 12, "fe80::%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 0, "fe80::"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::14", 12, "fe80::14%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::15", -7, "fe80::15"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::16", LOOPBACK_IFINDEX, "fe80::16%1"); +} + +static void test_in_addr_ifindex_from_string_auto(void) { + int family, ifindex; + union in_addr_union ua; + + /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */ + + assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 0); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%19", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 19); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%lo", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == LOOPBACK_IFINDEX); + + assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV); +} + static void *connect_thread(void *arg) { union sockaddr_union *sa = arg; _cleanup_close_ int fd = -1; @@ -398,6 +447,8 @@ int main(int argc, char *argv[]) { test_in_addr_prefix_intersect(); test_in_addr_prefix_next(); test_in_addr_to_string(); + test_in_addr_ifindex_to_string(); + test_in_addr_ifindex_from_string_auto(); test_nameinfo_pretty(); -- cgit v1.2.3-54-g00ecf From 7207052d252615b2e991b1f1e8eda79869193f09 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Jun 2016 19:00:36 +0200 Subject: resolved: also rewrite private /etc/resolv.conf when configuration is changed via bus calls This also moves log message generation into manager_write_resolv_conf(), so that it is shorter to invoke the function, given that we have to invoke it at a couple of additional places now. Fixes: #3225 --- src/resolve/resolved-link-bus.c | 8 ++++++++ src/resolve/resolved-manager.c | 4 +--- src/resolve/resolved-resolv-conf.c | 17 ++++++++++------- src/resolve/resolved.c | 7 ++----- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 2d5cd4a20d..6aff427192 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -23,6 +23,7 @@ #include "resolve-util.h" #include "resolved-bus.h" #include "resolved-link-bus.h" +#include "resolved-resolv-conf.h" #include "strv.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport); @@ -232,6 +233,8 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ dns_server_unlink_marked(l->dns_servers); link_allocate_scopes(l); + (void) manager_write_resolv_conf(l->manager); + return sd_bus_reply_method_return(message, NULL); clear: @@ -306,6 +309,9 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ goto clear; dns_search_domain_unlink_marked(l->search_domains); + + (void) manager_write_resolv_conf(l->manager); + return sd_bus_reply_method_return(message, NULL); clear: @@ -444,6 +450,8 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error link_allocate_scopes(l); link_add_rrs(l, false); + (void) manager_write_resolv_conf(l->manager); + return sd_bus_reply_method_return(message, NULL); } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 1be0fd289b..8dc7891143 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -284,9 +284,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void * log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex); } - r = manager_write_resolv_conf(m); - if (r < 0) - log_warning_errno(r, "Could not update "PRIVATE_RESOLV_CONF": %m"); + (void) manager_write_resolv_conf(m); return 0; } diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index df738e31ef..ae17aef3ab 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -225,29 +225,31 @@ int manager_write_resolv_conf(Manager *m) { assert(m); /* Read the system /etc/resolv.conf first */ - manager_read_resolv_conf(m); + (void) manager_read_resolv_conf(m); /* Add the full list to a set, to filter out duplicates */ r = manager_compile_dns_servers(m, &dns); if (r < 0) - return r; + return log_warning_errno(r, "Failed to compile list of DNS servers: %m"); r = manager_compile_search_domains(m, &domains); if (r < 0) - return r; + return log_warning_errno(r, "Failed to compile list of search domains: %m"); r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path); if (r < 0) - return r; + return log_warning_errno(r, "Failed to open private resolv.conf file for writing: %m"); - fchmod(fileno(f), 0644); + (void) fchmod(fileno(f), 0644); r = write_resolv_conf_contents(f, dns, domains); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to write private resolv.conf contents: %m"); goto fail; + } if (rename(temp_path, PRIVATE_RESOLV_CONF) < 0) { - r = -errno; + r = log_error_errno(errno, "Failed to move private resolv.conf file into place: %m"); goto fail; } @@ -256,5 +258,6 @@ int manager_write_resolv_conf(Manager *m) { fail: (void) unlink(PRIVATE_RESOLV_CONF); (void) unlink(temp_path); + return r; } diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 161ea03412..6cef401870 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -85,11 +85,8 @@ int main(int argc, char *argv[]) { goto finish; } - /* Write finish default resolv.conf to avoid a dangling - * symlink */ - r = manager_write_resolv_conf(m); - if (r < 0) - log_warning_errno(r, "Could not create "PRIVATE_RESOLV_CONF": %m"); + /* Write finish default resolv.conf to avoid a dangling symlink */ + (void) manager_write_resolv_conf(m); sd_notify(false, "READY=1\n" -- cgit v1.2.3-54-g00ecf From fe624c4c07026fe11f37b7517e81b3814fa868bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 22:08:21 +0200 Subject: time-util: add triple timestamp object We already have a double timestamp object that we use whenever we need both a MONOTONIC and a REALTIME timestamp taken and stored. With this change we also add a triple timestamp object that in addition stores a BOOTTIME timestamp, which is useful for a few usecases. Note that we keep dual_timestamp around, as it is useful in many cases where triple_timestamp is not, in particular because retrieving the monotonic and realtime timestamps is much cheaper on Linux that getting the boottime timestamp. --- src/basic/time-util.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/basic/time-util.h | 27 ++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index edd9179cb8..24e681bf85 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -87,6 +87,16 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { return ts; } +triple_timestamp* triple_timestamp_get(triple_timestamp *ts) { + assert(ts); + + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY; + + return ts; +} + dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); @@ -104,6 +114,24 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { return ts; } +triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) { + int64_t delta; + + assert(ts); + + if (u == USEC_INFINITY || u <= 0) { + ts->realtime = ts->monotonic = ts->boottime = u; + return ts; + } + + ts->realtime = u; + delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; + ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta); + ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY; + + return ts; +} + dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); @@ -136,6 +164,26 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us return ts; } +usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) { + + switch (clock) { + + case CLOCK_REALTIME: + case CLOCK_REALTIME_ALARM: + return ts->realtime; + + case CLOCK_MONOTONIC: + return ts->monotonic; + + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: + return ts->boottime; + + default: + return USEC_INFINITY; + } +} + usec_t timespec_load(const struct timespec *ts) { assert(ts); @@ -1107,6 +1155,30 @@ clockid_t clock_boottime_or_monotonic(void) { return CLOCK_MONOTONIC; } +bool clock_supported(clockid_t clock) { + struct timespec ts; + + switch (clock) { + + case CLOCK_MONOTONIC: + case CLOCK_REALTIME: + return true; + + case CLOCK_BOOTTIME: + return clock_boottime_supported(); + + case CLOCK_BOOTTIME_ALARM: + if (!clock_boottime_supported()) + return false; + + /* fall through, after checking the cached value for CLOCK_BOOTTIME. */ + + default: + /* For everything else, check properly */ + return clock_gettime(clock, &ts) >= 0; + } +} + int get_timezone(char **tz) { _cleanup_free_ char *t = NULL; const char *e; diff --git a/src/basic/time-util.h b/src/basic/time-util.h index a5e3f567ec..1b058f0e49 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -39,6 +39,12 @@ typedef struct dual_timestamp { usec_t monotonic; } dual_timestamp; +typedef struct triple_timestamp { + usec_t realtime; + usec_t monotonic; + usec_t boottime; +} triple_timestamp; + #define USEC_INFINITY ((usec_t) -1) #define NSEC_INFINITY ((nsec_t) -1) @@ -69,7 +75,8 @@ typedef struct dual_timestamp { #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) -#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) +#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {}) +#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {}) usec_t now(clockid_t clock); nsec_t now_nsec(clockid_t clock); @@ -79,11 +86,28 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u); +triple_timestamp* triple_timestamp_get(triple_timestamp *ts); +triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u); + +#define DUAL_TIMESTAMP_HAS_CLOCK(clock) \ + IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC) + +#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \ + IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) + static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); } +static inline bool triple_timestamp_is_set(triple_timestamp *ts) { + return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || + (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) || + (ts->boottime > 0 && ts->boottime != USEC_INFINITY)); +} + +usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock); + usec_t timespec_load(const struct timespec *ts) _pure_; struct timespec *timespec_store(struct timespec *ts, usec_t u); @@ -113,6 +137,7 @@ int get_timezones(char ***l); bool timezone_is_valid(const char *name); bool clock_boottime_supported(void); +bool clock_supported(clockid_t clock); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) \ -- cgit v1.2.3-54-g00ecf From e475d10c1be86f3c060cee86ddd6e1617608bdd8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 22:11:22 +0200 Subject: sd-event: port over to new triple timestamp logic --- src/libsystemd/sd-event/sd-event.c | 56 ++++++++++++-------------------------- 1 file changed, 17 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 7ba6527f63..f364b54b50 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -216,8 +216,7 @@ struct sd_event { pid_t original_pid; unsigned iteration; - dual_timestamp timestamp; - usec_t timestamp_boottime; + triple_timestamp timestamp; int state; bool exit_requested:1; @@ -1072,16 +1071,16 @@ _public_ int sd_event_add_time( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && - !clock_boottime_supported()) + if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */ + return -EOPNOTSUPP; + + type = clock_to_event_source_type(clock); /* checks whether sd-event supports this clock */ + if (type < 0) return -EOPNOTSUPP; if (!callback) callback = time_exit_callback; - type = clock_to_event_source_type(clock); - assert_return(type >= 0, -EOPNOTSUPP); - d = event_get_clock_data(e, type); assert(d); @@ -2530,9 +2529,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { goto finish; } - dual_timestamp_get(&e->timestamp); - if (clock_boottime_supported()) - e->timestamp_boottime = now(CLOCK_BOOTTIME); + triple_timestamp_get(&e->timestamp); for (i = 0; i < m; i++) { @@ -2573,7 +2570,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime); + r = process_timer(e, e->timestamp.boottime, &e->boottime); if (r < 0) goto finish; @@ -2585,7 +2582,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime_alarm); + r = process_timer(e, e->timestamp.boottime, &e->boottime_alarm); if (r < 0) goto finish; @@ -2759,43 +2756,24 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); - assert_return(IN_SET(clock, - CLOCK_REALTIME, - CLOCK_REALTIME_ALARM, - CLOCK_MONOTONIC, - CLOCK_BOOTTIME, - CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP); + if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock)) + return -EOPNOTSUPP; + + /* Generate a clean error in case CLOCK_BOOTTIME is not available. Note that don't use clock_supported() here, + * for a reason: there are systems where CLOCK_BOOTTIME is supported, but CLOCK_BOOTTIME_ALARM is not, but for + * the purpose of getting the time this doesn't matter. */ if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) return -EOPNOTSUPP; - if (!dual_timestamp_is_set(&e->timestamp)) { + if (!triple_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran * before and thus have no cached time. */ *usec = now(clock); return 1; } - switch (clock) { - - case CLOCK_REALTIME: - case CLOCK_REALTIME_ALARM: - *usec = e->timestamp.realtime; - break; - - case CLOCK_MONOTONIC: - *usec = e->timestamp.monotonic; - break; - - case CLOCK_BOOTTIME: - case CLOCK_BOOTTIME_ALARM: - *usec = e->timestamp_boottime; - break; - - default: - assert_not_reached("Unknown clock?"); - } - + *usec = triple_timestamp_by_clock(&e->timestamp, clock); return 0; } -- cgit v1.2.3-54-g00ecf From 16fed825d60ca1efa57d0b9231842cda9aae7a68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 22:11:47 +0200 Subject: sd-lldp: take triple timestamp when reading LLDP packets It's a good idea to store away the recption time of LLDP packets in the neighbor object, simply because the LLDP data only has a validity of a certain amount of time. Hence, let's record the timestamp when we receive the datagram and expose an API for it. Also, automatically expire LLDP neighbors based on this new timestamp. --- src/libsystemd-network/lldp-neighbor.c | 26 +++++++++++++++++++++++--- src/libsystemd-network/lldp-neighbor.h | 2 ++ src/libsystemd-network/sd-lldp.c | 8 ++++++++ src/systemd/sd-lldp.h | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 6a716430e3..c14126b60a 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -360,9 +360,16 @@ end_marker: void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { assert(n); - if (n->ttl > 0) - n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC); - else + if (n->ttl > 0) { + usec_t base; + + /* Use the packet's timestamp if there is one known */ + base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic()); + if (base <= 0 || base == USEC_INFINITY) + base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */ + + n->until = usec_add(base, n->ttl * USEC_PER_SEC); + } else n->until = 0; if (n->lldp) @@ -792,3 +799,16 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, return 0; } + +int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) { + assert_return(n, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&n->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&n->timestamp, clock); + return 0; +} diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h index f203bfa604..27a27055f1 100644 --- a/src/libsystemd-network/lldp-neighbor.h +++ b/src/libsystemd-network/lldp-neighbor.h @@ -43,6 +43,8 @@ struct sd_lldp_neighbor { sd_lldp *lldp; unsigned n_ref; + triple_timestamp timestamp; + usec_t until; unsigned prioq_idx; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 9d4587c80e..223a5ac02f 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -138,6 +138,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + old->timestamp = n->timestamp; lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; @@ -202,6 +203,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; ssize_t space, length; sd_lldp *lldp = userdata; + struct timespec ts; assert(fd >= 0); assert(lldp); @@ -223,6 +225,12 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v return -EINVAL; } + /* Try to get the timestamp of this packet if it is known */ + if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0) + triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts)); + else + triple_timestamp_get(&n->timestamp); + return lldp_handle_datagram(lldp, n); } diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 5772d5794a..617e0f1e17 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -145,6 +145,7 @@ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); /* Access to LLDP frame metadata */ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret); int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); /* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ -- cgit v1.2.3-54-g00ecf From 5f94b4e62e9439b3580653e30082981e33128b8a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:41:48 +0200 Subject: exit-code: minor coding style updates --- src/basic/exit-status.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index 92fa5ace61..d488cfc59f 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -38,8 +38,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { return "FAILURE"; } - - if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) { + if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB)) { switch ((int) status) { case EXIT_CHDIR: @@ -189,13 +188,9 @@ bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { /* If a daemon does not implement handlers for some of the * signals that's not considered an unclean shutdown */ if (code == CLD_KILLED) - return - status == SIGHUP || - status == SIGINT || - status == SIGTERM || - status == SIGPIPE || + return IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE) || (success_status && - set_contains(success_status->signal, INT_TO_PTR(status))); + set_contains(success_status->signal, INT_TO_PTR(status))); return false; } @@ -207,15 +202,14 @@ bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) { return code == CLD_EXITED && - (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED); + IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOTCONFIGURED); } void exit_status_set_free(ExitStatusSet *x) { assert(x); - set_free(x->status); - set_free(x->signal); - x->status = x->signal = NULL; + x->status = set_free(x->status); + x->signal = set_free(x->signal); } bool exit_status_set_is_empty(ExitStatusSet *x) { -- cgit v1.2.3-54-g00ecf From fc6a313b5b836a8642a47348272d7883e1b9349d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:45:08 +0200 Subject: lldp: add proper ref counting to sd_lldp object and a separate call for setting the ifindex Let's make sd-lldp a bit more like sd-ndisc ant the other APIs, and add proper ref counting and a separate call for setting the ifindex. This also adds a new lldp_reset() call we can use at various places to close all fds. This is also similar to how sd-ndisc already does it. --- src/libsystemd-network/lldp-internal.h | 2 + src/libsystemd-network/sd-lldp.c | 75 +++++++++++++++++++++++----------- src/libsystemd-network/test-lldp.c | 8 +++- src/network/networkd-link.c | 6 ++- src/systemd/sd-lldp.h | 10 +++-- 5 files changed, 70 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 7592bc4305..becc162fab 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -28,6 +28,8 @@ #include "prioq.h" struct sd_lldp { + unsigned n_ref; + int ifindex; int fd; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 223a5ac02f..9e9907ca37 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -234,10 +234,20 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v return lldp_handle_datagram(lldp, n); } +static void lldp_reset(sd_lldp *lldp) { + assert(lldp); + + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); + lldp->fd = safe_close(lldp->fd); +} + _public_ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); + assert_return(lldp->event, -EINVAL); + assert_return(lldp->ifindex > 0, -EINVAL); if (lldp->fd >= 0) return 0; @@ -248,24 +258,21 @@ _public_ int sd_lldp_start(sd_lldp *lldp) { if (lldp->fd < 0) return lldp->fd; - if (lldp->event) { - r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); - if (r < 0) - goto fail; + r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); + if (r < 0) + goto fail; - r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); - if (r < 0) - goto fail; + r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); + if (r < 0) + goto fail; - (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); - } + (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); + log_lldp("Started LLDP client"); return 1; fail: - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); - lldp->fd = safe_close(lldp->fd); - + lldp_reset(lldp); return r; } @@ -275,10 +282,9 @@ _public_ int sd_lldp_stop(sd_lldp *lldp) { if (lldp->fd < 0) return 0; - lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); - lldp->fd = safe_close(lldp->fd); + log_lldp("Stopping LLDP client"); + lldp_reset(lldp); lldp_flush_neighbors(lldp); return 1; @@ -322,39 +328,60 @@ _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *us return 0; } +_public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) { + assert_return(lldp, -EINVAL); + assert_return(ifindex > 0, -EINVAL); + assert_return(lldp->fd < 0, -EBUSY); + + lldp->ifindex = ifindex; + return 0; +} + +_public_ sd_lldp* sd_lldp_ref(sd_lldp *lldp) { + + if (!lldp) + return NULL; + + assert(lldp->n_ref > 0); + lldp->n_ref++; + + return lldp; +} + _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { if (!lldp) return NULL; + assert(lldp->n_ref > 0); + lldp->n_ref --; + + if (lldp->n_ref > 0) + return NULL; + + lldp_reset(lldp); + sd_lldp_detach_event(lldp); lldp_flush_neighbors(lldp); hashmap_free(lldp->neighbor_by_id); prioq_free(lldp->neighbor_by_expiry); - - sd_event_source_unref(lldp->io_event_source); - sd_event_source_unref(lldp->timer_event_source); - sd_event_unref(lldp->event); - safe_close(lldp->fd); - free(lldp); return NULL; } -_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) { +_public_ int sd_lldp_new(sd_lldp **ret) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; assert_return(ret, -EINVAL); - assert_return(ifindex > 0, -EINVAL); lldp = new0(sd_lldp, 1); if (!lldp) return -ENOMEM; + lldp->n_ref = 1; lldp->fd = -1; - lldp->ifindex = ifindex; lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; lldp->capability_mask = (uint16_t) -1; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 1aae2253c0..6bcd65de0a 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -54,11 +54,11 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; - r = sd_lldp_new(lldp, 42); + r = sd_lldp_new(lldp); if (r < 0) return r; - r = sd_lldp_attach_event(*lldp, e, 0); + r = sd_lldp_set_ifindex(*lldp, 42); if (r < 0) return r; @@ -66,6 +66,10 @@ static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void * if (r < 0) return r; + r = sd_lldp_attach_event(*lldp, e, 0); + if (r < 0) + return r; + r = sd_lldp_start(*lldp); if (r < 0) return r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ee52b1ce1e..90ed55d42c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2364,7 +2364,11 @@ static int link_configure(Link *link) { } if (link_lldp_rx_enabled(link)) { - r = sd_lldp_new(&link->lldp, link->ifindex); + r = sd_lldp_new(&link->lldp); + if (r < 0) + return r; + + r = sd_lldp_set_ifindex(link->lldp, link->ifindex); if (r < 0) return r; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 617e0f1e17..8f096c1b99 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -30,9 +30,6 @@ _SD_BEGIN_DECLARATIONS; -typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_neighbor sd_lldp_neighbor; - /* IEEE 802.3AB Clause 9: TLV Types */ enum { SD_LLDP_TYPE_END = 0, @@ -111,6 +108,9 @@ enum { SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; +typedef struct sd_lldp sd_lldp; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; + typedef enum sd_lldp_event { SD_LLDP_EVENT_ADDED = 'a', SD_LLDP_EVENT_REMOVED = 'r', @@ -120,7 +120,8 @@ typedef enum sd_lldp_event { typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); -int sd_lldp_new(sd_lldp **ret, int ifindex); +int sd_lldp_new(sd_lldp **ret); +sd_lldp* sd_lldp_ref(sd_lldp *lldp); sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); @@ -130,6 +131,7 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); +int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex); /* Controls how much and what to store in the neighbors database */ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); -- cgit v1.2.3-54-g00ecf From 8a19206d1bb4cde80defaa3f183b704e95782247 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:46:56 +0200 Subject: lldp: clarify that sd_lldp_neighbor_get_ttl() returns seconds Let's simply encode this in the parameter name. --- src/libsystemd-network/lldp-neighbor.c | 6 +++--- src/systemd/sd-lldp.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index c14126b60a..9f37e3db14 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -595,11 +595,11 @@ done: return 0; } -_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) { +_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) { assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); + assert_return(ret_sec, -EINVAL); - *ret = n->ttl; + *ret_sec = n->ttl; return 0; } diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 8f096c1b99..f9b79a0c40 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -155,7 +155,7 @@ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const vo int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec); int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); -- cgit v1.2.3-54-g00ecf From 09155f682a66eaf1f1e7cb0859a5bc0e2c5a39cf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:47:35 +0200 Subject: lldp: add _public_ to a two exported functions missing it --- src/libsystemd-network/lldp-neighbor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 9f37e3db14..a4af303259 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -658,7 +658,7 @@ _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint return 0; } -int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { +_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; int r; @@ -800,7 +800,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, return 0; } -int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) { +_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) { assert_return(n, -EINVAL); assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); assert_return(clock_supported(clock), -EOPNOTSUPP); -- cgit v1.2.3-54-g00ecf From a2966471d815a965e2f4b86cdad30c8086c1ec6d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:48:05 +0200 Subject: lldp: use NULL instead 0, when we deal with a pointer --- src/libsystemd-network/lldp-neighbor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index a4af303259..5811e0f2e8 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -675,7 +675,7 @@ _public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, return r; *ret = n; - n = 0; + n = NULL; return r; } -- cgit v1.2.3-54-g00ecf From a85b46c33f09d62a066231abdf9727e84a3c07cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:48:31 +0200 Subject: lldp: make sd_lldp_neighbor_tlv_rewind() return whether there's a first entry This way it's nicer to use as it matches how sd_lldp_neighbor_tlv_next() indicates an EOF too via its return value. --- src/libsystemd-network/lldp-neighbor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 5811e0f2e8..0ed680eecf 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -686,7 +686,7 @@ _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { assert(n->raw_size >= sizeof(struct ether_header)); n->rindex = sizeof(struct ether_header); - return 0; + return n->rindex < n->raw_size; } _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { -- cgit v1.2.3-54-g00ecf From f137029bb838b64c13bc33ba997094a01b97bb79 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:49:28 +0200 Subject: lldp: rename TLV accessor pseudo-macros Let's make sure the inline functions for retrieving TLV data actually carry TLV in the name, so that we don#t assume they retrieve the whole, raw packet data. --- src/libsystemd-network/lldp-neighbor.c | 11 +++++------ src/libsystemd-network/lldp-neighbor.h | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 0ed680eecf..88f7e329b0 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -700,7 +700,7 @@ _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { if (n->rindex + 2 > n->raw_size) /* Truncated message */ return -EBADMSG; - length = LLDP_NEIGHBOR_LENGTH(n); + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; @@ -718,7 +718,7 @@ _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { if (n->rindex + 2 > n->raw_size) return -EBADMSG; - *type = LLDP_NEIGHBOR_TYPE(n); + *type = LLDP_NEIGHBOR_TLV_TYPE(n); return 0; } @@ -750,14 +750,14 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], u if (r == 0) return -ENXIO; - length = LLDP_NEIGHBOR_LENGTH(n); + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (length < 4) return -EBADMSG; if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; - d = LLDP_NEIGHBOR_DATA(n); + d = LLDP_NEIGHBOR_TLV_DATA(n); memcpy(oui, d, 3); *subtype = d[3]; @@ -789,8 +789,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, if (n->rindex + 2 > n->raw_size) return -EBADMSG; - length = LLDP_NEIGHBOR_LENGTH(n); - + length = LLDP_NEIGHBOR_TLV_LENGTH(n); if (n->rindex + 2 + length > n->raw_size) return -EBADMSG; diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h index 27a27055f1..c1a7606d06 100644 --- a/src/libsystemd-network/lldp-neighbor.h +++ b/src/libsystemd-network/lldp-neighbor.h @@ -83,18 +83,18 @@ static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); } -static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) { +static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) { return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; } -static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) { +static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) { uint8_t *p; p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; return p[1] + (((size_t) (p[0] & 1)) << 8); } -static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) { +static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) { return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; } -- cgit v1.2.3-54-g00ecf From 35ad2cd7ce3c85a9ff8f251ac9c325bdd6e852ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:50:21 +0200 Subject: lldp: pass correct neighbor object to REMOVED callback --- src/libsystemd-network/sd-lldp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 9e9907ca37..c74deccd0c 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -43,7 +43,6 @@ static void lldp_flush_neighbors(sd_lldp *lldp) { static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { assert(lldp); - assert(n); log_lldp("Invoking callback for '%c'.", event); @@ -172,7 +171,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { finish: if (old) - lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); return r; } -- cgit v1.2.3-54-g00ecf From f3315c5860548b5560ef114a1e2af4eaafb32c6b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:50:40 +0200 Subject: lldp: deal properly with recv() returning EAGAIN/EINTR It might very well return EAGAIN in case of packet checksum problems and suchlike, hence let's better handle this nicely, the same way as we do it in the other sd-network libraries for incoming datagrams. --- src/libsystemd-network/sd-lldp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index c74deccd0c..66d5dbf203 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -216,8 +216,12 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v return -ENOMEM; length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); - if (length < 0) + if (length < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); + } if ((size_t) length != n->raw_size) { log_lldp("Packet size mismatch."); -- cgit v1.2.3-54-g00ecf From 3db2ec568c01676a2f5482b8127ba0005c5fa2b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:51:56 +0200 Subject: lldp: add sd_lldp_get_event() call sd-ndisc has something like this, let's add this for sd-lldp, too. --- src/libsystemd-network/sd-lldp.c | 6 ++++++ src/systemd/sd-lldp.h | 1 + 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 66d5dbf203..cbf62734a8 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -322,6 +322,12 @@ _public_ int sd_lldp_detach_event(sd_lldp *lldp) { return 0; } +_public_ sd_event* sd_lldp_get_event(sd_lldp *lldp) { + assert_return(lldp, NULL); + + return lldp->event; +} + _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { assert_return(lldp, -EINVAL); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index f9b79a0c40..ef9596838b 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -129,6 +129,7 @@ int sd_lldp_stop(sd_lldp *lldp); int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); +sd_event *sd_lldp_get_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex); -- cgit v1.2.3-54-g00ecf From a1fb61b0e826181b1bea514f8a7358081578133d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:52:32 +0200 Subject: lldp: minor coding style improvement --- src/libsystemd-network/sd-lldp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index cbf62734a8..0bd1e66aa0 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -530,11 +530,10 @@ _public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr * /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so * that our own can be filtered out here. */ - if (!addr) { + if (addr) + lldp->filter_address = *addr; + else zero(lldp->filter_address); - return 0; - } - lldp->filter_address = *addr; return 0; } -- cgit v1.2.3-54-g00ecf From f848976364c0442595f01fa147d82b2cc728c101 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:52:58 +0200 Subject: lldp: include sys/types.h in sd-lldp.h After all, we use clockid_t which is defined there. --- src/systemd/sd-lldp.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index ef9596838b..3f35eebea3 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -23,6 +23,7 @@ #include #include +#include #include "sd-event.h" -- cgit v1.2.3-54-g00ecf From c9d81ae858cdf0482fa4c9c37e5f5e26d615e8c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 17:56:59 +0200 Subject: exit-status: update comments a bit --- src/basic/exit-status.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 1208c8feed..2309f68815 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -25,6 +25,12 @@ #include "macro.h" #include "set.h" +/* This defines pretty names for the LSB 'start' verb exit codes. Note that they shouldn't be confused with the LSB + * 'status' verb exit codes which are defined very differently. For details see: + * + * https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html + */ + typedef enum ExitStatus { /* EXIT_SUCCESS defined by libc */ /* EXIT_FAILURE defined by libc */ @@ -37,9 +43,7 @@ typedef enum ExitStatus { /* The LSB suggests that error codes >= 200 are "reserved". We * use them here under the assumption that they hence are - * unused by init scripts. - * - * http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ + * unused by init scripts. */ EXIT_CHDIR = 200, EXIT_NICE, @@ -81,9 +85,9 @@ typedef enum ExitStatus { } ExitStatus; typedef enum ExitStatusLevel { - EXIT_STATUS_MINIMAL, - EXIT_STATUS_SYSTEMD, - EXIT_STATUS_LSB, + EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */ + EXIT_STATUS_SYSTEMD, /* cover libc and systemd's own exit codes */ + EXIT_STATUS_LSB, /* cover libc, systemd's own and LSB exit codes */ EXIT_STATUS_FULL = EXIT_STATUS_LSB } ExitStatusLevel; -- cgit v1.2.3-54-g00ecf From c917a32122ac18c9b6112d67fbb815d84a053e4a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 18:12:16 +0200 Subject: util-lib: add accessors for unaligned native endian words --- src/basic/unaligned.h | 18 ++++++++++++++++++ src/test/test-unaligned.c | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'src') diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index 79be645bed..7c847a3ccb 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -109,3 +109,21 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) { unaligned_write_le32(u, (uint32_t) a); unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); } + +#if __BYTE_ORDER == __BIG_ENDIAN +#define unaligned_read_ne16 unaligned_read_be16 +#define unaligned_read_ne32 unaligned_read_be32 +#define unaligned_read_ne64 unaligned_read_be64 + +#define unaligned_write_ne16 unaligned_write_be16 +#define unaligned_write_ne32 unaligned_write_be32 +#define unaligned_write_ne64 unaligned_write_be64 +#else +#define unaligned_read_ne16 unaligned_read_le16 +#define unaligned_read_ne32 unaligned_read_le32 +#define unaligned_read_ne64 unaligned_read_le64 + +#define unaligned_write_ne16 unaligned_write_le16 +#define unaligned_write_ne32 unaligned_write_le32 +#define unaligned_write_ne64 unaligned_write_le64 +#endif diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c index b18b3fca0e..4f64398943 100644 --- a/src/test/test-unaligned.c +++ b/src/test/test-unaligned.c @@ -159,7 +159,31 @@ static void test_le(void) { assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0); } +static void test_ne(void) { + uint16_t x = 4711; + uint32_t y = 123456; + uint64_t z = 9876543210; + + /* Note that we don't bother actually testing alignment issues in this function, after all the _ne() functions + * are just aliases for the _le() or _be() implementations, which we test extensively above. Hence, in this + * function, just ensure that they map to the right version on the local architecture. */ + + assert_se(unaligned_read_ne16(&x) == 4711); + assert_se(unaligned_read_ne32(&y) == 123456); + assert_se(unaligned_read_ne64(&z) == 9876543210); + + unaligned_write_ne16(&x, 1); + unaligned_write_ne32(&y, 2); + unaligned_write_ne64(&z, 3); + + assert_se(x == 1); + assert_se(y == 2); + assert_se(z == 3); +} + int main(int argc, const char *argv[]) { test_be(); test_le(); + test_ne(); + return 0; } -- cgit v1.2.3-54-g00ecf From 34380032fb8bdfd801fbd43c03acfb7ac664d2bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 20:34:21 +0200 Subject: util: make it easier to check whether in_addr or in6_addr addresses are NULL --- src/basic/in-addr-util.c | 20 ++++++++++++++------ src/basic/in-addr-util.h | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 245107ebb8..1447fa84aa 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -28,18 +28,26 @@ #include "macro.h" #include "util.h" +bool in4_addr_is_null(const struct in_addr *a) { + return a->s_addr == 0; +} + +bool in6_addr_is_null(const struct in6_addr *a) { + return + a->s6_addr32[0] == 0 && + a->s6_addr32[1] == 0 && + a->s6_addr32[2] == 0 && + a->s6_addr32[3] == 0; +} + int in_addr_is_null(int family, const union in_addr_union *u) { assert(u); if (family == AF_INET) - return u->in.s_addr == 0; + return in4_addr_is_null(&u->in); if (family == AF_INET6) - return - u->in6.s6_addr32[0] == 0 && - u->in6.s6_addr32[1] == 0 && - u->in6.s6_addr32[2] == 0 && - u->in6.s6_addr32[3] == 0; + return in6_addr_is_null(&u->in6); return -EAFNOSUPPORT; } diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 17798ce816..62cc1e1aa4 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -36,6 +36,9 @@ struct in_addr_data { union in_addr_union address; }; +bool in4_addr_is_null(const struct in_addr *a); +bool in6_addr_is_null(const struct in6_addr *a); + int in_addr_is_null(int family, const union in_addr_union *u); int in_addr_is_link_local(int family, const union in_addr_union *u); int in_addr_is_localhost(int family, const union in_addr_union *u); -- cgit v1.2.3-54-g00ecf From 1f152e4b41d730c7bbe23d8cbe45b7d342ba8c13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 20:35:13 +0200 Subject: network: use inet_ntop() rather than SD_NDISC_ADDRESS_FORMAT_VAL() when serializing Let's use the usual libc API for serializing IPv6 addresses, instead of the NDISC-specific macro we should get rid of anyway. --- src/libsystemd-network/network-internal.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index bfaa75880b..ce30b7fc25 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -380,18 +380,21 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { return size; } -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, - size_t size) { +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) { unsigned i; assert(f); assert(addresses); assert(size); - for (i = 0; i < size; i++) - fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s", - SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]), - (i < (size - 1)) ? " ": ""); + for (i = 0; i < size; i++) { + char buffer[INET6_ADDRSTRLEN]; + + fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f); + + if (i < size - 1) + fputc(' ', f); + } } int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { -- cgit v1.2.3-54-g00ecf From 1e7a0e21c97ac1bbc743009e5ec8c12bc6200e19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 20:38:12 +0200 Subject: network: beef up ipv6 RA support considerably This reworks sd-ndisc and networkd substantially to support IPv6 RA much more comprehensively. Since the API is extended quite a bit networkd has been ported over too, and the patch is not as straight-forward as one could wish. The rework includes: - Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two new configuration options have been added to networkd to make this configurable. - sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA message, and has direct, friendly acessor functions for the singleton RA properties, as well as an iterative interface to iterate through known and unsupported options. The router object may either be retrieved from the wire, or generated from raw data. In many ways the sd-ndisc API now matches the sd-lldp API, except that no implicit database of seen data is kept. (Note that sd-ndisc actually had a half-written, but unused implementaiton of such a store, which is removed now.) - sd-ndisc will now collect the reception timestamps of RA, which is useful to make sd_ndisc_router fully descriptive of what it covers. Fixes: #1079 --- Makefile.am | 4 + man/systemd.network.xml | 73 ++- src/libsystemd-network/icmp6-util.c | 7 +- src/libsystemd-network/ndisc-internal.h | 49 ++ src/libsystemd-network/ndisc-router.c | 779 +++++++++++++++++++++++++++++++ src/libsystemd-network/ndisc-router.h | 62 +++ src/libsystemd-network/sd-ndisc.c | 551 ++++++---------------- src/libsystemd-network/test-ndisc-rs.c | 163 ++++++- src/network/networkd-dhcp6.c | 15 +- src/network/networkd-link.c | 61 ++- src/network/networkd-link.h | 7 +- src/network/networkd-ndisc.c | 534 ++++++++++++++++++--- src/network/networkd-ndisc.h | 39 ++ src/network/networkd-network-gperf.gperf | 2 + src/network/networkd-network.c | 5 +- src/network/networkd-network.h | 3 + src/systemd/sd-ndisc.h | 114 +++-- 17 files changed, 1911 insertions(+), 557 deletions(-) create mode 100644 src/libsystemd-network/ndisc-internal.h create mode 100644 src/libsystemd-network/ndisc-router.c create mode 100644 src/libsystemd-network/ndisc-router.h create mode 100644 src/network/networkd-ndisc.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c31c30c051..9a34c686d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3430,6 +3430,9 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/network-internal.c \ src/libsystemd-network/network-internal.h \ src/libsystemd-network/sd-ndisc.c \ + src/libsystemd-network/ndisc-internal.h \ + src/libsystemd-network/ndisc-router.h \ + src/libsystemd-network/ndisc-router.c \ src/libsystemd-network/icmp6-util.h \ src/libsystemd-network/icmp6-util.c \ src/libsystemd-network/sd-dhcp6-client.c \ @@ -5462,6 +5465,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-ipv4ll.c \ src/network/networkd-dhcp4.c \ src/network/networkd-dhcp6.c \ + src/network/networkd-ndisc.h \ src/network/networkd-ndisc.c \ src/network/networkd-network.h \ src/network/networkd-network.c \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 821e22aff8..487bb2ab3f 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -528,23 +528,19 @@ IPv6AcceptRouterAdvertisements= - Force the setting of the accept_ra - (router advertisements) setting for the interface. - When unset, the kernel default is used, and router - advertisements are accepted only when local forwarding - is disabled for that interface. - When router advertisements are accepted, they will - trigger the start of the DHCPv6 client if the relevant - flags are passed, or if no routers are found on the link. - Takes a boolean. If true, router advertisements are - accepted, when false, router advertisements are ignored, - independently of the local forwarding state. - - See - ip-sysctl.txt - in the kernel documentation, but note that systemd's - setting of 1 corresponds to - kernel's setting of 2. + Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes + a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local + forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding + is disabled for that interface. When RAs are accepted, they may trigger the start of the DHCPv6 client if + the relevant flags are set in the RA data, or if no routers are found on the link. + + Further settings for the IPv6 RA support may be configured in the + [IPv6AcceptRouterAdvertisements] section, see below. + + Also see ip-sysctl.txt in the kernel + documentation regarding accept_ra, but note that systemd's setting of + 1 (i.e. true) corresponds to kernel's setting of 2. @@ -799,7 +795,7 @@ false. It is recommended to enable this option only on trusted networks, as setting this affects resolution - of all host names, in particular to single-label names. It is generally safer to use the supplied domain + of all host names, in particular of single-label names. It is generally safer to use the supplied domain only as routing domain, rather than as search domain, in order to not have it affect local resolution of single-label names. @@ -898,6 +894,47 @@ + + [IPv6AcceptRouterAdvertisements] Section Options + The [IPv6AcceptRouterAdvertisements] section configures the IPv6 Router Advertisement + (RA) client, if it is enabled with the IPv6AcceptRouterAdvertisements= setting described + above: + + + + UseDNS= + + When true (the default), the DNS servers received in the Router Advertisement will be used and take + precedence over any statically configured ones. + + This corresponds to the option in resolv.conf5. + + + + + UseDomains= + + Takes a boolean argument, or the special value route. When true, the domain name + received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to + the effect of the setting. If set to route, the domain name + received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the + effect of the setting when the argument is prefixed with + ~. Defaults to false. + + It is recommended to enable this option only on trusted networks, as setting this affects resolution + of all host names, in particular of single-label names. It is generally safer to use the supplied domain + only as routing domain, rather than as search domain, in order to not have it affect local resolution of + single-label names. + + When set to true, this setting corresponds to the option in resolv.conf5. + + + + + + [DHCPServer] Section Options The [DHCPServer] section contains diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index d81e9ebd88..c2e4b0e9e3 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -49,7 +49,8 @@ int icmp6_bind_router_solicitation(int index) { }; _cleanup_close_ int s = -1; char ifname[IF_NAMESIZE] = ""; - int r, zero = 0, one = 1, hops = 255; + static const int zero = 0, one = 1, hops = 255; + int r; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); if (s < 0) @@ -85,6 +86,10 @@ int icmp6_bind_router_solicitation(int index) { if (r < 0) return -errno; + r = setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); + if (r < 0) + return -errno; + if (if_indextoname(index, ifname) == 0) return -errno; diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h new file mode 100644 index 0000000000..60e183ff8c --- /dev/null +++ b/src/libsystemd-network/ndisc-internal.h @@ -0,0 +1,49 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include "log.h" + +#include "sd-ndisc.h" + +struct sd_ndisc { + unsigned n_ref; + + int ifindex; + int fd; + + sd_event *event; + int event_priority; + + struct ether_addr mac_addr; + uint8_t hop_limit; + uint32_t mtu; + + sd_event_source *recv_event_source; + sd_event_source *timeout_event_source; + + unsigned nd_sent; + + sd_ndisc_callback_t callback; + void *userdata; +}; + +#define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__) +#define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c new file mode 100644 index 0000000000..d9950b638c --- /dev/null +++ b/src/libsystemd-network/ndisc-router.c @@ -0,0 +1,779 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include + +#include "sd-ndisc.h" + +#include "alloc-util.h" +#include "dns-domain.h" +#include "hostname-util.h" +#include "missing.h" +#include "ndisc-internal.h" +#include "ndisc-router.h" +#include "strv.h" + +_public_ sd_ndisc_router* sd_ndisc_router_ref(sd_ndisc_router *rt) { + if (!rt) + return NULL; + + assert(rt->n_ref > 0); + rt->n_ref++; + + return rt; +} + +_public_ sd_ndisc_router* sd_ndisc_router_unref(sd_ndisc_router *rt) { + if (!rt) + return NULL; + + assert(rt->n_ref > 0); + rt->n_ref--; + + if (rt->n_ref > 0) + return NULL; + + free(rt); + return NULL; +} + +sd_ndisc_router *ndisc_router_new(size_t raw_size) { + sd_ndisc_router *rt; + + rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size); + if (!rt) + return NULL; + + rt->raw_size = raw_size; + rt->n_ref = 1; + + return rt; +} + +_public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size) { + _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(raw || raw_size <= 0, -EINVAL); + + rt = ndisc_router_new(raw_size); + if (!rt) + return -ENOMEM; + + memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size); + r = ndisc_router_parse(rt); + if (r < 0) + return r; + + *ret = rt; + rt = NULL; + + return r; +} + +_public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + if (in6_addr_is_null(&rt->address)) + return -ENODATA; + + *ret_addr = rt->address; + return 0; +} + +_public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) { + assert_return(rt, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&rt->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&rt->timestamp, clock); + return 0; +} + +_public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + *ret = NDISC_ROUTER_RAW(rt); + *size = rt->raw_size; + + return 0; +} + +int ndisc_router_parse(sd_ndisc_router *rt) { + struct nd_router_advert *a; + const uint8_t *p; + bool has_mtu = false, has_flag_extension = false; + size_t left; + + assert(rt); + + if (rt->raw_size < sizeof(struct nd_router_advert)) { + log_ndisc("Too small to be a router advertisement, ignoring."); + return -EBADMSG; + } + + /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */ + a = NDISC_ROUTER_RAW(rt); + + if (a->nd_ra_type != ND_ROUTER_ADVERT) { + log_ndisc("Received ND packet that is not a router advertisement, ignoring."); + return -EBADMSG; + } + + if (a->nd_ra_code != 0) { + log_ndisc("Received ND packet with wrong RA code, ignoring."); + return -EBADMSG; + } + + rt->hop_limit = a->nd_ra_curhoplimit; + rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */ + rt->lifetime = be16toh(a->nd_ra_router_lifetime); + + rt->preference = (rt->flags >> 3) & 3; + if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH)) + rt->preference = SD_NDISC_PREFERENCE_MEDIUM; + + p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert); + left = rt->raw_size - sizeof(struct nd_router_advert); + + for (;;) { + uint8_t type; + size_t length; + + if (left == 0) + break; + + if (left < 2) { + log_ndisc("Option lacks header, ignoring datagram."); + return -EBADMSG; + } + + type = p[0]; + length = p[1] * 8; + + if (length == 0) { + log_ndisc("Zero-length option, ignoring datagram."); + return -EBADMSG; + } + if (left < length) { + log_ndisc("Option truncated, ignoring datagram."); + return -EBADMSG; + } + + switch (type) { + + case SD_NDISC_OPTION_PREFIX_INFORMATION: + + if (length != 4*8) { + log_ndisc("Prefix option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + if (p[2] > 128) { + log_ndisc("Bad prefix length, ignoring datagram."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_MTU: { + uint32_t m; + + if (has_mtu) { + log_ndisc("MTU option specified twice, ignoring."); + continue; + } + + if (length != 8) { + log_ndisc("MTU option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + m = be32toh(*(uint32_t*) (p + 4)); + if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */ + rt->mtu = m; + + has_mtu = true; + break; + } + + case SD_NDISC_OPTION_ROUTE_INFORMATION: + if (length < 1*8 || length > 3*8) { + log_ndisc("Route information option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + if (p[2] > 128) { + log_ndisc("Bad route prefix length, ignoring datagram."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_RDNSS: + if (length < 3*8 || (length % (2*8)) != 1*8) { + log_ndisc("RDNSS option has invalid size."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_FLAGS_EXTENSION: + + if (has_flag_extension) { + log_ndisc("Flags extension option specified twice, ignoring."); + continue; + } + + if (length < 1*8) { + log_ndisc("Flags extension option has invalid size."); + return -EBADMSG; + } + + /* Add in the additional flags bits */ + rt->flags |= + ((uint64_t) p[2] << 8) | + ((uint64_t) p[3] << 16) | + ((uint64_t) p[4] << 24) | + ((uint64_t) p[5] << 32) | + ((uint64_t) p[6] << 40) | + ((uint64_t) p[7] << 48); + + has_flag_extension = true; + break; + + case SD_NDISC_OPTION_DNSSL: + if (length < 2*8) { + log_ndisc("DNSSL option has invalid size."); + return -EBADMSG; + } + + break; + } + + p += length, left -= length; + } + + rt->rindex = sizeof(struct nd_router_advert); + return 0; +} + +_public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = rt->hop_limit; + return 0; +} + +_public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) { + assert_return(rt, -EINVAL); + assert_return(ret_flags, -EINVAL); + + *ret_flags = rt->flags; + return 0; +} + +_public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) { + assert_return(rt, -EINVAL); + assert_return(ret_lifetime, -EINVAL); + + *ret_lifetime = rt->lifetime; + return 0; +} + +_public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = rt->preference; + return 0; +} + +_public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + if (rt->mtu <= 0) + return -ENODATA; + + *ret = rt->mtu; + return 0; +} + +_public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) { + assert_return(rt, -EINVAL); + + assert(rt->raw_size >= sizeof(struct nd_router_advert)); + rt->rindex = sizeof(struct nd_router_advert); + + return rt->rindex < rt->raw_size; +} + +_public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) { + size_t length; + + assert_return(rt, -EINVAL); + + if (rt->rindex == rt->raw_size) /* EOF */ + return -ESPIPE; + + if (rt->rindex + 2 > rt->raw_size) /* Truncated message */ + return -EBADMSG; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (rt->rindex + length > rt->raw_size) + return -EBADMSG; + + rt->rindex += length; + return rt->rindex < rt->raw_size; +} + +_public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + if (rt->rindex == rt->raw_size) /* EOF */ + return -ESPIPE; + + if (rt->rindex + 2 > rt->raw_size) /* Truncated message */ + return -EBADMSG; + + *ret = NDISC_ROUTER_OPTION_TYPE(rt); + return 0; +} + +_public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) { + uint8_t k; + int r; + + assert_return(rt, -EINVAL); + + r = sd_ndisc_router_option_get_type(rt, &k); + if (r < 0) + return r; + + return type == k; +} + +_public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) { + size_t length; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + /* Note that this returns the full option, including the option header */ + + if (rt->rindex + 2 > rt->raw_size) + return -EBADMSG; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (rt->rindex + length > rt->raw_size) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + *size = length; + + return 0; +} + +static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) { + struct nd_opt_prefix_info *ri; + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length != sizeof(struct nd_opt_prefix_info)) + return -EBADMSG; + + ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex); + if (ri->nd_opt_pi_prefix_len > 128) + return -EBADMSG; + + *ret = ri; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + struct nd_opt_prefix_info *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(ri->nd_opt_pi_valid_time); + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret = be32toh(pi->nd_opt_pi_preferred_time); + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret = pi->nd_opt_pi_flags_reserved; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret_addr = pi->nd_opt_pi_prefix; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + if (pi->nd_opt_pi_prefix_len > 128) + return -EBADMSG; + + *ret = pi->nd_opt_pi_prefix_len; + return 0; +} + +static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) { + uint8_t *ri; + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 1*8 || length > 3*8) + return -EBADMSG; + + ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + + if (ri[2] > 128) + return -EBADMSG; + + *ret = ri; + return 0; +} + +_public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} + +_public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + zero(*ret_addr); + memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8); + + return 0; +} + +_public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = ri[2]; + return 0; +} + +_public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = (ri[3] >> 3) & 3; + if (!IN_SET(*ret, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH)) + *ret = SD_NDISC_PREFERENCE_MEDIUM; + + return 0; +} + +static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) { + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 3*8 || (length % (2*8)) != 1*8) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + return 0; +} + +_public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_rdnss_info(rt, &ri); + if (r < 0) + return r; + + *ret = (const struct in6_addr*) (ri + 8); + return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16; +} + +_public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_rdnss_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} + +static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) { + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 2*8) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + return 0; +} + +_public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) { + _cleanup_strv_free_ char **l = NULL; + _cleanup_free_ char *e = NULL; + size_t allocated = 0, n = 0, left; + uint8_t *ri, *p; + bool first = true; + int r; + unsigned k = 0; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_dnssl_info(rt, &ri); + if (r < 0) + return r; + + p = ri + 8; + left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8; + + for (;;) { + if (left == 0) { + + if (n > 0) /* Not properly NUL terminated */ + return -EBADMSG; + + break; + } + + if (*p == 0) { + /* Found NUL termination */ + + if (n > 0) { + _cleanup_free_ char *normalized = NULL; + + e[n] = 0; + r = dns_name_normalize(e, &normalized); + if (r < 0) + return r; + + /* Ignore the root domain name or "localhost" and friends */ + if (!is_localhost(normalized) && + !dns_name_is_root(normalized)) { + + if (strv_push(&l, normalized) < 0) + return -ENOMEM; + + normalized = NULL; + k++; + } + } + + n = 0; + first = true; + p++, left--; + continue; + } + + /* Check for compression (which is not allowed) */ + if (*p > 63) + return -EBADMSG; + + if (1U + *p + 1U > left) + return -EBADMSG; + + if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U)) + return -ENOMEM; + + if (first) + first = false; + else + e[n++] = '.'; + + r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + n += r; + + left -= 1 + *p; + p += 1 + *p; + } + + if (strv_isempty(l)) { + *ret = NULL; + return 0; + } + + *ret = l; + l = NULL; + + return k; +} + +_public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_sec, -EINVAL); + + r = get_dnssl_info(rt, &ri); + if (r < 0) + return r; + + *ret_sec = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router.h new file mode 100644 index 0000000000..1fe703da63 --- /dev/null +++ b/src/libsystemd-network/ndisc-router.h @@ -0,0 +1,62 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include "sd-ndisc.h" + +#include "time-util.h" + +struct sd_ndisc_router { + unsigned n_ref; + + triple_timestamp timestamp; + struct in6_addr address; + + /* The raw packet size. The data is appended to the object, accessible via NDIS_ROUTER_RAW() */ + size_t raw_size; + + /* The current read index for the iterative option interface */ + size_t rindex; + + uint64_t flags; + unsigned preference; + uint16_t lifetime; + + uint8_t hop_limit; + uint32_t mtu; +}; + +static inline void* NDISC_ROUTER_RAW(const sd_ndisc_router *rt) { + return (uint8_t*) rt + ALIGN(sizeof(sd_ndisc_router)); +} + +static inline void *NDISC_ROUTER_OPTION_DATA(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_RAW(rt)) + rt->rindex; +} + +static inline uint8_t NDISC_ROUTER_OPTION_TYPE(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[0]; +} +static inline size_t NDISC_ROUTER_OPTION_LENGTH(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[1] * 8; +} + +sd_ndisc_router *ndisc_router_new(size_t raw_size); +int ndisc_router_parse(sd_ndisc_router *rt); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index ccb8002173..ea3fe369ce 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -19,165 +19,71 @@ #include #include -#include -#include -#include -#include #include "sd-ndisc.h" #include "alloc-util.h" -#include "async.h" +#include "fd-util.h" #include "icmp6-util.h" #include "in-addr-util.h" -#include "list.h" +#include "ndisc-internal.h" +#include "ndisc-router.h" #include "socket-util.h" #include "string-util.h" +#include "util.h" #define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC) -#define NDISC_MAX_ROUTER_SOLICITATIONS 3U +#define NDISC_MAX_ROUTER_SOLICITATIONS 3U -enum NDiscState { - NDISC_STATE_IDLE, - NDISC_STATE_SOLICITATION_SENT, - NDISC_STATE_ADVERTISEMENT_LISTEN, - _NDISC_STATE_MAX, - _NDISC_STATE_INVALID = -1, -}; +static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) { + assert(ndisc); -#define IP6_MIN_MTU 1280U -#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) -#define NDISC_OPT_LEN_UNITS 8U + log_ndisc("Invoking callback for '%c'.", event); -#define ND_RA_FLAG_PREF 0x18 -#define ND_RA_FLAG_PREF_LOW 0x03 -#define ND_RA_FLAG_PREF_MEDIUM 0x0 -#define ND_RA_FLAG_PREF_HIGH 0x1 -#define ND_RA_FLAG_PREF_INVALID 0x2 + if (!ndisc->callback) + return; -typedef struct NDiscPrefix NDiscPrefix; - -struct NDiscPrefix { - unsigned n_ref; - - sd_ndisc *nd; - - LIST_FIELDS(NDiscPrefix, prefixes); - - uint8_t len; - usec_t valid_until; - struct in6_addr addr; -}; - -struct sd_ndisc { - unsigned n_ref; - - enum NDiscState state; - int ifindex; - int fd; - - sd_event *event; - int event_priority; - - struct ether_addr mac_addr; - uint32_t mtu; - - LIST_HEAD(NDiscPrefix, prefixes); - - sd_event_source *recv_event_source; - sd_event_source *timeout_event_source; - - unsigned nd_sent; - - sd_ndisc_router_callback_t router_callback; - sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; - sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback; - sd_ndisc_callback_t callback; - void *userdata; -}; - -#define log_ndisc_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) -#define log_ndisc(p, fmt, ...) log_ndisc_errno(p, 0, fmt, ##__VA_ARGS__) - -static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { - - if (!prefix) - return NULL; - - assert(prefix->n_ref > 0); - prefix->n_ref--; - - if (prefix->n_ref > 0) - return NULL; - - if (prefix->nd) - LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix); - - free(prefix); - - return NULL; -} - -static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { - NDiscPrefix *prefix; - - assert(ret); - - prefix = new0(NDiscPrefix, 1); - if (!prefix) - return -ENOMEM; - - prefix->n_ref = 1; - LIST_INIT(prefixes, prefix); - prefix->nd = nd; - - *ret = prefix; - return 0; + ndisc->callback(ndisc, event, rt, ndisc->userdata); } -int sd_ndisc_set_callback( +_public_ int sd_ndisc_set_callback( sd_ndisc *nd, - sd_ndisc_router_callback_t router_callback, - sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback, - sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback, sd_ndisc_callback_t callback, void *userdata) { assert_return(nd, -EINVAL); - nd->router_callback = router_callback; - nd->prefix_onlink_callback = prefix_onlink_callback; - nd->prefix_autonomous_callback = prefix_autonomous_callback; nd->callback = callback; nd->userdata = userdata; return 0; } -int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { +_public_ int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { assert_return(nd, -EINVAL); assert_return(ifindex > 0, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); nd->ifindex = ifindex; return 0; } -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { +_public_ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { assert_return(nd, -EINVAL); if (mac_addr) - memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr)); + nd->mac_addr = *mac_addr; else zero(nd->mac_addr); return 0; - } -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { +_public_ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int r; assert_return(nd, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); assert_return(!nd->event, -EBUSY); if (event) @@ -193,21 +99,22 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { return 0; } -int sd_ndisc_detach_event(sd_ndisc *nd) { +_public_ int sd_ndisc_detach_event(sd_ndisc *nd) { + assert_return(nd, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); nd->event = sd_event_unref(nd->event); - return 0; } -sd_event *sd_ndisc_get_event(sd_ndisc *nd) { +_public_ sd_event *sd_ndisc_get_event(sd_ndisc *nd) { assert_return(nd, NULL); return nd->event; } -sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { +_public_ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { if (!nd) return NULL; @@ -221,15 +128,14 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { static int ndisc_reset(sd_ndisc *nd) { assert(nd); - nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); - nd->fd = asynchronous_close(nd->fd); nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); + nd->fd = safe_close(nd->fd); return 0; } -sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { - NDiscPrefix *prefix, *p; +_public_ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { if (!nd) return NULL; @@ -242,16 +148,12 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { ndisc_reset(nd); sd_ndisc_detach_event(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) - prefix = ndisc_prefix_unref(prefix); - free(nd); return NULL; } -int sd_ndisc_new(sd_ndisc **ret) { +_public_ int sd_ndisc_new(sd_ndisc **ret) { _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL; assert_return(ret, -EINVAL); @@ -261,223 +163,70 @@ int sd_ndisc_new(sd_ndisc **ret) { return -ENOMEM; nd->n_ref = 1; - nd->ifindex = -1; nd->fd = -1; - LIST_HEAD_INIT(nd->prefixes); - *ret = nd; nd = NULL; return 0; } -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { +_public_ int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { assert_return(nd, -EINVAL); assert_return(mtu, -EINVAL); if (nd->mtu == 0) - return -ENOMSG; + return -ENODATA; *mtu = nd->mtu; return 0; } -static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, - const struct in6_addr *addr, - uint8_t addr_prefixlen) { - uint8_t bytes, mask, len; - - assert(prefix); - assert(addr); - - len = MIN(prefixlen, addr_prefixlen); - - bytes = len / 8; - mask = 0xff << (8 - len % 8); +_public_ int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret) { + assert_return(nd, -EINVAL); + assert_return(ret, -EINVAL); - if (memcmp(prefix, addr, bytes) != 0 || - (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask)) - return -EADDRNOTAVAIL; + if (nd->hop_limit == 0) + return -ENODATA; + *ret = nd->hop_limit; return 0; } -static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr, - uint8_t addr_len, NDiscPrefix **result) { - NDiscPrefix *prefix, *p; - usec_t time_now; - int r; - - assert(nd); - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - if (prefix->valid_until < time_now) { - prefix = ndisc_prefix_unref(prefix); - continue; - } - - if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) { - *result = prefix; - return 0; - } - } - - return -EADDRNOTAVAIL; -} - -static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, - const struct nd_opt_prefix_info *prefix_opt) { - NDiscPrefix *prefix; - uint32_t lifetime_valid, lifetime_preferred; - usec_t time_now; - char time_string[FORMAT_TIMESPAN_MAX]; +static int ndisc_handle_datagram(sd_ndisc *nd, sd_ndisc_router *rt) { int r; assert(nd); - assert(prefix_opt); + assert(rt); - if (len < prefix_opt->nd_opt_pi_len) - return -EBADMSG; - - if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO))) + r = ndisc_router_parse(rt); + if (r == -EBADMSG) /* Bad packet */ return 0; - - if (in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &prefix_opt->nd_opt_pi_prefix) > 0) - return 0; - - lifetime_valid = be32toh(prefix_opt->nd_opt_pi_valid_time); - lifetime_preferred = be32toh(prefix_opt->nd_opt_pi_preferred_time); - - if (lifetime_valid < lifetime_preferred) - return 0; - - r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix, - prefix_opt->nd_opt_pi_prefix_len, &prefix); - if (r < 0) { - if (r != -EADDRNOTAVAIL) - return r; - - /* if router advertisement prefix valid timeout is zero, the timeout - callback will be called immediately to clean up the prefix */ - - r = ndisc_prefix_new(nd, &prefix); - if (r < 0) - return r; - - prefix->len = prefix_opt->nd_opt_pi_prefix_len; - - memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix, - sizeof(prefix->addr)); - - log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); - - LIST_PREPEND(prefixes, nd->prefixes, prefix); - - } else { - if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) { - uint8_t prefixlen; - - prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); - - log_ndisc(nd, "Prefix length mismatch %d/%d using %d", - prefix->len, - prefix_opt->nd_opt_pi_prefix_len, - prefixlen); - - prefix->len = prefixlen; - } - - log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); - } - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) - return r; - - prefix->valid_until = time_now + lifetime_valid * USEC_PER_SEC; - - if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && nd->prefix_onlink_callback) - nd->prefix_onlink_callback(nd, &prefix->addr, prefix->len, prefix->valid_until, nd->userdata); - - if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && nd->prefix_autonomous_callback) - nd->prefix_autonomous_callback(nd, &prefix->addr, prefix->len, lifetime_preferred, lifetime_valid, - nd->userdata); - - return 0; -} - -static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) { - struct nd_opt_hdr *opt_hdr; - void *opt; - - assert(nd); - assert(ra); - - if (len < sizeof(struct nd_router_advert) + NDISC_OPT_LEN_UNITS) { - log_ndisc(nd, "Router Advertisement below minimum length"); - return -EBADMSG; - } - - len -= sizeof(struct nd_router_advert); - opt = ra + 1; - opt_hdr = opt; - - while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) { - struct nd_opt_mtu *opt_mtu; - struct nd_opt_prefix_info *opt_prefix; - uint32_t mtu; - - if (opt_hdr->nd_opt_len == 0) - return -EBADMSG; - - switch (opt_hdr->nd_opt_type) { - - case ND_OPT_MTU: - opt_mtu = opt; - - mtu = be32toh(opt_mtu->nd_opt_mtu_mtu); - - if (mtu != nd->mtu) { - nd->mtu = MAX(mtu, IP6_MIN_MTU); - log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu); - } - - break; - - case ND_OPT_PREFIX_INFORMATION: - opt_prefix = opt; - ndisc_prefix_update(nd, len, opt_prefix); - break; - } + return 0; - len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS; - opt = (void*) ((uint8_t*) opt + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); - opt_hdr = opt; - } + /* Update global variables we keep */ + if (rt->mtu > 0) + nd->mtu = rt->mtu; + if (rt->hop_limit > 0) + nd->hop_limit = rt->hop_limit; - if (len > 0) - log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); + log_ndisc("Received Router Advertisement: flags %s preference %s lifetime %" PRIu16 " sec", + rt->flags & ND_RA_FLAG_MANAGED ? "MANAGED" : rt->flags & ND_RA_FLAG_OTHER ? "OTHER" : "none", + rt->preference == SD_NDISC_PREFERENCE_HIGH ? "high" : rt->preference == SD_NDISC_PREFERENCE_LOW ? "low" : "medium", + rt->lifetime); + ndisc_callback(nd, SD_NDISC_EVENT_ROUTER, rt); return 0; } -static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_free_ struct nd_router_advert *ra = NULL; +static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL; sd_ndisc *nd = userdata; union { struct cmsghdr cmsghdr; - uint8_t buf[CMSG_LEN(sizeof(int))]; + uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */ + CMSG_SPACE(sizeof(struct timeval))]; } control = {}; struct iovec iov = {}; union sockaddr_union sa = {}; @@ -490,10 +239,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t .msg_controllen = sizeof(control), }; struct cmsghdr *cmsg; - struct in6_addr *gw; - unsigned lifetime; ssize_t len, buflen; - int r, pref, stateful; assert(s); assert(nd); @@ -501,35 +247,47 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t buflen = next_datagram_size_fd(fd); if (buflen < 0) - return buflen; - - iov.iov_len = buflen; + return log_ndisc_errno(buflen, "Failed to determine datagram size to read: %m"); - ra = malloc(iov.iov_len); - if (!ra) + rt = ndisc_router_new(buflen); + if (!rt) return -ENOMEM; - iov.iov_base = ra; + iov.iov_base = NDISC_ROUTER_RAW(rt); + iov.iov_len = rt->raw_size; - len = recvmsg(fd, &msg, 0); + len = recvmsg(fd, &msg, MSG_DONTWAIT); if (len < 0) { if (errno == EAGAIN || errno == EINTR) return 0; - return log_ndisc_errno(nd, errno, "Could not receive message from ICMPv6 socket: %m"); + return log_ndisc_errno(errno, "Could not receive message from ICMPv6 socket: %m"); } - if ((size_t) len < sizeof(struct nd_router_advert)) { - log_ndisc(nd, "Too small to be a router advertisement: ignoring"); - return 0; + + if ((size_t) len != rt->raw_size) { + log_ndisc("Packet size mismatch."); + return -EINVAL; } - if (msg.msg_namelen == 0) - gw = NULL; /* only happens when running the test-suite over a socketpair */ - else if (msg.msg_namelen != sizeof(sa.in6)) { - log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen); - return 0; - } else - gw = &sa.in6.sin6_addr; + if (msg.msg_namelen == sizeof(struct sockaddr_in6) && + sa.in6.sin6_family == AF_INET6) { + + if (in_addr_is_link_local(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr) <= 0) { + _cleanup_free_ char *addr = NULL; + + (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr, &addr); + log_ndisc("Received RA from non-link-local address %s. Ignoring.", strna(addr)); + return 0; + } + + rt->address = sa.in6.sin6_addr; + + } else if (msg.msg_namelen > 0) { + log_ndisc("Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t) msg.msg_namelen); + return -EINVAL; + } + + /* namelen == 0 only happens when running the test-suite over a socketpair */ assert(!(msg.msg_flags & MSG_CTRUNC)); assert(!(msg.msg_flags & MSG_TRUNC)); @@ -538,61 +296,29 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { - int hops = *(int*)CMSG_DATA(cmsg); + int hops = *(int*) CMSG_DATA(cmsg); if (hops != 255) { - log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops); + log_ndisc("Received RA with invalid hop limit %d. Ignoring.", hops); return 0; } - - break; } - } - if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) { - _cleanup_free_ char *addr = NULL; - - (void)in_addr_to_string(AF_INET6, (const union in_addr_union*) gw, &addr); - - log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring.", strna(addr)); - return 0; + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMP && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + triple_timestamp_from_realtime(&rt->timestamp, timeval_load(CMSG_DATA(cmsg))); } - if (ra->nd_ra_type != ND_ROUTER_ADVERT) - return 0; - - if (ra->nd_ra_code != 0) - return 0; + if (!triple_timestamp_is_set(&rt->timestamp)) + triple_timestamp_get(&rt->timestamp); nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; - - stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); - pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3; - - if (!IN_SET(pref, ND_RA_FLAG_PREF_LOW, ND_RA_FLAG_PREF_HIGH)) - pref = ND_RA_FLAG_PREF_MEDIUM; - - lifetime = be16toh(ra->nd_ra_router_lifetime); - - log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %u sec", - stateful & ND_RA_FLAG_MANAGED ? "MANAGED" : stateful & ND_RA_FLAG_OTHER ? "OTHER" : "none", - pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium", - lifetime); - r = ndisc_ra_parse(nd, ra, (size_t) len); - if (r < 0) { - log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m"); - return 0; - } - - if (nd->router_callback) - nd->router_callback(nd, stateful, gw, lifetime, pref, nd->userdata); - - return 0; + return ndisc_handle_datagram(nd, rt); } -static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { +static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ndisc *nd = userdata; usec_t time_now, next_timeout; int r; @@ -601,43 +327,34 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, assert(nd); assert(nd->event); - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { - if (nd->callback) - nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata); - nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; - } else { - r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); - if (r < 0) { - log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m"); - goto fail; - } else { - nd->state = NDISC_STATE_SOLICITATION_SENT; - log_ndisc(nd, "Sent Router Solicitation"); - } - - nd->nd_sent++; + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + ndisc_callback(nd, SD_NDISC_EVENT_TIMEOUT, NULL); + return 0; + } - assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); + r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); + if (r < 0) { + log_ndisc_errno(r, "Error sending Router Solicitation: %m"); + goto fail; + } - next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; + log_ndisc("Sent Router Solicitation"); + nd->nd_sent++; - r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), - next_timeout, 0, - ndisc_router_solicitation_timeout, nd); - if (r < 0) { - log_ndisc_errno(nd, r, "Failed to allocate timer event: %m"); - goto fail; - } + assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); + next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; - r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); - if (r < 0) { - log_ndisc_errno(nd, r, "Cannot set timer priority: %m"); - goto fail; - } + r = sd_event_source_set_time(nd->timeout_event_source, next_timeout); + if (r < 0) { + log_ndisc_errno(r, "Error updating timer: %m"); + goto fail; + } - (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); + r = sd_event_source_set_enabled(nd->timeout_event_source, SD_EVENT_ONESHOT); + if (r < 0) { + log_ndisc_errno(r, "Error reenabling timer: %m"); + goto fail; } return 0; @@ -647,38 +364,36 @@ fail: return 0; } -int sd_ndisc_stop(sd_ndisc *nd) { +_public_ int sd_ndisc_stop(sd_ndisc *nd) { assert_return(nd, -EINVAL); - if (nd->state == NDISC_STATE_IDLE) + if (nd->fd < 0) return 0; - log_ndisc(nd, "Stopping IPv6 Router Solicitation client"); + log_ndisc("Stopping IPv6 Router Solicitation client"); ndisc_reset(nd); - nd->state = NDISC_STATE_IDLE; - - if (nd->callback) - nd->callback(nd, SD_NDISC_EVENT_STOP, nd->userdata); - - return 0; + return 1; } -int sd_ndisc_router_discovery_start(sd_ndisc *nd) { +_public_ int sd_ndisc_start(sd_ndisc *nd) { int r; assert_return(nd, -EINVAL); assert_return(nd->event, -EINVAL); assert_return(nd->ifindex > 0, -EINVAL); - assert_return(nd->state == NDISC_STATE_IDLE, -EBUSY); - r = icmp6_bind_router_solicitation(nd->ifindex); - if (r < 0) - return r; + if (nd->fd >= 0) + return 0; - nd->fd = r; + assert(!nd->recv_event_source); + assert(!nd->timeout_event_source); - r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd); + nd->fd = icmp6_bind_router_solicitation(nd->ifindex); + if (nd->fd < 0) + return nd->fd; + + r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_recv, nd); if (r < 0) goto fail; @@ -688,7 +403,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message"); - r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd); + r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_timeout, nd); if (r < 0) goto fail; @@ -698,8 +413,8 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); - log_ndisc(ns, "Started IPv6 Router Solicitation client"); - return 0; + log_ndisc("Started IPv6 Router Solicitation client"); + return 1; fail: ndisc_reset(nd); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index 4817c968ac..d9669488be 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -18,11 +18,15 @@ ***/ #include +#include #include "sd-ndisc.h" +#include "alloc-util.h" +#include "hexdecoct.h" #include "icmp6-util.h" #include "socket-util.h" +#include "strv.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} @@ -35,6 +39,144 @@ static int test_fd[2]; typedef int (*send_ra_t)(uint8_t flags); static send_ra_t send_ra_function; +static void router_dump(sd_ndisc_router *rt) { + struct in6_addr addr; + char buf[FORMAT_TIMESTAMP_MAX]; + uint8_t hop_limit; + uint64_t t, flags; + uint32_t mtu; + uint16_t lifetime; + unsigned preference; + int r; + + assert_se(rt); + + log_info("--"); + assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA); + + assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0); + log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t)); + + assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0); + log_info("Monotonic: %" PRIu64, t); + + if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0) + log_info("No hop limit set"); + else + log_info("Hop limit: %u", hop_limit); + + assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); + log_info("Flags: <%s|%s>", + flags & ND_RA_FLAG_OTHER ? "OTHER" : "", + flags & ND_RA_FLAG_MANAGED ? "MANAGED" : ""); + + assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0); + log_info("Preference: %s", + preference == SD_NDISC_PREFERENCE_LOW ? "low" : + preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium"); + + assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0); + log_info("Lifetime: %" PRIu16, lifetime); + + if (sd_ndisc_router_get_mtu(rt, &mtu) < 0) + log_info("No MTU set"); + else + log_info("MTU: %" PRIu32, mtu); + + r = sd_ndisc_router_option_rewind(rt); + for (;;) { + uint8_t type; + + assert_se(r >= 0); + + if (r == 0) + break; + + assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0); + + log_info(">> Option %u", type); + + switch (type) { + + case SD_NDISC_OPTION_SOURCE_LL_ADDRESS: + case SD_NDISC_OPTION_TARGET_LL_ADDRESS: { + _cleanup_free_ char *c = NULL; + const void *p; + size_t n; + + assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0); + assert_se(n > 2); + assert_se(c = hexmem((uint8_t*) p + 2, n - 2)); + + log_info("Address: %s", c); + break; + } + + case SD_NDISC_OPTION_PREFIX_INFORMATION: { + uint32_t lifetime_valid, lifetime_preferred; + unsigned prefix_len; + uint8_t pfl; + struct in6_addr a; + char buff[INET6_ADDRSTRLEN]; + + assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0); + log_info("Valid Lifetime: %" PRIu32, lifetime_valid); + + assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0); + log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred); + + assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0); + log_info("Flags: <%s|%s>", + pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "", + pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : ""); + + assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0); + log_info("Prefix Length: %u", prefix_len); + + assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0); + log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff))); + + break; + } + + case SD_NDISC_OPTION_RDNSS: { + const struct in6_addr *a; + uint32_t lt; + int n, i; + + n = sd_ndisc_router_rdnss_get_addresses(rt, &a); + assert_se(n > 0); + + for (i = 0; i < n; i++) { + char buff[INET6_ADDRSTRLEN]; + log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff))); + } + + assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, <) >= 0); + log_info("Lifetime: %" PRIu32, lt); + break; + } + + case SD_NDISC_OPTION_DNSSL: { + _cleanup_strv_free_ char **l = NULL; + uint32_t lt; + int n, i; + + n = sd_ndisc_router_dnssl_get_domains(rt, &l); + assert_se(n > 0); + + for (i = 0; i < n; i++) + log_info("Domain: %s", l[i]); + + assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, <) >= 0); + log_info("Lifetime: %" PRIu32, lt); + break; + }} + + r = sd_ndisc_router_option_next(rt); + } +} + static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) { assert_se(false); @@ -83,32 +225,39 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { return send_ra_function(0); } -static void test_rs_done(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { +static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { sd_event *e = userdata; static unsigned idx = 0; - uint8_t flags_array[] = { + uint64_t flags_array[] = { 0, 0, 0, ND_RA_FLAG_OTHER, ND_RA_FLAG_MANAGED }; + uint64_t flags; uint32_t mtu; assert_se(nd); + if (event != SD_NDISC_EVENT_ROUTER) + return; + + router_dump(rt); + + assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); assert_se(flags == flags_array[idx]); idx++; if (verbose) - printf(" got event 0x%02x\n", flags); + printf(" got event 0x%02" PRIx64 "\n", flags); if (idx < ELEMENTSOF(flags_array)) { send_ra(flags_array[idx]); return; } - assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG); + assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA); sd_event_exit(e, 0); } @@ -132,17 +281,17 @@ static void test_rs(void) { assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0); assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0); + assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0); assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), time_now + 2 *USEC_PER_SEC, 0, test_rs_hangcheck, NULL) >= 0); assert_se(sd_ndisc_stop(nd) >= 0); - assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_start(nd) >= 0); assert_se(sd_ndisc_stop(nd) >= 0); - assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_start(nd) >= 0); sd_event_loop(e); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 50721b1c74..15acf56a5f 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -60,10 +60,15 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, return 1; } -static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, - uint32_t lifetime_preferred, uint32_t lifetime_valid) { - int r; +static int dhcp6_address_change( + Link *link, + struct in6_addr *ip6_addr, + uint32_t lifetime_preferred, + uint32_t lifetime_valid) { + _cleanup_address_free_ Address *addr = NULL; + char buffer[INET6_ADDRSTRLEN]; + int r; r = address_new(&addr); if (r < 0) @@ -79,8 +84,8 @@ static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, - "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", - SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6), + "DHCPv6 address %s/%d timeout preferred %d valid %d", + inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_configure(addr, link, dhcp6_address_handler, true); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 90ed55d42c..11628339b9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -28,8 +28,9 @@ #include "fileio.h" #include "netlink-util.h" #include "network-internal.h" -#include "networkd.h" #include "networkd-lldp-tx.h" +#include "networkd-ndisc.h" +#include "networkd.h" #include "set.h" #include "socket-util.h" #include "stdio-util.h" @@ -504,7 +505,10 @@ static void link_free(Link *link) { sd_ipv4ll_unref(link->ipv4ll); sd_dhcp6_client_unref(link->dhcp6_client); - sd_ndisc_unref(link->ndisc_router_discovery); + sd_ndisc_unref(link->ndisc); + + set_free_free(link->ndisc_rdnss); + set_free_free(link->ndisc_dnssl); if (link->manager) hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); @@ -616,8 +620,8 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m"); } - if (link->ndisc_router_discovery) { - k = sd_ndisc_stop(link->ndisc_router_discovery); + if (link->ndisc) { + k = sd_ndisc_stop(link->ndisc); if (k < 0) r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } @@ -1453,11 +1457,11 @@ static int link_acquire_ipv6_conf(Link *link) { } if (link_ipv6_accept_ra_enabled(link)) { - assert(link->ndisc_router_discovery); + assert(link->ndisc); log_link_debug(link, "Discovering IPv6 routers"); - r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); + r = sd_ndisc_start(link->ndisc); if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); } @@ -3087,6 +3091,22 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in6_addrs(f, in6_addrs, r); + space = true; + } + } + + /* Make sure to flush out old entries before we use the NDISC data */ + ndisc_vacuum(link); + + if (link->network->dhcp_use_dns && link->ndisc_rdnss) { + NDiscRDNSS *dd; + + SET_FOREACH(dd, link->ndisc_rdnss, i) { + if (space) + fputc(' ', f); + + serialize_in6_addrs(f, &dd->address, 1); + space = true; } } @@ -3132,7 +3152,6 @@ int link_save(Link *link) { if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { if (link->dhcp_lease) (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); - if (dhcp6_lease) (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains); } @@ -3140,22 +3159,34 @@ int link_save(Link *link) { fputs("DOMAINS=", f); fputstrv(f, link->network->search_domains, NULL, &space); - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { + NDiscDNSSL *dd; - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + + SET_FOREACH(dd, link->ndisc_dnssl, i) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } fputc('\n', f); fputs("ROUTE_DOMAINS=", f); fputstrv(f, link->network->route_domains, NULL, NULL); - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { + NDiscDNSSL *dd; - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + + SET_FOREACH(dd, link->ndisc_dnssl, i) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } fputc('\n', f); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 5efefd27d6..7db94e79e8 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -98,6 +98,7 @@ typedef struct Link { unsigned dhcp4_messages; bool dhcp4_configured; bool dhcp6_configured; + unsigned ndisc_messages; bool ndisc_configured; @@ -111,7 +112,10 @@ typedef struct Link { sd_dhcp_server *dhcp_server; - sd_ndisc *ndisc_router_discovery; + sd_ndisc *ndisc; + Set *ndisc_rdnss; + Set *ndisc_dnssl; + sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; @@ -161,7 +165,6 @@ int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link, int ir); -int ndisc_configure(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index a0d4fa77d8..2a1ba2bac7 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -17,14 +17,15 @@ along with systemd; If not, see . ***/ -#include #include -#include -#include #include "sd-ndisc.h" #include "networkd.h" +#include "networkd-ndisc.h" + +#define NDISC_DNSSL_MAX 64U +#define NDISC_RDNSS_MAX 64U static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; @@ -49,19 +50,92 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void * return 1; } -static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) { - _cleanup_address_free_ Address *address = NULL; - Link *link = userdata; +static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { + _cleanup_route_free_ Route *route = NULL; + struct in6_addr gateway; + uint16_t lifetime; + unsigned preference; usec_t time_now; int r; - assert(nd); assert(link); - assert(link->network); + assert(rt); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + if (lifetime == 0) /* not a default router */ + return; + + r = sd_ndisc_router_get_address(rt, &gateway); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + + r = sd_ndisc_router_get_preference(rt, &preference); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m"); + return; + } + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = route_new(&route); + if (r < 0) { + log_link_error_errno(link, r, "Could not allocate route: %m"); + return; + } + + route->family = AF_INET6; + route->table = RT_TABLE_MAIN; + route->protocol = RTPROT_RA; + route->pref = preference; + route->gw.in6 = gateway; + route->lifetime = time_now + lifetime * USEC_PER_SEC; + + r = route_configure(route, link, ndisc_netlink_handler); + if (r < 0) { + log_link_warning_errno(link, r, "Could not set default route: %m"); + link_enter_failed(link); + return; + } + + link->ndisc_messages++; +} + +static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) { + _cleanup_address_free_ Address *address = NULL; + uint32_t lifetime_valid, lifetime_preferred; + unsigned prefixlen; + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix length: %m"); + return; + } + + r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m"); return; + } + + r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m"); + return; + } r = address_new(&address); if (r < 0) { @@ -69,10 +143,13 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - address->family = AF_INET6; - address->in_addr.in6 = *prefix; + r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix address: %m"); + return; + } + if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0) memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { @@ -102,17 +179,33 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr link->ndisc_messages++; } -static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) { +static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { _cleanup_route_free_ Route *route = NULL; - Link *link = userdata; usec_t time_now; + uint32_t lifetime; + unsigned prefixlen; int r; - assert(nd); assert(link); + assert(rt); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); return; + } + + r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix length: %m"); + return; + } + + r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix lifetime: %m"); + return; + } r = route_new(&route); if (r < 0) { @@ -120,16 +213,19 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - route->family = AF_INET6; route->table = RT_TABLE_MAIN; route->protocol = RTPROT_RA; route->flags = RTM_F_PREFIX; - route->dst.in6 = *prefix; route->dst_prefixlen = prefixlen; route->lifetime = time_now + lifetime * USEC_PER_SEC; + r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix address: %m"); + return; + } + r = route_configure(route, link, ndisc_netlink_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set prefix route: %m"); @@ -140,32 +236,47 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre link->ndisc_messages++; } -static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { +static void ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { _cleanup_route_free_ Route *route = NULL; - Link *link = userdata; + struct in6_addr gateway; + uint32_t lifetime; + unsigned preference, prefixlen; usec_t time_now; int r; assert(link); - assert(link->network); - assert(link->manager); - assert(link->dhcp6_client); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_route_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + if (lifetime == 0) return; - if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { - /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */ - r = dhcp6_request_address(link, flags & ND_RA_FLAG_MANAGED ? false : true); - if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); - else - log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); + r = sd_ndisc_router_get_address(rt, &gateway); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; } - if (!gateway) + r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get route prefix length: %m"); return; + } + + r = sd_ndisc_router_route_get_preference(rt, &preference); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m"); + return; + } + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } r = route_new(&route); if (r < 0) { @@ -173,18 +284,23 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - route->family = AF_INET6; route->table = RT_TABLE_MAIN; route->protocol = RTPROT_RA; - route->pref = pref; - route->gw.in6 = *gateway; + route->pref = preference; + route->gw.in6 = gateway; + route->dst_prefixlen = prefixlen; route->lifetime = time_now + lifetime * USEC_PER_SEC; + r = sd_ndisc_router_route_get_address(rt, &route->dst.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get route address: %m"); + return; + } + r = route_configure(route, link, ndisc_netlink_handler); if (r < 0) { - log_link_warning_errno(link, r, "Could not set default route: %m"); + log_link_warning_errno(link, r, "Could not set additional route: %m"); link_enter_failed(link); return; } @@ -192,7 +308,290 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a link->ndisc_messages++; } -static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { +static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) { + const NDiscRDNSS *x = p; + + siphash24_compress(&x->address, sizeof(x->address), state); +} + +static int ndisc_rdnss_compare_func(const void *_a, const void *_b) { + const NDiscRDNSS *a = _a, *b = _b; + + return memcmp(&a->address, &b->address, sizeof(a->address)); +} + +static const struct hash_ops ndisc_rdnss_hash_ops = { + .hash = ndisc_rdnss_hash_func, + .compare = ndisc_rdnss_compare_func +}; + +static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { + uint32_t lifetime; + const struct in6_addr *a; + usec_t time_now; + int i, n, r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m"); + return; + } + + n = sd_ndisc_router_rdnss_get_addresses(rt, &a); + if (n < 0) { + log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m"); + return; + } + + for (i = 0; i < n; i++) { + NDiscRDNSS d = { + .address = a[i] + }, *x; + + if (lifetime == 0) { + (void) set_remove(link->ndisc_rdnss, &d); + link_dirty(link); + continue; + } + + x = set_get(link->ndisc_rdnss, &d); + if (x) { + x->valid_until = time_now + lifetime * USEC_PER_SEC; + continue; + } + + ndisc_vacuum(link); + + if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) { + log_link_warning(link, "Too many RDNSS records per link, ignoring."); + continue; + } + + r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops); + if (r < 0) { + log_oom(); + return; + } + + x = new0(NDiscRDNSS, 1); + if (!x) { + log_oom(); + return; + } + + x->address = a[i]; + x->valid_until = time_now + lifetime * USEC_PER_SEC; + + r = set_put(link->ndisc_rdnss, x); + if (r < 0) { + free(x); + log_oom(); + return; + } + + assert(r > 0); + link_dirty(link); + } +} + +static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) { + const NDiscDNSSL *x = p; + + siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state); +} + +static int ndisc_dnssl_compare_func(const void *_a, const void *_b) { + const NDiscDNSSL *a = _a, *b = _b; + + return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b)); +} + +static const struct hash_ops ndisc_dnssl_hash_ops = { + .hash = ndisc_dnssl_hash_func, + .compare = ndisc_dnssl_compare_func +}; + +static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { + _cleanup_strv_free_ char **l = NULL; + uint32_t lifetime; + usec_t time_now; + char **i; + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m"); + return; + } + + r = sd_ndisc_router_dnssl_get_domains(rt, &l); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m"); + return; + } + + STRV_FOREACH(i, l) { + struct { + NDiscDNSSL header; + char domain[strlen(*i)]; + } s; + NDiscDNSSL *x; + + zero(s.header); + strcpy(s.domain, *i); + + if (lifetime == 0) { + (void) set_remove(link->ndisc_dnssl, &s); + link_dirty(link); + continue; + } + + x = set_get(link->ndisc_dnssl, &s); + if (x) { + x->valid_until = time_now + lifetime * USEC_PER_SEC; + continue; + } + + ndisc_vacuum(link); + + if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) { + log_link_warning(link, "Too many DNSSL records per link, ignoring."); + continue; + } + + r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops); + if (r < 0) { + log_oom(); + return; + } + + x = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1); + if (!x) { + log_oom(); + return; + } + + strcpy(NDISC_DNSSL_DOMAIN(x), *i); + x->valid_until = time_now + lifetime * USEC_PER_SEC; + + r = set_put(link->ndisc_dnssl, x); + if (r < 0) { + free(x); + log_oom(); + return; + } + + assert(r > 0); + link_dirty(link); + } +} + +static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_option_rewind(rt); + for (;;) { + uint8_t type; + + if (r < 0) { + log_link_warning_errno(link, r, "Failed to iterate through options: %m"); + return; + } + if (r == 0) /* EOF */ + break; + + r = sd_ndisc_router_option_get_type(rt, &type); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA option type: %m"); + return; + } + + switch (type) { + + case SD_NDISC_OPTION_PREFIX_INFORMATION: { + uint8_t flags; + + r = sd_ndisc_router_prefix_get_flags(rt, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m"); + return; + } + + if (flags & ND_OPT_PI_FLAG_ONLINK) + ndisc_router_process_onlink_prefix(link, rt); + if (flags & ND_OPT_PI_FLAG_AUTO) + ndisc_router_process_autonomous_prefix(link, rt); + + break; + } + + case SD_NDISC_OPTION_ROUTE_INFORMATION: + ndisc_router_process_route(link, rt); + break; + + case SD_NDISC_OPTION_RDNSS: + ndisc_router_process_rdnss(link, rt); + break; + + case SD_NDISC_OPTION_DNSSL: + ndisc_router_process_dnssl(link, rt); + break; + } + + r = sd_ndisc_router_option_next(rt); + } +} + +static void ndisc_router_handler(Link *link, sd_ndisc_router *rt) { + uint64_t flags; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + assert(rt); + + r = sd_ndisc_router_get_flags(rt, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA flags: %m"); + return; + } + + if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { + /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */ + r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED)); + if (r < 0 && r != -EBUSY) + log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); + else + log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); + } + + ndisc_router_process_default(link, rt); + ndisc_router_process_options(link, rt); +} + +static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { Link *link = userdata; assert(link); @@ -201,12 +600,15 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { return; switch (event) { + + case SD_NDISC_EVENT_ROUTER: + ndisc_router_handler(link, rt); + break; + case SD_NDISC_EVENT_TIMEOUT: link->ndisc_configured = true; link_check_ready(link); - break; - case SD_NDISC_EVENT_STOP: break; default: log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event); @@ -216,30 +618,52 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { int ndisc_configure(Link *link) { int r; - assert_return(link, -EINVAL); + assert(link); + + r = sd_ndisc_new(&link->ndisc); + if (r < 0) + return r; - r = sd_ndisc_new(&link->ndisc_router_discovery); + r = sd_ndisc_attach_event(link->ndisc, NULL, 0); if (r < 0) return r; - r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0); + r = sd_ndisc_set_mac(link->ndisc, &link->mac); if (r < 0) return r; - r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac); + r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex); if (r < 0) return r; - r = sd_ndisc_set_ifindex(link->ndisc_router_discovery, link->ifindex); + r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link); if (r < 0) return r; - r = sd_ndisc_set_callback(link->ndisc_router_discovery, - ndisc_router_handler, - ndisc_prefix_onlink_handler, - ndisc_prefix_autonomous_handler, - ndisc_handler, - link); + return 0; +} + +void ndisc_vacuum(Link *link) { + NDiscRDNSS *r; + NDiscDNSSL *d; + Iterator i; + usec_t time_now; + + assert(link); + + /* Removes all RDNSS and DNSSL entries whose validity time has passed */ + + time_now = now(clock_boottime_or_monotonic()); + + SET_FOREACH(r, link->ndisc_rdnss, i) + if (r->valid_until < time_now) { + (void) set_remove(link->ndisc_rdnss, r); + link_dirty(link); + } - return r; + SET_FOREACH(d, link->ndisc_dnssl, i) + if (d->valid_until < time_now) { + (void) set_remove(link->ndisc_dnssl, d); + link_dirty(link); + } } diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h new file mode 100644 index 0000000000..2002f55107 --- /dev/null +++ b/src/network/networkd-ndisc.h @@ -0,0 +1,39 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + 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 . +***/ + +#include "networkd-link.h" + +typedef struct NDiscRDNSS { + usec_t valid_until; + struct in6_addr address; +} NDiscRDNSS; + +typedef struct NDiscDNSSL { + usec_t valid_until; + /* The domain name follows immediately. */ +} NDiscDNSSL; + +static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) { + return ((char*) n) + ALIGN(sizeof(NDiscDNSSL)); +} + +int ndisc_configure(Link *link); +void ndisc_vacuum(Link *link); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 03e4e3b39f..c722db55c7 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -89,6 +89,8 @@ DHCP.DUIDRawData, config_parse_duid_rawdata, DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +IPv6AcceptRouterAdvertisements.UseDNS config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) +IPv6AcceptRouterAdvertisements.UseDomains config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index dd89b3770c..e961db60a7 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -51,8 +51,8 @@ static int network_load_one(Manager *manager, const char *filename) { if (!file) { if (errno == ENOENT) return 0; - else - return -errno; + + return -errno; } if (null_or_empty_fd(fileno(file))) { @@ -134,6 +134,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_hop_limit = -1; network->duid.type = _DUID_TYPE_INVALID; network->proxy_arp = -1; + network->ipv6_accept_ra_use_dns = true; r = config_parse(NULL, filename, file, "Match\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 91099161ce..b54616b838 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -154,6 +154,9 @@ struct Network { int ipv6_hop_limit; int proxy_arp; + bool ipv6_accept_ra_use_dns; + DHCPUseDomains ipv6_accept_ra_use_domains; + union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 2b774233b8..9f7d4ef71a 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include "sd-event.h" @@ -29,55 +31,99 @@ _SD_BEGIN_DECLARATIONS; +/* Neightbor Discovery Options, RFC 4861, Section 4.6 and + * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ enum { - SD_NDISC_EVENT_STOP = 0, - SD_NDISC_EVENT_TIMEOUT = 1, + SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, + SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, + SD_NDISC_OPTION_PREFIX_INFORMATION = 3, + SD_NDISC_OPTION_MTU = 5, + SD_NDISC_OPTION_ROUTE_INFORMATION = 24, + SD_NDISC_OPTION_RDNSS = 25, + SD_NDISC_OPTION_FLAGS_EXTENSION = 26, + SD_NDISC_OPTION_DNSSL = 31, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, +}; + +/* Route preference, RFC 4191, Section 2.1 */ +enum { + SD_NDISC_PREFERENCE_LOW = 3U, + SD_NDISC_PREFERENCE_MEDIUM = 0U, + SD_NDISC_PREFERENCE_HIGH = 1U, }; typedef struct sd_ndisc sd_ndisc; +typedef struct sd_ndisc_router sd_ndisc_router; -typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata); -typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime, void *userdata); -typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata); -typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata); - -int sd_ndisc_set_callback(sd_ndisc *nd, - sd_ndisc_router_callback_t rcb, - sd_ndisc_prefix_onlink_callback_t plcb, - sd_ndisc_prefix_autonomous_callback_t pacb, - sd_ndisc_callback_t cb, - void *userdata); -int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); +typedef enum sd_ndisc_event { + SD_NDISC_EVENT_TIMEOUT = 't', + SD_NDISC_EVENT_ROUTER = 'r', +} sd_ndisc_event; -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); -int sd_ndisc_detach_event(sd_ndisc *nd); -sd_event *sd_ndisc_get_event(sd_ndisc *nd); +typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); +int sd_ndisc_new(sd_ndisc **ret); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); -int sd_ndisc_new(sd_ndisc **ret); - -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); +int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd); -int sd_ndisc_router_discovery_start(sd_ndisc *nd); -#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata); +int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ - be16toh((address).s6_addr16[0]), \ - be16toh((address).s6_addr16[1]), \ - be16toh((address).s6_addr16[2]), \ - be16toh((address).s6_addr16[3]), \ - be16toh((address).s6_addr16[4]), \ - be16toh((address).s6_addr16[5]), \ - be16toh((address).s6_addr16[6]), \ - be16toh((address).s6_addr16[7]) +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret); +int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret); + +int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); +sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); +sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); + +int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags); +int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime); +int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); + +/* Generic option access */ +int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); +int sd_ndisc_router_option_next(sd_ndisc_router *rt); +int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); +int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ +int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); + +/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ +int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); +int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); + +/* Specific option access: SD_NDISC_OPTION_RDNSS */ +int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); +int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); + +/* Specific option access: SD_NDISC_OPTION_DNSSL */ +int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); +int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); _SD_END_DECLARATIONS; -- cgit v1.2.3-54-g00ecf From 53203e5f8f9a79d0ad774e29ea165b471e64619f Mon Sep 17 00:00:00 2001 From: michaelolbrich Date: Mon, 6 Jun 2016 21:59:51 +0200 Subject: mount: make sure got into MOUNT_DEAD state after a successful umount (#3444) Without this code the following can happen: 1. Open a file to keep a mount busy 2. Try to stop the corresponding mount unit with systemctl -> umount fails and the failure is remembered in mount->result 3. Close the file and umount the filesystem manually -> mount_dispatch_io() calls "mount_enter_dead(mount, MOUNT_SUCCESS)" -> Old error in mount->result is reused and the mount unit enters a failed state Clear the old error result when 'mountinfo' reports a successful umount to fix this. --- src/core/mount.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 665a60bb55..8290ac859d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1706,6 +1706,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, /* This has just been unmounted by * somebody else, follow the state * change. */ + mount->result = MOUNT_SUCCESS; mount_enter_dead(mount, MOUNT_SUCCESS); break; -- cgit v1.2.3-54-g00ecf From cf6f7f66a4aff31286b2da850dd2d41595cf1f99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Jun 2016 22:03:31 +0200 Subject: core: add minor comment Let's explain #3444 briefly in the sources, too. --- src/core/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 8290ac859d..fda4d65d6f 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1706,7 +1706,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, /* This has just been unmounted by * somebody else, follow the state * change. */ - mount->result = MOUNT_SUCCESS; + mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */ mount_enter_dead(mount, MOUNT_SUCCESS); break; -- cgit v1.2.3-54-g00ecf From bdc49d4491da97f7821c34740bcfd26d472085a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Jun 2016 22:04:33 +0200 Subject: cgtop: minimize aux variable scope --- src/cgtop/cgtop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 6bd2288897..c67b328b38 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -868,14 +868,16 @@ static int get_cgroup_root(char **ret) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *unit = NULL, *path = NULL; - char *aux; const char *m; int r; if (arg_root) { + char *aux; + aux = strdup(arg_root); if (!aux) return log_oom(); + *ret = aux; return 0; } -- cgit v1.2.3-54-g00ecf From 138f4c69064504bf7ef83cc8a53133f007ad84d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jun 2016 10:23:20 +0200 Subject: fstab-generator: don't process root= if it happens to be "gpt-auto" (#3452) As that's handled by "gpt-auto-generator". Fixes: #3404 --- src/fstab-generator/fstab-generator.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 108522873e..fc7cf39847 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -496,6 +496,12 @@ static int add_sysroot_mount(void) { return 0; } + if (streq(arg_root_what, "gpt-auto")) { + /* This is handled by the gpt-auto generator */ + log_debug("Skipping root directory handling, as gpt-auto was requested."); + return 0; + } + what = fstab_node_to_udev_node(arg_root_what); if (!what) return log_oom(); -- cgit v1.2.3-54-g00ecf From 82e4eda664d40ef60829e27d84b1610c2f4070cd Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 7 Jun 2016 10:38:33 +0200 Subject: sd-netlink: fix deep recursion in message destruction (#3455) On larger systems we might very well see messages with thousands of parts. When we free them, we must avoid recursing into each part, otherwise we very likely get stack overflows. Fix sd_netlink_message_unref() to use an iterative approach rather than recursion (also avoid tail-recursion in case it is not optimized by the compiler). --- src/libsystemd/sd-netlink/netlink-message.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 86d8dee867..df3b3c922e 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -120,7 +120,9 @@ sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) { } sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) { - if (m && REFCNT_DEC(m->n_ref) == 0) { + sd_netlink_message *t; + + while (m && REFCNT_DEC(m->n_ref) == 0) { unsigned i; free(m->hdr); @@ -128,9 +130,9 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) { for (i = 0; i <= m->n_containers; i++) free(m->containers[i].attributes); - sd_netlink_message_unref(m->next); - - free(m); + t = m; + m = m->next; + free(t); } return NULL; -- cgit v1.2.3-54-g00ecf From f921f5739e003c5e99cd78cfedab253be884525e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jun 2016 11:19:26 +0200 Subject: networkd: rename IPv6AcceptRouterAdvertisements to IPv6AcceptRA The long name is just too hard to type. We generally should avoid using acronyms too liberally, if they aren't established enough, but it appears that "RA" is known well enough. Internally we call the option "ipv6_accept_ra" anyway, and the kernel also exposes it under this name. Hence, let's rename the IPv6AcceptRouterAdvertisements= setting and the [IPv6AcceptRouterAdvertisements] section to IPv6AcceptRA= and [IPv6AcceptRA]. The old setting IPv6AcceptRouterAdvertisements= is kept for compatibility with older configuration. (However the section [IPv6AcceptRouterAdvertisements] is not, as it was never available in a published version of systemd. --- man/systemd.network.xml | 12 ++++++------ src/network/networkd-network-gperf.gperf | 6 ++++-- src/network/networkd-network.c | 1 + test/networkd-test.py | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 487bb2ab3f..24deb0d1d7 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -240,7 +240,7 @@ By enabling DHCPv6 support explicitly, the DHCPv6 client will be started regardless of the presence of routers on the link, or what flags the routers pass. See - IPv6AcceptRouterAdvertisements=. + IPv6AcceptRA=. Furthermore, note that by default the domain name specified through DHCP is not used for name resolution. @@ -527,7 +527,7 @@ no. - IPv6AcceptRouterAdvertisements= + IPv6AcceptRA= Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding @@ -535,7 +535,7 @@ the relevant flags are set in the RA data, or if no routers are found on the link. Further settings for the IPv6 RA support may be configured in the - [IPv6AcceptRouterAdvertisements] section, see below. + [IPv6AcceptRA] section, see below. Also see ip-sysctl.txt in the kernel @@ -895,9 +895,9 @@ - [IPv6AcceptRouterAdvertisements] Section Options - The [IPv6AcceptRouterAdvertisements] section configures the IPv6 Router Advertisement - (RA) client, if it is enabled with the IPv6AcceptRouterAdvertisements= setting described + [IPv6AcceptRA] Section Options + The [IPv6AcceptRA] section configures the IPv6 Router Advertisement + (RA) client, if it is enabled with the IPv6AcceptRA= setting described above: diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index c722db55c7..d9f5b95cdf 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -55,6 +55,8 @@ Network.NTP, config_parse_strv, Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) +Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) +/* legacy alias for the above */ Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) @@ -89,8 +91,8 @@ DHCP.DUIDRawData, config_parse_duid_rawdata, DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) -IPv6AcceptRouterAdvertisements.UseDNS config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) -IPv6AcceptRouterAdvertisements.UseDomains config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) +IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) +IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index e961db60a7..c03c0f0bed 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -145,6 +145,7 @@ static int network_load_one(Manager *manager, const char *filename) { "DHCP\0" "DHCPv4\0" /* compat */ "DHCPServer\0" + "IPv6AcceptRA\0" "Bridge\0" "BridgeFDB\0", config_item_perf_lookup, network_network_gperf_lookup, diff --git a/test/networkd-test.py b/test/networkd-test.py index f94224cce2..78da0a213a 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -205,7 +205,7 @@ DHCP=%s def test_coldplug_dhcp_yes_ip4_no_ra(self): # with disabling RA explicitly things should be fast self.do_test(coldplug=True, ipv6=False, - extra_opts='IPv6AcceptRouterAdvertisements=False') + extra_opts='IPv6AcceptRA=False') def test_coldplug_dhcp_ip4_only(self): # we have a 12s timeout on RA, so we need to wait longer @@ -215,7 +215,7 @@ DHCP=%s def test_coldplug_dhcp_ip4_only_no_ra(self): # with disabling RA explicitly things should be fast self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', - extra_opts='IPv6AcceptRouterAdvertisements=False') + extra_opts='IPv6AcceptRA=False') def test_coldplug_dhcp_ip6(self): self.do_test(coldplug=True, ipv6=True) -- cgit v1.2.3-54-g00ecf From ea683512f9b82f2257770f0ed56d819eea230fc2 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 7 Jun 2016 20:47:41 +0300 Subject: hwdb: selinuxify a bit (#3460) -bash-4.3# rm /etc/udev/hwdb.bin -bash-4.3# systemd-hwdb update -bash-4.3# ls -Z /etc/udev/hwdb.bin system_u:object_r:systemd_hwdb_etc_t:s0 /etc/udev/hwdb.bin Fixes: #3458 --- src/hwdb/hwdb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 1160dacdf1..e12cd93d1c 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -29,7 +29,9 @@ #include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" +#include "label.h" #include "mkdir.h" +#include "selinux-util.h" #include "strbuf.h" #include "string-util.h" #include "strv.h" @@ -643,12 +645,12 @@ static int hwdb_update(int argc, char *argv[], void *userdata) { if (!hwdb_bin) return -ENOMEM; - mkdir_parents(hwdb_bin, 0755); + mkdir_parents_label(hwdb_bin, 0755); r = trie_store(trie, hwdb_bin); if (r < 0) return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin); - return 0; + return label_fix(hwdb_bin, false, false); } static void help(void) { @@ -732,6 +734,8 @@ int main (int argc, char *argv[]) { if (r <= 0) goto finish; + mac_selinux_init(); + r = hwdb_main(argc, argv); finish: -- cgit v1.2.3-54-g00ecf From b9c59555b1b06b28a8ec0d99348b7864d3ad5465 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 10:18:56 +0200 Subject: sysv-generator: remove more dead code (#3462) The changes in 788d2b088b13a2444b9eb2ea82c0cc57d9f0980f weren't complete, only half the code that dealt with K links was removed. This is a follow-up patch that removes the rest too. No functional changes. --- src/sysv-generator/sysv-generator.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 4e12071e93..3ed8f23ff9 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -856,7 +856,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic _cleanup_free_ char *name = NULL, *fpath = NULL; int a, b; - if (de->d_name[0] != 'S' && de->d_name[0] != 'K') + if (de->d_name[0] != 'S') continue; if (strlen(de->d_name) < 4) @@ -886,28 +886,23 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic continue; } - if (de->d_name[0] == 'S') { + service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); - service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); - - r = set_ensure_allocated(&runlevel_services[i], NULL); - if (r < 0) { - log_oom(); - goto finish; - } - - r = set_put(runlevel_services[i], service); - if (r < 0) { - log_oom(); - goto finish; - } + r = set_ensure_allocated(&runlevel_services[i], NULL); + if (r < 0) { + log_oom(); + goto finish; + } + r = set_put(runlevel_services[i], service); + if (r < 0) { + log_oom(); + goto finish; } } } } - for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) SET_FOREACH(service, runlevel_services[i], j) { r = strv_extend(&service->before, rcnd_table[i].target); -- cgit v1.2.3-54-g00ecf From 8121f4d209eca85dcb11830800483cdfafbef9b7 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Wed, 8 Jun 2016 18:08:56 +0200 Subject: logind: really handle *KeyIgnoreInhibited options in logind.conf --- src/login/logind-action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 9a8089f97c..95a2a01173 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -85,7 +85,7 @@ int manager_handle_action( } /* If the key handling is inhibited, don't do anything */ - if (inhibit_key > 0) { + if (!ignore_inhibited && inhibit_key > 0) { if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) { log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key)); return 0; -- cgit v1.2.3-54-g00ecf From a1a8e4f5e9d87c386c630482dd288c0e354ff971 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Wed, 8 Jun 2016 18:16:42 +0200 Subject: logind: minor cleanup and use IN_SET() in manager_handle_action() --- src/login/logind-action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 95a2a01173..8ef48dbaa1 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -124,7 +124,7 @@ int manager_handle_action( return -EALREADY; } - inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE || handle == HANDLE_HYBRID_SLEEP ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; + inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; /* If the actual operation is inhibited, warn and fail */ if (!ignore_inhibited && -- cgit v1.2.3-54-g00ecf From 1ff74fb6e3243a2ade9ac38aa5effccb25432ad1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 10:01:16 +0200 Subject: execute: check whether the specified fd is a tty before chowning/chmoding it (#3457) Let's add an extra safety check before we chmod/chown a TTY to the right user, as we might end up having connected something to STDIN/STDOUT that is actually not a TTY, even though this might have been requested, due to permissive StandardInput= settings or transient service activation with fds passed in. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85255 --- src/core/execute.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 2cef70e668..e718c43df9 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -552,6 +552,10 @@ static int chown_terminal(int fd, uid_t uid) { assert(fd >= 0); + /* Before we chown/chmod the TTY, let's ensure this is actually a tty */ + if (isatty(fd) < 1) + return 0; + /* This might fail. What matters are the results. */ (void) fchown(fd, uid, -1); (void) fchmod(fd, TTY_MODE); -- cgit v1.2.3-54-g00ecf From 9d3e340639bc0b4610f7ece98a84157dbc1c2c8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 10:49:36 +0200 Subject: load-fragment: don't try to do a template instance replacement if we are not an instance (#3451) Corrects: 7aad67e7 Fixes: #3438 --- src/core/load-fragment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b53301a147..2d8f6296c8 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3743,7 +3743,7 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { /* If the symlink name we are looking at is unit template, then we must search for instance of this template */ - if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) { + if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) { _cleanup_free_ char *instance = NULL; r = unit_name_replace_instance(k, (*u)->instance, &instance); -- cgit v1.2.3-54-g00ecf From a3071999b83f53b37b24140baf64ef771b9f3e26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 10:51:20 +0200 Subject: udev-builtin-blkid: fix GPT_FLAG_NO_AUTO check for ESP (#3450) The flags check was accidentally placed in the ESP if block, but should be in the root if block. This corrects: 0238d4c660e732dd03ba0cdb54a29ec5870ee849 Fixes: #3440 Also see: #3441 --- src/udev/udev-builtin-blkid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index ed0ea5ce5f..3c58445836 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -147,11 +147,6 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) { if (sd_id128_equal(type, GPT_ESP)) { sd_id128_t id, esp; - unsigned long long flags; - - flags = blkid_partition_get_flags(pp); - if (flags & GPT_FLAG_NO_AUTO) - continue; /* We found an ESP, let's see if it matches * the ESP we booted from. */ @@ -167,6 +162,11 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) { found_esp = true; } else if (sd_id128_equal(type, GPT_ROOT_NATIVE)) { + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & GPT_FLAG_NO_AUTO) + continue; /* We found a suitable root partition, let's * remember the first one. */ -- cgit v1.2.3-54-g00ecf From 52e045f9b8c3228db8ef2d8b53e099c654056fcc Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 9 Jun 2016 21:11:35 +0530 Subject: bus_util: add support to map double (#3479) Now we don't support parsing double at map_basic. when trying to use bus_message_map_all_properties with a double this fails. Let's add it. --- src/shared/bus-util.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 4efbf3710f..8cfa936347 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1085,6 +1085,19 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ break; } + case SD_BUS_TYPE_DOUBLE: { + double d; + double *p = userdata; + + r = sd_bus_message_read_basic(m, type, &d); + if (r < 0) + break; + + *p = d; + + break; + } + default: break; } -- cgit v1.2.3-54-g00ecf From 267fabd2ab3c05e9899e4f238ac090b0d3943739 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 18:55:16 +0200 Subject: networkd: clean up vlan handling a bit (#3478) Let's add a generic parser for VLAN ids, which should become handy as preparation for PR #3428. Let's also make sure we use uint16_t for the vlan ID type everywhere, and that validity checks are already applied at the time of parsing, and not only whne we about to prepare a netdev. Also, establish a common definition VLANID_INVALID we can use for non-initialized VLAN id fields. --- Makefile.am | 2 + src/network/networkd-netdev-gperf.gperf | 5 ++- src/network/networkd-netdev-vlan.c | 15 ++++--- src/network/networkd-netdev-vlan.h | 4 +- src/shared/vlan-util.c | 69 +++++++++++++++++++++++++++++++++ src/shared/vlan-util.h | 35 +++++++++++++++++ 6 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 src/shared/vlan-util.c create mode 100644 src/shared/vlan-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 9a34c686d5..d233614403 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1042,6 +1042,8 @@ libshared_la_SOURCES = \ src/shared/resolve-util.h \ src/shared/bus-unit-util.c \ src/shared/bus-unit-util.h \ + src/shared/vlan-util.h \ + src/shared/vlan-util.c \ src/shared/tests.h \ src/shared/tests.c diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index adc64977b9..a9512cd77b 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -3,6 +3,7 @@ #include "conf-parser.h" #include "network-internal.h" #include "networkd-netdev-bond.h" +#include "networkd-netdev-bridge.h" #include "networkd-netdev-ipvlan.h" #include "networkd-netdev-macvlan.h" #include "networkd-netdev-tunnel.h" @@ -10,8 +11,8 @@ #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" -#include "networkd-netdev-bridge.h" #include "networkd-netdev.h" +#include "vlan-util.h" %} struct ConfigPerfItem; %null_strings @@ -33,7 +34,7 @@ NetDev.Name, config_parse_ifname, 0, NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind) NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu) NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac) -VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id) +VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id) MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode) diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c index b1f4714afa..3cc072388f 100644 --- a/src/network/networkd-netdev-vlan.c +++ b/src/network/networkd-netdev-vlan.c @@ -20,6 +20,7 @@ #include #include "networkd-netdev-vlan.h" +#include "vlan-util.h" static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { VLan *v; @@ -33,11 +34,9 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin assert(v); - if (v->id <= VLANID_MAX) { - r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m"); - } + r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m"); return 0; } @@ -52,8 +51,8 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) { assert(v); - if (v->id > VLANID_MAX) { - log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename); + if (v->id == VLANID_INVALID) { + log_warning("VLAN without valid Id (%"PRIu16") configured in %s.", v->id, filename); return -EINVAL; } @@ -66,7 +65,7 @@ static void vlan_init(NetDev *netdev) { assert(netdev); assert(v); - v->id = VLANID_MAX + 1; + v->id = VLANID_INVALID; } const NetDevVTable vlan_vtable = { diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 73aacf4a0f..2dfe314b6e 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -23,12 +23,10 @@ typedef struct VLan VLan; #include "networkd-netdev.h" -#define VLANID_MAX 4094 - struct VLan { NetDev meta; - uint64_t id; + uint16_t id; }; DEFINE_NETDEV_CAST(VLAN, VLan); diff --git a/src/shared/vlan-util.c b/src/shared/vlan-util.c new file mode 100644 index 0000000000..78d66dd3d9 --- /dev/null +++ b/src/shared/vlan-util.c @@ -0,0 +1,69 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "vlan-util.h" +#include "parse-util.h" +#include "conf-parser.h" + +int parse_vlanid(const char *p, uint16_t *ret) { + uint16_t id; + int r; + + r = safe_atou16(p, &id); + if (r < 0) + return r; + if (!vlanid_is_valid(id)) + return -ERANGE; + + *ret = id; + return 0; +} + +int config_parse_vlanid( + 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) { + + uint16_t *id = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_vlanid(rvalue, id); + if (r == -ERANGE) { + log_syntax(unit, LOG_ERR, filename, line, r, "VLAN identifier outside of valid range 0…4094, ignoring: %s", rvalue); + return 0; + } + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN identifier value, ignoring: %s", rvalue); + return 0; + } + + return 0; +} diff --git a/src/shared/vlan-util.h b/src/shared/vlan-util.h new file mode 100644 index 0000000000..ce6763b3a3 --- /dev/null +++ b/src/shared/vlan-util.h @@ -0,0 +1,35 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include + +#define VLANID_MAX 4094 +#define VLANID_INVALID UINT16_MAX + +/* Note that we permit VLAN Id 0 here, as that is apparently OK by the Linux kernel */ +static inline bool vlanid_is_valid(uint16_t id) { + return id <= VLANID_MAX; +} + +int parse_vlanid(const char *p, uint16_t *ret); + +int config_parse_vlanid(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); -- cgit v1.2.3-54-g00ecf From 6cad256dbe6343de4329934ea7c08707a365d340 Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Thu, 9 Jun 2016 13:44:31 +0200 Subject: networkd-link: parse linkinfo to get kind --- src/network/networkd-link.c | 20 +++++++++++++++++++- src/network/networkd-link.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 6746d88fc8..5f25873b46 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -396,7 +396,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) { static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { _cleanup_link_unref_ Link *link = NULL; uint16_t type; - const char *ifname; + const char *ifname, *kind = NULL; int r, ifindex; unsigned short iftype; @@ -404,6 +404,15 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { assert(message); assert(ret); + /* check for link kind */ + r = sd_netlink_message_enter_container(message, IFLA_LINKINFO); + if (r == 0) { + (void)sd_netlink_message_read_string(message, IFLA_INFO_KIND, &kind); + r = sd_netlink_message_exit_container(message); + if (r < 0) + return r; + } + r = sd_netlink_message_get_type(message, &type); if (r < 0) return r; @@ -438,6 +447,12 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { if (!link->ifname) return -ENOMEM; + if (kind) { + link->kind = strdup(kind); + if (!link->kind) + return -ENOMEM; + } + r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); if (r < 0) log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); @@ -515,6 +530,9 @@ static void link_free(Link *link) { free(link->ifname); + if (link->kind) + free(link->kind); + (void)unlink(link->state_file); free(link->state_file); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7db94e79e8..2809b1fe0b 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -68,6 +68,7 @@ typedef struct Link { int ifindex; char *ifname; + char *kind; unsigned short iftype; char *state_file; struct ether_addr mac; -- cgit v1.2.3-54-g00ecf From 13b498f967c5117a88d72304bed1f8c0b9c1bb87 Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Wed, 1 Jun 2016 15:18:21 +0200 Subject: networkd: add support to configure VLAN on bridge ports --- Makefile.am | 2 + man/systemd.network.xml | 53 +++++ src/basic/macro.h | 9 + src/basic/missing.h | 8 + src/network/networkd-brvlan.c | 335 +++++++++++++++++++++++++++++++ src/network/networkd-brvlan.h | 29 +++ src/network/networkd-link.c | 16 ++ src/network/networkd-network-gperf.gperf | 4 + src/network/networkd-network.c | 3 +- src/network/networkd-network.h | 8 + 10 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 src/network/networkd-brvlan.c create mode 100644 src/network/networkd-brvlan.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index d233614403..528e0ced92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5480,6 +5480,8 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-manager-bus.c \ src/network/networkd-fdb.h \ src/network/networkd-fdb.c \ + src/network/networkd-brvlan.h \ + src/network/networkd-brvlan.c \ src/network/networkd-address-pool.h \ src/network/networkd-address-pool.c \ src/network/networkd-util.h \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 24deb0d1d7..ea98c821fa 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1130,6 +1130,39 @@ + + [BridgeVLAN] Section Options + The [BridgeVLAN] section manages the VLAN ID configuration of a bridge port and accepts + the following keys. Specify several [BridgeVLAN] sections to configure several VLAN entries. + The VLANFiltering= option has to be enabled, see [Bridge] section in + systemd.netdev5. + + + + VLAN= + + The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid + from 1 to 4094. + + + + EgressUntagged= + + The VLAN ID specified here will be used to untag frames on egress. Configuring + EgressUntagged= implicates the use of VLAN= above and will enable the + VLAN ID for ingress as well. This can be either a single ID or a range M-N. + + + + PVID= + + The Port VLAN ID specified here is assigned to all untagged frames at ingress. + PVID= can be used only once. Configuring PVID= implicates the use of + VLAN= above and will enable the VLAN ID for ingress as well. + + + + Example @@ -1174,6 +1207,26 @@ Name=enp2s0 [Network] Bridge=bridge0 + + + /etc/systemd/network/25-bridge-slave-interface-vlan.network + + [Match] +Name=enp2s0 + +[Network] +Bridge=bridge0 + +[BridgeVLAN] +VLAN=1-32 +PVID=42 +EgressUntagged=42 + +[BridgeVLAN] +VLAN=100-200 + +[BridgeVLAN] +EgressUntagged=300-400 /etc/systemd/network/25-ipip.network diff --git a/src/basic/macro.h b/src/basic/macro.h index e41aa4260f..6b2aeb933f 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -89,6 +89,15 @@ #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ +/* builtins */ +#if __SIZEOF_INT__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffs(x); +#elif __SIZEOF_LONG__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffsl(x); +#else +#error "neither int nor long are four bytes long?!?" +#endif + /* Rounds up */ #define ALIGN4(l) (((l) + 3) & ~3) diff --git a/src/basic/missing.h b/src/basic/missing.h index 51dafcaca9..8b977871e9 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -759,6 +759,14 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif +#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */ +#endif + +#ifndef BRIDGE_VLAN_INFO_RANGE_END +#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */ +#endif + #if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID #define IFLA_BR_UNSPEC 0 #define IFLA_BR_FORWARD_DELAY 1 diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c new file mode 100644 index 0000000000..77c08d090c --- /dev/null +++ b/src/network/networkd-brvlan.c @@ -0,0 +1,335 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 BISDN GmbH. All rights reserved. + + 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 . +***/ + +#include +#include +#include + +#include "alloc-util.h" +#include "conf-parser.h" +#include "netlink-util.h" +#include "networkd-brvlan.h" +#include "networkd.h" +#include "parse-util.h" +#include "vlan-util.h" + +static bool is_bit_set(unsigned bit, uint32_t scope) { + assert(bit < sizeof(scope)*8); + return scope & (1 << bit); +} + +static inline void set_bit(unsigned nr, uint32_t *addr) { + if (nr < BRIDGE_VLAN_BITMAP_MAX) + addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); +} + +static inline int is_vid_valid(unsigned vid) { + if (vid > VLANID_MAX || vid == 0) + return -EINVAL; + return 0; +} + +static int find_next_bit(int i, uint32_t x) { + int j; + + if (i >= 32) + return -1; + + /* find first bit */ + if (i < 0) + return BUILTIN_FFS_U32(x); + + /* mask off prior finds to get next */ + j = __builtin_ffs(x >> i); + return j ? j + i : 0; +} + +static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) { + struct bridge_vlan_info br_vlan; + int i, j, k, r, done, cnt; + uint16_t begin, end; + bool untagged; + + assert(link); + assert(req); + assert(br_vid_bitmap); + assert(br_untagged_bitmap); + + i = cnt = -1; + + begin = end = UINT16_MAX; + for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) { + unsigned base_bit; + uint32_t vid_map = br_vid_bitmap[k]; + uint32_t untagged_map = br_untagged_bitmap[k]; + + base_bit = k * 32; + i = -1; + done = 0; + do { + j = find_next_bit(i, vid_map); + if (j > 0) { + /* first hit of any bit */ + if (begin == UINT16_MAX && end == UINT16_MAX) { + begin = end = j - 1 + base_bit; + untagged = is_bit_set(j - 1, untagged_map); + goto next; + } + + /* this bit is a continuation of prior bits */ + if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) { + end++; + goto next; + } + } else + done = 1; + + if (begin != UINT16_MAX) { + cnt++; + if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1) + break; + + br_vlan.flags = 0; + if (untagged) + br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED; + + if (begin == end) { + br_vlan.vid = begin; + + if (begin == pvid) + br_vlan.flags |= BRIDGE_VLAN_INFO_PVID; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + } else { + br_vlan.vid = begin; + br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + + br_vlan.vid = end; + br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; + br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + } + + if (done) + break; + } + if (j > 0) { + begin = end = j - 1 + base_bit; + untagged = is_bit_set(j - 1, untagged_map); + } + + next: + i = j; + } while(!done); + } + if (!cnt) + return -EINVAL; + + return cnt; +} + +static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) + log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m"); + + return 1; +} + +int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + uint16_t flags; + sd_netlink *rtnl; + + assert(link); + assert(link->manager); + assert(br_vid_bitmap); + assert(br_untagged_bitmap); + assert(link->network); + + /* pvid might not be in br_vid_bitmap yet */ + if (pvid) + set_bit(pvid, br_vid_bitmap); + + rtnl = link->manager->rtnl; + + /* create new RTM message */ + r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); + + r = sd_rtnl_message_link_set_family(req, PF_BRIDGE); + if (r < 0) + return log_link_error_errno(link, r, "Could not set message family: %m"); + + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); + + /* master needs flag self */ + if (!link->network->bridge) { + flags = BRIDGE_FLAGS_SELF; + sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t)); + } + + /* add vlan info */ + r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap); + if (r < 0) + return log_link_error_errno(link, r, "Could not append VLANs: %m"); + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); + + /* send message to the kernel */ + r = sd_netlink_call_async(rtnl, req, set_brvlan_handler, link, 0, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + + return 0; +} + +static int parse_vid_range(const char *rvalue, uint16_t *vid, uint16_t *vid_end) { + int r; + char *p; + char *_rvalue = NULL; + uint16_t _vid = UINT16_MAX; + uint16_t _vid_end = UINT16_MAX; + + assert(rvalue); + assert(vid); + assert(vid_end); + + _rvalue = strdupa(rvalue); + p = strchr(_rvalue, '-'); + if (p) { + *p = '\0'; + p++; + r = parse_vlanid(_rvalue, &_vid); + if (r < 0) + return r; + + if (!_vid) + return -ERANGE; + + r = parse_vlanid(p, &_vid_end); + if (r < 0) + return r; + + if (!_vid_end) + return -ERANGE; + } else { + r = parse_vlanid(_rvalue, &_vid); + if (r < 0) + return r; + + if (!_vid) + return -ERANGE; + } + + *vid = _vid; + *vid_end = _vid_end; + return r; +} + +int config_parse_brvlan_vlan(const char *unit, const char *filename, + unsigned line, const char *section, + unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, + void *userdata) { + Network *network = userdata; + int r; + uint16_t vid, vid_end; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_vid_range(rvalue, &vid, &vid_end); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue); + return 0; + } + + if (UINT16_MAX == vid_end) + set_bit(vid++, network->br_vid_bitmap); + else { + if (vid >= vid_end) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue); + return 0; + } + for (; vid <= vid_end; vid++) + set_bit(vid, network->br_vid_bitmap); + } + return 0; +} + +int config_parse_brvlan_untagged(const char *unit, const char *filename, + unsigned line, const char *section, + unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, + void *userdata) { + Network *network = userdata; + int r; + uint16_t vid, vid_end; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_vid_range(rvalue, &vid, &vid_end); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue); + return 0; + } + + if (UINT16_MAX == vid_end) { + set_bit(vid, network->br_vid_bitmap); + set_bit(vid, network->br_untagged_bitmap); + } else { + if (vid >= vid_end) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue); + return 0; + } + for (; vid <= vid_end; vid++) { + set_bit(vid, network->br_vid_bitmap); + set_bit(vid, network->br_untagged_bitmap); + } + } + return 0; +} diff --git a/src/network/networkd-brvlan.h b/src/network/networkd-brvlan.h new file mode 100644 index 0000000000..6aa6883bfc --- /dev/null +++ b/src/network/networkd-brvlan.h @@ -0,0 +1,29 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2016 BISDN GmbH. All rights reserved. + + 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 . +***/ + +#include + +typedef struct Link Link; + +int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap); + +int config_parse_brvlan_vlan(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_brvlan_untagged(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/network/networkd-link.c b/src/network/networkd-link.c index 5f25873b46..dce5c2be6e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1114,6 +1114,16 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u return 1; } +static int link_set_bridge_vlan(Link *link) { + int r = 0; + + r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap); + if (r < 0) + log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m"); + + return r; +} + static int link_set_bridge_fdb(Link *link) { FdbEntry *fdb_entry; int r = 0; @@ -1996,6 +2006,12 @@ static int link_joined(Link *link) { log_link_error_errno(link, r, "Could not set bridge message: %m"); } + if (link->network->bridge || NETDEV_KIND_BRIDGE == netdev_kind_from_string(link->kind)) { + r = link_set_bridge_vlan(link); + if (r < 0) + log_link_error_errno(link, r, "Could not set bridge vlan: %m"); + } + return link_enter_set_addresses(link); } diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index d9f5b95cdf..0b0aa58f67 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -4,6 +4,7 @@ #include "networkd.h" #include "networkd-conf.h" #include "network-internal.h" +#include "vlan-util.h" %} struct ConfigPerfItem; %null_strings @@ -112,6 +113,9 @@ Bridge.AllowPortToBeRoot, config_parse_bool, Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 +BridgeVLAN.PVID, config_parse_vlanid, 0, offsetof(Network, pvid) +BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0 +BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0 /* backwards compatibility: do not add new entries to this section */ Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c03c0f0bed..84bdf75b38 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -147,7 +147,8 @@ static int network_load_one(Manager *manager, const char *filename) { "DHCPServer\0" "IPv6AcceptRA\0" "Bridge\0" - "BridgeFDB\0", + "BridgeFDB\0" + "BridgeVLAN\0", config_item_perf_lookup, network_network_gperf_lookup, false, false, true, network); if (r < 0) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index a49748d1b1..38688cc400 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -28,6 +28,7 @@ #include "resolve-util.h" #include "networkd-address.h" +#include "networkd-brvlan.h" #include "networkd-fdb.h" #include "networkd-lldp-tx.h" #include "networkd-netdev.h" @@ -37,6 +38,9 @@ #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 +#define BRIDGE_VLAN_BITMAP_MAX 4096 +#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32) + typedef enum DCHPClientIdentifier { DHCP_CLIENT_ID_MAC, DHCP_CLIENT_ID_DUID, @@ -146,6 +150,10 @@ struct Network { bool unicast_flood; unsigned cost; + uint16_t pvid; + uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN]; + uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN]; + AddressFamilyBoolean ip_forward; bool ip_masquerade; -- cgit v1.2.3-54-g00ecf From 174306cf08e60d36ff30bcf0d294c557c548fdbb Mon Sep 17 00:00:00 2001 From: Andrew Jeddeloh Date: Fri, 10 Jun 2016 03:35:43 -0700 Subject: networkd: fix dbus matchmac interface (#3485) Fix issue where the *Network passed via userdata is being offset by offsetof(Network, matchmac) leading to incorrect values being exposed in dbus. --- src/network/networkd-network-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index d6b7448a43..6e21676d23 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -60,7 +60,7 @@ const sd_bus_vtable network_vtable[] = { SD_BUS_PROPERTY("Description", "s", NULL, offsetof(Network, description), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Network, filename), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match_mac), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match_driver), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match_type), SD_BUS_VTABLE_PROPERTY_CONST), -- cgit v1.2.3-54-g00ecf From 9c1e04d0fa80c73ef0dd4647c103cdb7edb7f580 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 10 Jun 2016 13:09:06 +0200 Subject: nspawn: introduce --notify-ready=[no|yes] (#3474) This the patch implements a notificaiton mechanism from the init process in the container to systemd-nspawn. The switch --notify-ready=yes configures systemd-nspawn to wait the "READY=1" message from the init process in the container to send its own to systemd. --notify-ready=no is equivalent to the previous behavior before this patch, systemd-nspawn notifies systemd with a "READY=1" message when the container is created. This notificaiton mechanism uses socket file with path relative to the contanier "/run/systemd/nspawn/notify". The default values it --notify-ready=no. It is also possible to configure this mechanism from the .nspawn files using NotifyReady. This parameter takes the same options of the command line switch. Before this patch, systemd-nspawn notifies "ready" after the inner child was created, regardless the status of the service running inside it. Now, with --notify-ready=yes, systemd-nspawn notifies when the service is ready. This is really useful when there are dependencies between different contaniers. Fixes https://github.com/systemd/systemd/issues/1369 Based on the work from https://github.com/systemd/systemd/pull/3022 Testing: Boot a OS inside a container with systemd-nspawn. Note: modify the commands accordingly with your filesystem. 1. Create a filesystem where you can boot an OS. 2. sudo systemd-nspawn -D ${HOME}/distros/fedora-23/ sh 2.1. Create the unit file /etc/systemd/system/sleep.service inside the container (You can use the example below) 2.2. systemdctl enable sleep 2.3 exit 3. sudo systemd-run --service-type=notify --unit=notify-test ${HOME}/systemd/systemd-nspawn --notify-ready=yes -D ${HOME}/distros/fedora-23/ -b 4. In a different shell run "systemctl status notify-test" When using --notify-ready=yes the service status is "activating" for 20 seconds before being set to "active (running)". Instead, using --notify-ready=no the service status is marked "active (running)" quickly, without waiting for the 20 seconds. This patch was also test with --private-users=yes, you can test it just adding it at the end of the command at point 3. ------ sleep.service ------ [Unit] Description=sleep After=network.target [Service] Type=oneshot ExecStart=/bin/sleep 20 [Install] WantedBy=multi-user.target ------------ end ------------ --- man/systemd-nspawn.xml | 13 +++ man/systemd.nspawn.xml | 9 ++ src/nspawn/nspawn-gperf.gperf | 1 + src/nspawn/nspawn-settings.h | 4 +- src/nspawn/nspawn.c | 195 ++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 214 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 0c8c699201..08122795f4 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -980,6 +980,19 @@ effect. + + --notify-ready= + + Configures support for notifications from the container's init process. + --notify-ready= takes a boolean ( and ). + With option systemd-nspawn notifies systemd + with a READY=1 message when the init process is created. + With option systemd-nspawn waits for the + READY=1 message from the init process in the container + before sending its own to systemd. For more details about notifications + see sd_notify3). + + diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 3683412c14..6df4aeb2a9 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -259,6 +259,15 @@ command line switch, and takes the same options. This option is privileged (see above). + + + NotifyReady= + + Configures support for notifications from the container's init process. + This is equivalent to use command line switch, + and takes the same options. See systemd-nspawn1 + for details about the specific options supported. + diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 2b5d452662..3231a48d5a 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -27,6 +27,7 @@ Exec.Personality, config_parse_personality, 0, offsetof(Settings, Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory) Exec.PrivateUsers, config_parse_private_users, 0, 0 +Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready) Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) Files.Bind, config_parse_bind, 0, 0 diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 1c47e37912..231e6d7266 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -56,7 +56,8 @@ typedef enum SettingsMask { SETTING_CUSTOM_MOUNTS = 1 << 11, SETTING_WORKING_DIRECTORY = 1 << 12, SETTING_USERNS = 1 << 13, - _SETTINGS_MASK_ALL = (1 << 14) -1 + SETTING_NOTIFY_READY = 1 << 14, + _SETTINGS_MASK_ALL = (1 << 15) -1 } SettingsMask; typedef struct Settings { @@ -73,6 +74,7 @@ typedef struct Settings { char *working_directory; UserNamespaceMode userns_mode; uid_t uid_shift, uid_range; + bool notify_ready; /* [Image] */ int read_only; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d1c65e8b0b..ea24de7608 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -104,6 +104,10 @@ * UID range here */ #define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000)) #define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000)) +/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path + * nspawn_notify_socket_path is relative to the container + * the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */ +#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify" typedef enum ContainerStatus { CONTAINER_TERMINATED, @@ -187,6 +191,7 @@ static SettingsMask arg_settings_mask = 0; static int arg_settings_trusted = -1; static char **arg_parameters = NULL; static const char *arg_container_service_name = "systemd-nspawn"; +static bool arg_notify_ready = false; static void help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" @@ -267,6 +272,8 @@ static void help(void) { " the service unit nspawn is running in\n" " --volatile[=MODE] Run the system in volatile mode\n" " --settings=BOOLEAN Load additional settings from .nspawn file\n" + " --notify-ready=BOOLEAN Receive notifications from the container's init process,\n" + " accepted values: yes and no\n" , program_invocation_short_name); } @@ -367,6 +374,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SETTINGS, ARG_CHDIR, ARG_PRIVATE_USERS_CHOWN, + ARG_NOTIFY_READY, }; static const struct option options[] = { @@ -415,6 +423,7 @@ static int parse_argv(int argc, char *argv[]) { { "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL }, { "settings", required_argument, NULL, ARG_SETTINGS }, { "chdir", required_argument, NULL, ARG_CHDIR }, + { "notify-ready", required_argument, NULL, ARG_NOTIFY_READY }, {} }; @@ -987,6 +996,16 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_WORKING_DIRECTORY; break; + case ARG_NOTIFY_READY: + r = parse_boolean(optarg); + if (r < 0) { + log_error("%s is not a valid notify mode. Valid modes are: yes, no, and ready.", optarg); + return -EINVAL; + } + arg_notify_ready = r; + arg_settings_mask |= SETTING_NOTIFY_READY; + break; + case '?': return -EINVAL; @@ -2529,6 +2548,7 @@ static int inner_child( NULL, /* container_uuid */ NULL, /* LISTEN_FDS */ NULL, /* LISTEN_PID */ + NULL, /* NOTIFY_SOCKET */ NULL }; @@ -2656,6 +2676,8 @@ static int inner_child( (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0)) return log_oom(); } + if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0) + return log_oom(); env_use = strv_env_merge(2, envp, arg_setenv); if (!env_use) @@ -2725,6 +2747,37 @@ static int inner_child( return log_error_errno(r, "execv() failed: %m"); } +static int setup_sd_notify_child(void) { + static const int one = 1; + int fd = -1; + union sockaddr_union sa = { + .sa.sa_family = AF_UNIX, + }; + int r; + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) + return log_error_errno(errno, "Failed to allocate notification socket: %m"); + + (void) mkdir_parents(NSPAWN_NOTIFY_SOCKET_PATH, 0755); + (void) unlink(NSPAWN_NOTIFY_SOCKET_PATH); + + strncpy(sa.un.sun_path, NSPAWN_NOTIFY_SOCKET_PATH, sizeof(sa.un.sun_path)-1); + r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); + if (r < 0) { + safe_close(fd); + return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); + } + + r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + if (r < 0) { + safe_close(fd); + return log_error_errno(errno, "SO_PASSCRED failed: %m"); + } + + return fd; +} + static int outer_child( Barrier *barrier, const char *directory, @@ -2736,6 +2789,7 @@ static int outer_child( bool secondary, int pid_socket, int uuid_socket, + int notify_socket, int kmsg_socket, int rtnl_socket, int uid_shift_socket, @@ -2744,12 +2798,14 @@ static int outer_child( pid_t pid; ssize_t l; int r; + _cleanup_close_ int fd = -1; assert(barrier); assert(directory); assert(console); assert(pid_socket >= 0); assert(uuid_socket >= 0); + assert(notify_socket >= 0); assert(kmsg_socket >= 0); cg_unified_flush(); @@ -2936,6 +2992,10 @@ static int outer_child( if (r < 0) return log_error_errno(r, "Failed to move root directory: %m"); + fd = setup_sd_notify_child(); + if (fd < 0) + return fd; + pid = raw_clone(SIGCHLD|CLONE_NEWNS| (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) | (arg_private_network ? CLONE_NEWNET : 0) | @@ -2945,6 +3005,7 @@ static int outer_child( if (pid == 0) { pid_socket = safe_close(pid_socket); uuid_socket = safe_close(uuid_socket); + notify_socket = safe_close(notify_socket); uid_shift_socket = safe_close(uid_shift_socket); /* The inner child has all namespaces that are @@ -2974,8 +3035,13 @@ static int outer_child( return -EIO; } + l = send_one_fd(notify_socket, fd, 0); + if (l < 0) + return log_error_errno(errno, "Failed to send notify fd: %m"); + pid_socket = safe_close(pid_socket); uuid_socket = safe_close(uuid_socket); + notify_socket = safe_close(notify_socket); kmsg_socket = safe_close(kmsg_socket); rtnl_socket = safe_close(rtnl_socket); @@ -3058,6 +3124,96 @@ static int setup_uid_map(pid_t pid) { return 0; } +static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_fdset_free_ FDSet *fds = NULL; + char buf[NOTIFY_BUFFER_MAX+1]; + char *p = NULL; + struct iovec iovec = { + .iov_base = buf, + .iov_len = sizeof(buf)-1, + }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + struct ucred *ucred = NULL; + ssize_t n; + pid_t inner_child_pid; + _cleanup_strv_free_ char **tags = NULL; + + assert(userdata); + + inner_child_pid = PTR_TO_PID(userdata); + + if (revents != EPOLLIN) { + log_warning("Got unexpected poll event for notify fd."); + return 0; + } + + n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return log_warning_errno(errno, "Couldn't read notification socket: %m"); + } + cmsg_close_all(&msghdr); + + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + ucred = (struct ucred*) CMSG_DATA(cmsg); + } + } + + if (!ucred || ucred->pid != inner_child_pid) { + log_warning("Received notify message without valid credentials. Ignoring."); + return 0; + } + + if ((size_t) n >= sizeof(buf)) { + log_warning("Received notify message exceeded maximum size. Ignoring."); + return 0; + } + + buf[n] = 0; + tags = strv_split(buf, "\n\r"); + if (!tags) + return log_oom(); + + if (strv_find(tags, "READY=1")) + sd_notifyf(false, "READY=1\n"); + + p = strv_find_startswith(tags, "STATUS="); + if (p) + sd_notifyf(false, "STATUS=Container running: %s", p); + + return 0; +} + +static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid) { + int r; + sd_event_source *notify_event_source; + + r = sd_event_add_io(event, ¬ify_event_source, fd, EPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid); + if (r < 0) + return log_error_errno(r, "Failed to allocate notify event source: %m"); + + (void) sd_event_source_set_description(notify_event_source, "nspawn-notify"); + + return 0; +} + static int load_settings(void) { _cleanup_(settings_freep) Settings *settings = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -3286,6 +3442,9 @@ static int load_settings(void) { } } + if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0) + arg_notify_ready = settings->notify_ready; + return 0; } @@ -3536,7 +3695,9 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uuid_socket_pair[2] = { -1, -1 }, + notify_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; + _cleanup_close_ int notify_socket= -1; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; @@ -3587,6 +3748,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0) { + r = log_error_errno(errno, "Failed to create notify socket pair: %m"); + goto finish; + } + if (arg_userns_mode != USER_NAMESPACE_NO) if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); @@ -3628,6 +3794,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]); uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]); + notify_socket_pair[0] = safe_close(notify_socket_pair[0]); uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); (void) reset_all_signal_handlers(); @@ -3643,6 +3810,7 @@ int main(int argc, char *argv[]) { secondary, pid_socket_pair[1], uuid_socket_pair[1], + notify_socket_pair[1], kmsg_socket_pair[1], rtnl_socket_pair[1], uid_shift_socket_pair[1], @@ -3661,6 +3829,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); pid_socket_pair[1] = safe_close(pid_socket_pair[1]); uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); + notify_socket_pair[1] = safe_close(notify_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); if (arg_userns_mode != USER_NAMESPACE_NO) { @@ -3734,6 +3903,13 @@ int main(int argc, char *argv[]) { goto finish; } + /* We also retrieve the socket used for notifications generated by outer child */ + notify_socket = receive_one_fd(notify_socket_pair[0], 0); + if (notify_socket < 0) { + r = log_error_errno(errno, "Failed to receive notification socket from the outer child: %m"); + goto finish; + } + log_debug("Init process invoked as PID " PID_FMT, pid); if (arg_userns_mode != USER_NAMESPACE_NO) { @@ -3848,6 +4024,16 @@ int main(int argc, char *argv[]) { goto finish; } + r = sd_event_new(&event); + if (r < 0) { + log_error_errno(r, "Failed to get default event source: %m"); + goto finish; + } + + r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(pid)); + if (r < 0) + goto finish; + /* Let the child know that we are ready and wait that the child is completely ready now. */ if (!barrier_place_and_sync(&barrier)) { /* #4 */ log_error("Child died too early."); @@ -3860,15 +4046,10 @@ int main(int argc, char *argv[]) { etc_passwd_lock = safe_close(etc_passwd_lock); sd_notifyf(false, - "READY=1\n" "STATUS=Container running.\n" "X_NSPAWN_LEADER_PID=" PID_FMT, pid); - - r = sd_event_new(&event); - if (r < 0) { - log_error_errno(r, "Failed to get default event source: %m"); - goto finish; - } + if (!arg_notify_ready) + sd_notify(false, "READY=1\n"); if (arg_kill_signal > 0) { /* Try to kill the init system on SIGINT or SIGTERM */ -- cgit v1.2.3-54-g00ecf From cf677fe6868f0565dd625cfbc2992a0f2cd3e053 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 10 Jun 2016 18:19:54 +0200 Subject: core/execute: add the magic character '!' to allow privileged execution (#3493) This patch implements the new magic character '!'. By putting '!' in front of a command, systemd executes it with full privileges ignoring paramters such as User, Group, SupplementaryGroups, CapabilityBoundingSet, AmbientCapabilities, SecureBits, SystemCallFilter, SELinuxContext, AppArmorProfile, SmackProcessLabel, and RestrictAddressFamilies. Fixes partially https://github.com/systemd/systemd/issues/3414 Related to https://github.com/coreos/rkt/issues/2482 Testing: 1. Create a user 'bob' 2. Create the unit file /etc/systemd/system/exec-perm.service (You can use the example below) 3. sudo systemctl start ext-perm.service 4. Verify that the commands starting with '!' were not executed as bob, 4.1 Looking to the output of ls -l /tmp/exec-perm 4.2 Each file contains the result of the id command. ````````````````````````````````````````````````````````````````` [Unit] Description=ext-perm [Service] Type=oneshot TimeoutStartSec=0 User=bob ExecStartPre=!/usr/bin/sh -c "/usr/bin/rm /tmp/exec-perm*" ; /usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-pre" ExecStart=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start" ; !/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-star-2" ExecStartPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-post" ExecReload=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-reload" ExecStop=!/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop" ExecStopPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop-post" [Install] WantedBy=multi-user.target] ````````````````````````````````````````````````````````````````` --- man/systemd.exec.xml | 27 +++++++++++++++------------ man/systemd.service.xml | 7 ++++--- src/core/execute.c | 6 +++--- src/core/execute.h | 3 ++- src/core/load-fragment.c | 15 ++++++++++----- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4a3dd14c39..1c3256a662 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -146,7 +146,7 @@ Sets the Unix user or group that the processes are executed as, respectively. Takes a single user or group name or ID as argument. If no group is set, the default group - of the user is chosen. + of the user is chosen. These do not affect commands prefixed with !. @@ -161,7 +161,7 @@ this one will have no effect. In any way, this option does not override, but extends the list of supplementary groups configured in the system group database for the - user. + user. This does not affect commands prefixed with !. @@ -795,7 +795,8 @@ process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior settings have no effect. If set to ~ (without any further argument), the bounding set is - reset to the full set of available capabilities, also undoing any previous settings. + reset to the full set of available capabilities, also undoing any previous settings. This does not affect + commands prefixed with !. @@ -824,7 +825,8 @@ as a non-privileged user but still want to give it some capabilities. Note that in this case option keep-caps is automatically added to SecureBits= to retain the - capabilities over the user change. + capabilities over the user change. AmbientCapabilities= does not affect + commands prefixed with !. @@ -840,8 +842,8 @@ . This option may appear more than once, in which case the secure bits are ORed. If the empty string is assigned to this option, - the bits are reset to 0. See - capabilities7 + the bits are reset to 0. This does not affect commands prefixed with !. + See capabilities7 for details. @@ -1097,8 +1099,8 @@ domain transition. However, the policy still needs to authorize the transition. This directive is ignored if SELinux is disabled. If prefixed by -, all errors - will be ignored. See - setexeccon3 + will be ignored. This does not affect commands prefixed with !. + See setexeccon3 for details. @@ -1110,7 +1112,7 @@ Profiles must already be loaded in the kernel, or the unit will fail. This result in a non operation if AppArmor is not enabled. If prefixed by -, all errors will - be ignored. + be ignored. This does not affect commands prefixed with !. @@ -1129,7 +1131,8 @@ The value may be prefixed by -, in which case all errors will be ignored. An empty value may be - specified to unset previous assignments. + specified to unset previous assignments. This does not affect + commands prefixed with !. @@ -1180,7 +1183,7 @@ listed explicitly. This option may be specified more than once, in which case the filter masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will - have no effect. + have no effect. This does not affect commands prefixed with !. If you specify both types of this option (i.e. whitelisting and blacklisting), the first encountered will @@ -1343,7 +1346,7 @@ family should be included in the configured whitelist as it is frequently used for local communication, including for syslog2 - logging. + logging. This does not affect commands prefixed with !. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 6641dfed4f..6e969abc25 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -295,9 +295,10 @@ If the absolute filename is prefixed with -, an exit code of the command normally considered a failure (i.e. non-zero exit status or abnormal - exit due to signal) is ignored and considered success. If both - - and @ are used, they - can appear in either order. + exit due to signal) is ignored and considered success. + If the absolute path is prefixed with ! then + it is executed with full privileges. -, @, and ! + may be used together and they can appear in any order. If more than one command is specified, the commands are invoked sequentially in the order they appear in the unit diff --git a/src/core/execute.c b/src/core/execute.c index e718c43df9..802f14d575 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1717,7 +1717,7 @@ static int exec_child( umask(context->umask); - if (params->apply_permissions) { + if (params->apply_permissions && !command->privileged) { r = enforce_groups(context, username, gid); if (r < 0) { *exit_status = EXIT_GROUP; @@ -1842,7 +1842,7 @@ static int exec_child( } #ifdef HAVE_SELINUX - if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) { + if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) { r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net); if (r < 0) { *exit_status = EXIT_SELINUX_CONTEXT; @@ -1867,7 +1867,7 @@ static int exec_child( return r; } - if (params->apply_permissions) { + if (params->apply_permissions && !command->privileged) { bool use_address_families = context->address_families_whitelist || !set_isempty(context->address_families); diff --git a/src/core/execute.h b/src/core/execute.h index 464869d226..cd1f7b36f6 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -81,7 +81,8 @@ struct ExecCommand { char **argv; ExecStatus exec_status; LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ - bool ignore; + bool ignore:1; + bool privileged:1; }; struct ExecRuntime { diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 2d8f6296c8..17c72aed88 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -596,7 +596,7 @@ int config_parse_exec( p = rvalue; do { _cleanup_free_ char *path = NULL, *firstword = NULL; - bool separate_argv0 = false, ignore = false; + bool separate_argv0 = false, ignore = false, privileged = false; _cleanup_free_ ExecCommand *nce = NULL; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; @@ -610,14 +610,18 @@ int config_parse_exec( return 0; f = firstword; - for (i = 0; i < 2; i++) { - /* We accept an absolute path as first argument, or - * alternatively an absolute prefixed with @ to allow - * overriding of argv[0]. */ + for (i = 0; i < 3; i++) { + /* We accept an absolute path as first argument. + * If it's prefixed with - and the path doesn't exist, + * we ignore it instead of erroring out; + * if it's prefixed with @, we allow overriding of argv[0]; + * and if it's prefixed with !, it will be run with full privileges */ if (*f == '-' && !ignore) ignore = true; else if (*f == '@' && !separate_argv0) separate_argv0 = true; + else if (*f == '!' && !privileged) + privileged = true; else break; f++; @@ -715,6 +719,7 @@ int config_parse_exec( nce->argv = n; nce->path = path; nce->ignore = ignore; + nce->privileged = privileged; exec_command_append_list(e, nce); -- cgit v1.2.3-54-g00ecf From 64c3610b55799c738e4fdc7236fadd635649c0f4 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Fri, 10 Jun 2016 18:33:15 +0200 Subject: core: disable colors when displaying cylon when systemd.log_color=off (#3495) --- src/core/manager.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 14d97a87d0..ec8acdff5b 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -136,23 +136,28 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po if (pos > 1) { if (pos > 2) p = mempset(p, ' ', pos-2); - p = stpcpy(p, ANSI_RED); + if (log_get_show_color()) + p = stpcpy(p, ANSI_RED); *p++ = '*'; } if (pos > 0 && pos <= width) { - p = stpcpy(p, ANSI_HIGHLIGHT_RED); + if (log_get_show_color()) + p = stpcpy(p, ANSI_HIGHLIGHT_RED); *p++ = '*'; } - p = stpcpy(p, ANSI_NORMAL); + if (log_get_show_color()) + p = stpcpy(p, ANSI_NORMAL); if (pos < width) { - p = stpcpy(p, ANSI_RED); + if (log_get_show_color()) + p = stpcpy(p, ANSI_RED); *p++ = '*'; if (pos < width-1) p = mempset(p, ' ', width-1-pos); - strcpy(p, ANSI_NORMAL); + if (log_get_show_color()) + strcpy(p, ANSI_NORMAL); } } -- cgit v1.2.3-54-g00ecf From 033f0ab85d9cc5e8ae66e07d4740482abb5617ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Jun 2016 21:45:12 +0200 Subject: systemctl: don't suppress error code when handling legacy commands For legacy commands such as /sbin/halt or /sbin/poweroff we support legacy fallbacks that talk via traditional SysV way with PID 1 to issue the desired operation. We do this on any kind of error if the primary method of operation fails. When this is the case we suppress any error message that is normally generated, in order to not confuse the user. When suppressing this log message, don't suppress the original error code, because there's really no reason to. --- src/systemctl/systemctl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index df41182529..9ff460d158 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2693,10 +2693,9 @@ static int start_unit_one( if (r < 0) { const char *verb; - if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) - /* There's always a fallback possible for - * legacy actions. */ - return -EADDRNOTAVAIL; + /* There's always a fallback possible for legacy actions. */ + if (arg_action != ACTION_SYSTEMCTL) + return r; verb = method_to_verb(method); -- cgit v1.2.3-54-g00ecf From 2853b60ab553d0692d699897f38d2c175721ba54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Jun 2016 21:48:08 +0200 Subject: systemctl: prolong timeout of "systemctl daemon-reload" Reloading or reexecuting PID 1 means the unit generators are rerun, which are timed out at 90s. Make sure the method call asking for the reload is timed out at twice that, so that the generators have 90s and the reload operation has 90s too. This reworks the daemon_reload() call in systemctl, and makes it exclusively about reloading/reexecing. Previously it was used for other trivial method calls too, which didn't really help readability. As the code paths are now sufficiently different, split out the old code into a new function trivial_method(). This call also does a similar change as c8ad4efb277c3235d58789170af11bb3c847d655 but for the reload/reexec operation. Fixes: #3353 --- src/systemctl/systemctl.c | 110 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9ff460d158..914dba36dc 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -174,6 +174,7 @@ static bool arg_firmware_setup = false; static bool arg_now = false; static int daemon_reload(int argc, char *argv[], void* userdata); +static int trivial_method(int argc, char *argv[], void *userdata); static int halt_now(enum action a); static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state); @@ -2283,7 +2284,7 @@ static int cancel_job(int argc, char *argv[], void *userdata) { int r = 0; if (argc <= 1) - return daemon_reload(argc, argv, userdata); + return trivial_method(argc, argv, userdata); polkit_agent_open_if_enabled(); @@ -3251,7 +3252,7 @@ static int start_special(int argc, char *argv[], void *userdata) { ACTION_REBOOT, ACTION_KEXEC, ACTION_EXIT)) - return daemon_reload(argc, argv, userdata); + return trivial_method(argc, argv, userdata); /* First try logind, to allow authentication with polkit */ if (IN_SET(a, @@ -5052,6 +5053,7 @@ static int set_property(int argc, char *argv[], void *userdata) { static int daemon_reload(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; const char *method; sd_bus *bus; int r; @@ -5062,26 +5064,76 @@ static int daemon_reload(int argc, char *argv[], void *userdata) { if (r < 0) return r; - if (arg_action == ACTION_RELOAD) + switch (arg_action) { + + case ACTION_RELOAD: method = "Reload"; - else if (arg_action == ACTION_REEXEC) + break; + + case ACTION_REEXEC: method = "Reexecute"; - else { - assert(arg_action == ACTION_SYSTEMCTL); + break; + + case ACTION_SYSTEMCTL: + method = streq(argv[0], "daemon-reexec") ? "Reexecute" : + /* "daemon-reload" */ "Reload"; + break; - method = - streq(argv[0], "clear-jobs") || - streq(argv[0], "cancel") ? "ClearJobs" : - streq(argv[0], "daemon-reexec") ? "Reexecute" : - streq(argv[0], "reset-failed") ? "ResetFailed" : - streq(argv[0], "halt") ? "Halt" : - streq(argv[0], "poweroff") ? "PowerOff" : - streq(argv[0], "reboot") ? "Reboot" : - streq(argv[0], "kexec") ? "KExec" : - streq(argv[0], "exit") ? "Exit" : - /* "daemon-reload" */ "Reload"; + default: + assert_not_reached("Unexpected action"); } + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method); + if (r < 0) + return bus_log_create_error(r); + + /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which + * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have + * their timeout, and for everything else there's the same time budget in place. */ + + r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL); + + /* On reexecution, we expect a disconnect, not a reply */ + if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute")) + r = 0; + + if (r < 0 && arg_action == ACTION_SYSTEMCTL) + return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r)); + + /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the + * old ways of doing things, hence don't log any error in that case here. */ + + return r < 0 ? r : 0; +} + +static int trivial_method(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method; + sd_bus *bus; + int r; + + polkit_agent_open_if_enabled(); + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + method = + streq(argv[0], "clear-jobs") || + streq(argv[0], "cancel") ? "ClearJobs" : + streq(argv[0], "reset-failed") ? "ResetFailed" : + streq(argv[0], "halt") ? "Halt" : + streq(argv[0], "reboot") ? "Reboot" : + streq(argv[0], "kexec") ? "KExec" : + streq(argv[0], "exit") ? "Exit" : + /* poweroff */ "PowerOff"; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -5091,16 +5143,11 @@ static int daemon_reload(int argc, char *argv[], void *userdata) { &error, NULL, NULL); - if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) - /* There's always a fallback possible for - * legacy actions. */ - r = -EADDRNOTAVAIL; - else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute")) - /* On reexecution, we expect a disconnect, not a - * reply */ - r = 0; - else if (r < 0) - return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r)); + if (r < 0 && arg_action == ACTION_SYSTEMCTL) + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + + /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the + * old ways of doing things, hence don't log any error in that case here. */ return r < 0 ? r : 0; } @@ -5112,7 +5159,7 @@ static int reset_failed(int argc, char *argv[], void *userdata) { int r, q; if (argc <= 1) - return daemon_reload(argc, argv, userdata); + return trivial_method(argc, argv, userdata); polkit_agent_open_if_enabled(); @@ -7497,7 +7544,7 @@ static int systemctl_main(int argc, char *argv[]) { { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers }, { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs }, { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines }, - { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method }, { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job }, { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, @@ -7570,7 +7617,7 @@ static int reload_with_fallback(void) { return 0; /* Nothing else worked, so let's try signals */ - assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC); + assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC)); if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) return log_error_errno(errno, "kill() failed: %m"); @@ -7584,8 +7631,7 @@ static int start_with_fallback(void) { if (start_unit(0, NULL, NULL) >= 0) return 0; - /* Nothing else worked, so let's try - * /dev/initctl */ + /* Nothing else worked, so let's try /dev/initctl */ if (talk_initctl() > 0) return 0; -- cgit v1.2.3-54-g00ecf From e373507d2570fe474a09fd6e3836ead32dca912f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 23:26:24 +0200 Subject: networkd: fix bad memory access for routes that are note attached to a link yet (#3499) Corrects: 1b566071 Also see: https://github.com/systemd/systemd/pull/3478#issuecomment-225008542 --- src/network/networkd-route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 6359f967a2..52037f9c6d 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -492,7 +492,7 @@ int route_configure( assert(route->family == AF_INET || route->family == AF_INET6); if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 && - set_size(route->link->routes) >= ROUTES_PER_LINK_MAX) + set_size(link->routes) >= ROUTES_PER_LINK_MAX) return -E2BIG; r = sd_rtnl_message_new_route(link->manager->rtnl, &req, -- cgit v1.2.3-54-g00ecf From bc81447ea556586b09226ce2d3fe375a7adc2c16 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 20:23:49 +0200 Subject: resolved: flush all caches if SIGUSR2 is received --- src/resolve/resolved-manager.c | 17 +++++++++++++++++ src/resolve/resolved-manager.h | 1 + src/resolve/resolved.c | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 8dc7891143..6cf75f9183 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -466,6 +466,21 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si return 0; } +static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + Manager *m = userdata; + DnsScope *scope; + + assert(s); + assert(si); + assert(m); + + LIST_FOREACH(scopes, scope, m->dns_scopes) + dns_cache_flush(&scope->cache); + + log_info("Flushed all caches."); + return 0; +} + int manager_new(Manager **ret) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -526,6 +541,7 @@ int manager_new(Manager **ret) { return r; (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m); + (void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m); *ret = m; m = NULL; @@ -584,6 +600,7 @@ Manager *manager_free(Manager *m) { sd_bus_unref(m->bus); sd_event_source_unref(m->sigusr1_event_source); + sd_event_source_unref(m->sigusr2_event_source); sd_event_unref(m->event); diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index e82a824f29..97f75ace79 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -120,6 +120,7 @@ struct Manager { sd_bus_slot *prepare_for_sleep_slot; sd_event_source *sigusr1_event_source; + sd_event_source *sigusr2_event_source; unsigned n_transactions_total; unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX]; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 6cef401870..3a47b82d8a 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1) >= 0); r = manager_new(&m); if (r < 0) { -- cgit v1.2.3-54-g00ecf From ba35662fbdde7b90aed6b34c641b4ff0ea740c68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 20:40:30 +0200 Subject: resolved: also add a way to flush all caches via the bus And expose it in "resolve-tool --flush-caches". --- man/systemd-resolve.xml | 6 ++++++ src/resolve/resolve-tool.c | 36 ++++++++++++++++++++++++++++++++++++ src/resolve/resolved-bus.c | 12 ++++++++++++ src/resolve/resolved-manager.c | 15 +++++++++++---- src/resolve/resolved-manager.h | 2 ++ 5 files changed, 67 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index 4b66f836a2..b917ac20a2 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -288,6 +288,12 @@ Resets the statistics counters shown in to zero. + + + + Flushes all DNS resource record caches the service maintains locally. + + diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 7e145c64c4..bc6dcf04a4 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -66,6 +66,7 @@ static enum { MODE_RESOLVE_TLSA, MODE_STATISTICS, MODE_RESET_STATISTICS, + MODE_FLUSH_CACHES, } arg_mode = MODE_RESOLVE_HOST; static ServiceFamily service_family_from_string(const char *s) { @@ -1037,6 +1038,24 @@ static int reset_statistics(sd_bus *bus) { return 0; } +static int flush_caches(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "FlushCaches", + &error, + NULL, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r)); + + return 0; +} + static void help_protocol_types(void) { if (arg_legend) puts("Known protocol types:"); @@ -1097,6 +1116,7 @@ static void help(void) { " --legend=BOOL Print headers and additional info (default: yes)\n" " --statistics Show resolver statistics\n" " --reset-statistics Reset resolver statistics\n" + " --flush-caches Flush all local DNS caches\n" , program_invocation_short_name); } @@ -1114,6 +1134,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, + ARG_FLUSH_CACHES, }; static const struct option options[] = { @@ -1134,6 +1155,7 @@ static int parse_argv(int argc, char *argv[]) { { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, {} }; @@ -1307,6 +1329,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESET_STATISTICS; break; + case ARG_FLUSH_CACHES: + arg_mode = MODE_FLUSH_CACHES; + break; + case '?': return -EINVAL; @@ -1473,6 +1499,16 @@ int main(int argc, char **argv) { r = reset_statistics(bus); break; + + case MODE_FLUSH_CACHES: + if (argc > optind) { + log_error("Too many arguments."); + r = -EINVAL; + goto finish; + } + + r = flush_caches(bus); + break; } finish: diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6d4e5746f7..a72a03cfad 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1535,6 +1535,17 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e return sd_bus_reply_method_return(message, "o", p); } +static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + assert(message); + assert(m); + + manager_flush_caches(m); + + return sd_bus_reply_method_return(message, NULL); +} + static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), @@ -1550,6 +1561,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), + SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0), SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 6cf75f9183..a46f13b92f 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -468,16 +468,14 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { Manager *m = userdata; - DnsScope *scope; assert(s); assert(si); assert(m); - LIST_FOREACH(scopes, scope, m->dns_scopes) - dns_cache_flush(&scope->cache); - + manager_flush_caches(m); log_info("Flushed all caches."); + return 0; } @@ -1251,3 +1249,12 @@ bool manager_routable(Manager *m, int family) { return false; } + +void manager_flush_caches(Manager *m) { + DnsScope *scope; + + assert(m); + + LIST_FOREACH(scopes, scope, m->dns_scopes) + dns_cache_flush(&scope->cache); +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 97f75ace79..ef71202ef9 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -170,3 +170,5 @@ bool manager_dnssec_supported(Manager *m); void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key); bool manager_routable(Manager *m, int family); + +void manager_flush_caches(Manager *m); -- cgit v1.2.3-54-g00ecf From 04b764bf76a74943ca652691cfd5b511ed8fe96c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 20:54:10 +0200 Subject: resolved: move verification that link is unmanaged into the proper bus calls Previously, we checked only for the various SetLinkXYZ() calls on the Manager object exposed on the bus if the specified interface is managed/unmanaged by networkd (as we don't permit overriding DNS configuration via bus calls if networkd owns the device), but the equivalent SetXYZ() calls on the Link object did not have such a check. Fix that by moving the appropriate check into the latter, as the former just calls that anyway. --- src/resolve/resolved-bus.c | 22 +--------------------- src/resolve/resolved-link-bus.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index a72a03cfad..6d86cbf123 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1442,26 +1442,6 @@ static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error return 0; } -static int get_unmanaged_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) { - Link *l; - int r; - - assert(m); - assert(ret); - - r = get_any_link(m, ifindex, &l, error); - if (r < 0) - return r; - - if (l->flags & IFF_LOOPBACK) - return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name); - if (l->is_managed) - return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name); - - *ret = l; - return 0; -} - static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) { int ifindex, r; Link *l; @@ -1475,7 +1455,7 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_ if (r < 0) return r; - r = get_unmanaged_link(m, ifindex, &l, error); + r = get_any_link(m, ifindex, &l, error); if (r < 0) return r; diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 6aff427192..bfb87d78e7 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -18,6 +18,7 @@ ***/ #include "alloc-util.h" +#include "bus-common-errors.h" #include "bus-util.h" #include "parse-util.h" #include "resolve-util.h" @@ -158,6 +159,17 @@ static int property_get_dnssec_supported( return sd_bus_message_append(reply, "b", link_dnssec_supported(l)); } +static int verify_unmanaged_link(Link *l, sd_bus_error *error) { + assert(l); + + if (l->flags & IFF_LOOPBACK) + return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name); + if (l->is_managed) + return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name); + + return 0; +} + int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ struct in_addr_data *dns = NULL; size_t allocated = 0, n = 0; @@ -168,6 +180,10 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_enter_container(message, 'a', "(iay)"); if (r < 0) return r; @@ -249,6 +265,10 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_enter_container(message, 'a', "(sb)"); if (r < 0) return r; @@ -328,6 +348,10 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_read(message, "s", &llmnr); if (r < 0) return r; @@ -356,6 +380,10 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_read(message, "s", &mdns); if (r < 0) return r; @@ -384,6 +412,10 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_read(message, "s", &dnssec); if (r < 0) return r; @@ -411,6 +443,10 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + r = sd_bus_message_read_strv(message, &ntas); if (r < 0) return r; @@ -442,10 +478,15 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) { Link *l = userdata; + int r; assert(message); assert(l); + r = verify_unmanaged_link(l, error); + if (r < 0) + return r; + link_flush_settings(l); link_allocate_scopes(l); link_add_rrs(l, false); -- cgit v1.2.3-54-g00ecf From cabffaf86c17cdf74f92b8ef168fb9668f699c14 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 4 Jun 2016 18:15:42 -0400 Subject: test-keymap-util: use kbd-model-map/language-fallback-map from $(srcdir) This adds (undocumented) environment variables SYSTEMD_KBD_MODEL_MAP and SYSTEMD_LANGUAGE_FALLBACK_MAP, which, if set, override compiled-in locations of those two files. Instead of skipping tests when the maps are not installed, just use the one from the source dir. We still cannot do the mappings the other way if /usr/lib/kbd/keymaps is not present, so truncate the tests in that case. Also tweak the debug messages a bit to make it easier to see which function is failing. --- Makefile.am | 4 ++++ src/locale/keymap-util.c | 43 ++++++++++++++++++++++++++++++++++++------- src/locale/test-keymap-util.c | 38 +++++++++++++++++--------------------- 3 files changed, 57 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index fc6f3bf6d5..de3013567e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,6 +141,10 @@ else noinst_PROGRAMS = TESTS = endif +AM_TESTS_ENVIRONMENT = \ + export SYSTEMD_KBD_MODEL_MAP=$(abs_top_srcdir)/src/locale/kbd-model-map; \ + export SYSTEMD_LANGUAGE_FALLBACK_MAP=$(abs_top_srcdir)/src/locale/language-fallback-map; + if ENABLE_BASH_COMPLETION dist_bashcompletion_DATA = $(dist_bashcompletion_data) nodist_bashcompletion_DATA = $(nodist_bashcompletion_data) diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index 17bef9e481..a6bcd1ad54 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -46,6 +46,26 @@ static const char* strnulldash(const char *s) { return isempty(s) || streq(s, "-") ? NULL : s; } +static const char* systemd_kbd_model_map(void) { + const char* s; + + s = getenv("SYSTEMD_KBD_MODEL_MAP"); + if (s) + return s; + + return SYSTEMD_KBD_MODEL_MAP; +} + +static const char* systemd_language_fallback_map(void) { + const char* s; + + s = getenv("SYSTEMD_LANGUAGE_FALLBACK_MAP"); + if (s) + return s; + + return SYSTEMD_LANGUAGE_FALLBACK_MAP; +} + static void context_free_x11(Context *c) { c->x11_layout = mfree(c->x11_layout); c->x11_options = mfree(c->x11_options); @@ -427,8 +447,11 @@ static int read_next_mapping(const char* filename, } int vconsole_convert_to_x11(Context *c) { + const char *map; int modified = -1; + map = systemd_kbd_model_map(); + if (isempty(c->vc_keymap)) { modified = !isempty(c->x11_layout) || @@ -441,7 +464,7 @@ int vconsole_convert_to_x11(Context *c) { _cleanup_fclose_ FILE *f = NULL; unsigned n = 0; - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + f = fopen(map, "re"); if (!f) return -errno; @@ -449,7 +472,7 @@ int vconsole_convert_to_x11(Context *c) { _cleanup_strv_free_ char **a = NULL; int r; - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); + r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a); if (r < 0) return r; if (r == 0) @@ -526,14 +549,17 @@ int find_converted_keymap(const char *x11_layout, const char *x11_variant, char } int find_legacy_keymap(Context *c, char **new_keymap) { - _cleanup_fclose_ FILE *f; + const char *map; + _cleanup_fclose_ FILE *f = NULL; unsigned n = 0; unsigned best_matching = 0; int r; assert(!isempty(c->x11_layout)); - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + map = systemd_kbd_model_map(); + + f = fopen(map, "re"); if (!f) return -errno; @@ -541,7 +567,7 @@ int find_legacy_keymap(Context *c, char **new_keymap) { _cleanup_strv_free_ char **a = NULL; unsigned matching = 0; - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); + r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a); if (r < 0) return r; if (r == 0) @@ -619,13 +645,16 @@ int find_legacy_keymap(Context *c, char **new_keymap) { } int find_language_fallback(const char *lang, char **language) { + const char *map; _cleanup_fclose_ FILE *f = NULL; unsigned n = 0; assert(lang); assert(language); - f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re"); + map = systemd_language_fallback_map(); + + f = fopen(map, "re"); if (!f) return -errno; @@ -633,7 +662,7 @@ int find_language_fallback(const char *lang, char **language) { _cleanup_strv_free_ char **a = NULL; int r; - r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a); + r = read_next_mapping(map, 2, 2, f, &n, &a); if (r <= 0) return r; diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c index 1e30fa4cb0..7e2c9e505a 100644 --- a/src/locale/test-keymap-util.c +++ b/src/locale/test-keymap-util.c @@ -24,16 +24,10 @@ static void test_find_language_fallback(void) { _cleanup_free_ char *ans = NULL, *ans2 = NULL; - int r; - log_info("/* %s */", __func__); + log_info("/*** %s ***/", __func__); - r = find_language_fallback("foobar", &ans); - if (r == -ENOENT) { - log_info_errno(r, "Skipping language fallback tests: %m"); - return; - } - assert_se(r == 0); + assert_se(find_language_fallback("foobar", &ans) == 0); assert_se(ans == NULL); assert_se(find_language_fallback("csb", &ans) == 0); @@ -50,16 +44,17 @@ static void test_find_converted_keymap(void) { _cleanup_free_ char *ans = NULL, *ans2 = NULL; int r; - log_info("/* %s */", __func__); + log_info("/*** %s ***/", __func__); assert_se(find_converted_keymap("pl", "foobar", &ans) == 0); assert_se(ans == NULL); r = find_converted_keymap("pl", NULL, &ans); if (r == 0) { - log_info_errno(r, "Skipping find_converted_keymap tests: %m"); + log_info("Skipping rest of %s: keymaps are not installed", __func__); return; } + assert_se(r == 1); assert_se(streq(ans, "pl")); @@ -70,17 +65,11 @@ static void test_find_converted_keymap(void) { static void test_find_legacy_keymap(void) { Context c = {}; _cleanup_free_ char *ans = NULL, *ans2 = NULL; - int r; - log_info("/* %s */", __func__); + log_info("/*** %s ***/", __func__); c.x11_layout = (char*) "foobar"; - r = find_legacy_keymap(&c, &ans); - if (r == -ENOENT) { - log_info_errno(r, "Skipping test_legacy_keymap tests: %m"); - return; - } - assert_se(r == 0); + assert_se(find_legacy_keymap(&c, &ans) == 0); assert_se(ans == NULL); c.x11_layout = (char*) "pl"; @@ -95,7 +84,7 @@ static void test_find_legacy_keymap(void) { static void test_vconsole_convert_to_x11(void) { _cleanup_(context_free) Context c = {}; - log_info("/* %s */", __func__); + log_info("/*** %s ***/", __func__); log_info("/* test emptying first (:) */"); assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0); @@ -148,8 +137,9 @@ static void test_vconsole_convert_to_x11(void) { static void test_x11_convert_to_vconsole(void) { _cleanup_(context_free) Context c = {}; + int r; - log_info("/* %s */", __func__); + log_info("/*** %s ***/", __func__); log_info("/* test emptying first (:) */"); assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0); @@ -176,7 +166,13 @@ static void test_x11_convert_to_vconsole(void) { log_info("/* test with known variant, new mapping (es:dvorak) */"); assert_se(free_and_strdup(&c.x11_variant, "dvorak") >= 0); - assert_se(x11_convert_to_vconsole(&c) == 1); + r = x11_convert_to_vconsole(&c); + if (r == 0) { + log_info("Skipping rest of %s: keymaps are not installed", __func__); + return; + } + + assert_se(r == 1); assert_se(streq(c.vc_keymap, "es-dvorak")); log_info("/* test with old mapping (fr:latin9) */"); -- cgit v1.2.3-54-g00ecf From f045931a733c06252c6aaa845adac0bb56e2b9c0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 12 Jun 2016 10:42:13 -0400 Subject: Fixed a small typo in a comment (#3514) --- src/basic/random-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 2f468db770..ad7b3eedf2 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -46,7 +46,7 @@ int dev_urandom(void *p, size_t n) { * never block, and will always return some data from the * kernel, regardless if the random pool is fully initialized * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases + * returned entropy, but is good enough for our usual usecases * of seeding the hash functions for hashtable */ /* Use the getrandom() syscall unless we know we don't have -- cgit v1.2.3-54-g00ecf From ceac40781befe3b47141fea2e445258de572952f Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Sun, 12 Jun 2016 19:59:21 +0200 Subject: networkd: cleanup of bridge vlan code (#3505) cleanup minor nitpicks mentioned in #3428 --- src/network/networkd-brvlan.c | 12 +++--------- src/network/networkd-link.c | 5 ++--- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c index 77c08d090c..f621b8011b 100644 --- a/src/network/networkd-brvlan.c +++ b/src/network/networkd-brvlan.c @@ -39,12 +39,6 @@ static inline void set_bit(unsigned nr, uint32_t *addr) { addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); } -static inline int is_vid_valid(unsigned vid) { - if (vid > VLANID_MAX || vid == 0) - return -EINVAL; - return 0; -} - static int find_next_bit(int i, uint32_t x) { int j; @@ -240,21 +234,21 @@ static int parse_vid_range(const char *rvalue, uint16_t *vid, uint16_t *vid_end) if (r < 0) return r; - if (!_vid) + if (_vid == 0) return -ERANGE; r = parse_vlanid(p, &_vid_end); if (r < 0) return r; - if (!_vid_end) + if (_vid_end == 0) return -ERANGE; } else { r = parse_vlanid(_rvalue, &_vid); if (r < 0) return r; - if (!_vid) + if (_vid == 0) return -ERANGE; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index dce5c2be6e..0302f57f26 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -530,8 +530,7 @@ static void link_free(Link *link) { free(link->ifname); - if (link->kind) - free(link->kind); + free(link->kind); (void)unlink(link->state_file); free(link->state_file); @@ -2006,7 +2005,7 @@ static int link_joined(Link *link) { log_link_error_errno(link, r, "Could not set bridge message: %m"); } - if (link->network->bridge || NETDEV_KIND_BRIDGE == netdev_kind_from_string(link->kind)) { + if (link->network->bridge || streq("bridge", link->kind)) { r = link_set_bridge_vlan(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge vlan: %m"); -- cgit v1.2.3-54-g00ecf From 0e83e7a5a25ac90fc43c6f6d73007f9177614f3e Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Sun, 12 Jun 2016 20:01:14 +0200 Subject: networkd: more vlan cleanup (#3506) use config_parse_vlanid to parse vlan for BridgeFDB entries --- src/network/networkd-fdb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 9829438ba2..be8aebee2d 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -26,6 +26,7 @@ #include "networkd-fdb.h" #include "networkd.h" #include "util.h" +#include "vlan-util.h" #define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U @@ -240,9 +241,9 @@ int config_parse_fdb_vlan_id( if (r < 0) return log_oom(); - r = config_parse_unsigned(unit, filename, line, section, - section_line, lvalue, ltype, - rvalue, &fdb_entry->vlan_id, userdata); + r = config_parse_vlanid(unit, filename, line, section, + section_line, lvalue, ltype, + rvalue, &fdb_entry->vlan_id, userdata); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From ba4cd7e2573e591aa120655414d911f1a1882fe1 Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Mon, 13 Jun 2016 04:13:42 +0300 Subject: util-lib: drop trailing non-printable characters from cmdline (#3512) If max_length is equal or greater than cmdline length all trailing non-printable characters are dropped. If max_length is 0 it should do the same. This should also fix cmdline truncation if the last character is not '\0'. Fixes #3469. --- src/basic/process-util.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index b991e7c6ba..f6bde20fc5 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -102,6 +102,7 @@ int get_process_comm(pid_t pid, char **name) { int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { _cleanup_fclose_ FILE *f = NULL; + bool space = false; char *r = NULL, *k; const char *p; int c; @@ -128,14 +129,21 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -ENOMEM; } - r[len++] = isprint(c) ? c : ' '; - } + if (isprint(c)) { + if (space) { + r[len++] = ' '; + space = false; + } + + r[len++] = c; + } else + space = true; + } if (len > 0) - r[len-1] = 0; + r[len] = 0; } else { - bool space = false; size_t left; r = new(char, max_length); -- cgit v1.2.3-54-g00ecf From 9a140c3564006216e4c3a20c8d657669c09544c4 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 12 Jun 2016 19:42:51 -0400 Subject: test-process-util: rework the test function to take pid as argument This fixes a bunch of copy&paste errors in the output. --- src/test/test-process-util.c | 70 ++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 4616314200..40bf8b3c10 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -29,71 +29,64 @@ #include "log.h" #include "macro.h" #include "process-util.h" +#include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" #include "virt.h" -static void test_get_process_comm(void) { +static void test_get_process_comm(pid_t pid) { struct stat st; _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL; _cleanup_free_ char *env = NULL; + char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)]; pid_t e; uid_t u; gid_t g; dev_t h; int r; - pid_t me; - if (stat("/proc/1/comm", &st) == 0) { - assert_se(get_process_comm(1, &a) >= 0); - log_info("pid1 comm: '%s'", a); + xsprintf(path, "/proc/"PID_FMT"/comm", pid); + + if (stat(path, &st) == 0) { + assert_se(get_process_comm(pid, &a) >= 0); + log_info("PID"PID_FMT" comm: '%s'", pid, a); } else - log_warning("/proc/1/comm does not exist."); + log_warning("%s not exist.", path); - assert_se(get_process_cmdline(1, 0, true, &c) >= 0); - log_info("pid1 cmdline: '%s'", c); + assert_se(get_process_cmdline(pid, 0, true, &c) >= 0); + log_info("PID"PID_FMT" cmdline: '%s'", pid, c); - assert_se(get_process_cmdline(1, 8, false, &d) >= 0); - log_info("pid1 cmdline truncated: '%s'", d); + assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated: '%s'", pid, d); - assert_se(get_process_ppid(1, &e) >= 0); - log_info("pid1 ppid: "PID_FMT, e); - assert_se(e == 0); + assert_se(get_process_ppid(pid, &e) >= 0); + log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); + assert_se(pid == 1 ? e == 0 : e > 0); - assert_se(is_kernel_thread(1) == 0); + assert_se(is_kernel_thread(pid) == 0 || pid != 1); - r = get_process_exe(1, &f); + r = get_process_exe(pid, &f); assert_se(r >= 0 || r == -EACCES); - log_info("pid1 exe: '%s'", strna(f)); - - assert_se(get_process_uid(1, &u) == 0); - log_info("pid1 uid: "UID_FMT, u); - assert_se(u == 0); - - assert_se(get_process_gid(1, &g) == 0); - log_info("pid1 gid: "GID_FMT, g); - assert_se(g == 0); + log_info("PID"PID_FMT" exe: '%s'", pid, strna(f)); - me = getpid(); + assert_se(get_process_uid(pid, &u) == 0); + log_info("PID"PID_FMT" UID: "UID_FMT, pid, u); + assert_se(u == 0 || pid != 1); - r = get_process_cwd(me, &cwd); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 cwd: '%s'", cwd); - - r = get_process_root(me, &root); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 root: '%s'", root); + assert_se(get_process_gid(pid, &g) == 0); + log_info("PID"PID_FMT" GID: "GID_FMT, pid, g); + assert_se(g == 0 || pid != 1); - r = get_process_environ(me, &env); + r = get_process_environ(pid, &env); assert_se(r >= 0 || r == -EACCES); - log_info("self strlen(environ): '%zu'", strlen(env)); + log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno); if (!detect_container()) - assert_se(get_ctty_devnr(1, &h) == -ENXIO); + assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1); - getenv_for_pid(1, "PATH", &i); - log_info("pid1 $PATH: '%s'", strna(i)); + getenv_for_pid(pid, "PATH", &i); + log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i)); } static void test_pid_is_unwaited(void) { @@ -157,7 +150,8 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_get_process_comm(); + test_get_process_comm(1); + test_get_process_comm(getpid()); test_pid_is_unwaited(); test_pid_is_alive(); test_personality(); -- cgit v1.2.3-54-g00ecf From 18dade5aaee9f13efb95e6359723974d811c9b1e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 12 Jun 2016 19:51:11 -0400 Subject: test-process-util: allow pid to be specified on the command line This makes it easy to test the query code on "ssh localhost" and similar. --- src/test/test-process-util.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 40bf8b3c10..8bb5f6e3a3 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -28,6 +28,7 @@ #include "architecture.h" #include "log.h" #include "macro.h" +#include "parse-util.h" #include "process-util.h" #include "stdio-util.h" #include "string-util.h" @@ -150,8 +151,16 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_get_process_comm(1); - test_get_process_comm(getpid()); + if (argc > 1) { + pid_t pid = 0; + + (void) parse_pid(argv[1], &pid); + test_get_process_comm(pid); + } else { + test_get_process_comm(1); + test_get_process_comm(getpid()); + } + test_pid_is_unwaited(); test_pid_is_alive(); test_personality(); -- cgit v1.2.3-54-g00ecf From 4201ce672a267e081ec5ba6f36ae5cf18db8187f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 12 Jun 2016 20:57:41 -0400 Subject: process-util: remove broken support for pid==0 Our functions that query /proc/pid/ support using pid==0 to mean self. get_process_id also seemed to support that, but it was not implemented correctly: the result should be in *uid, not returned, and also it gave completely bogus result when called from get_process_gid(). But afaict, get_process_{uid,gid} were never called with pid==0, so it's not an actual bug. Remove the broken code to avoid confusion. --- src/basic/process-util.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index f6bde20fc5..08fa98bb9e 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -325,9 +325,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { assert(field); assert(uid); - if (pid == 0) - return getuid(); - p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); if (!f) { -- cgit v1.2.3-54-g00ecf From 988b3b1765153051d48f1b47f42e78d02d2f7a9a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 13 Jun 2016 00:57:28 -0400 Subject: systemctl: disallow systemctl --user reboot (#3519) ... as well as halt/poweroff/kexec/suspend/hibernate/hybrid-sleep. Running those commands will fail in user mode, but we try to set the wall message first, which might even succeed for privileged users. Best to nip the whole sequence in the bud. https://github.com/systemd/systemd/pull/3453#issuecomment-225455156 --- src/systemctl/systemctl.c | 142 +++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 914dba36dc..784c1cd7b5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3274,6 +3274,18 @@ static int start_special(int argc, char *argv[], void *userdata) { return start_unit(argc, argv, userdata); } +static int start_system_special(int argc, char *argv[], void *userdata) { + /* Like start_special above, but raises an error when running in user mode */ + + if (arg_scope != UNIT_FILE_SYSTEM) { + log_error("Bad action for %s mode.", + arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user"); + return -EINVAL; + } + + return start_special(argc, argv, userdata); +} + static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) { _cleanup_strv_free_ char **names = NULL; UnitActiveState active_state; @@ -7539,71 +7551,71 @@ static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units }, - { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, - { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets }, - { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers }, - { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs }, - { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines }, - { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method }, - { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job }, - { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ - { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */ - { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, - { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */ - { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ - { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */ - { "isolate", 2, 2, VERB_NOCHROOT, start_unit }, - { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit }, - { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, - { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, - { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed }, - { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, - { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat }, - { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, - { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, - { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, - { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, - { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment }, - { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, - { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, - { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment}, - { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_special }, - { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_special }, - { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special }, - { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed }, - { "enable", 2, VERB_ANY, 0, enable_unit }, - { "disable", 2, VERB_ANY, 0, enable_unit }, - { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled }, - { "reenable", 2, VERB_ANY, 0, enable_unit }, - { "preset", 2, VERB_ANY, 0, enable_unit }, - { "preset-all", VERB_ANY, 1, 0, preset_all }, - { "mask", 2, VERB_ANY, 0, enable_unit }, - { "unmask", 2, VERB_ANY, 0, enable_unit }, - { "link", 2, VERB_ANY, 0, enable_unit }, - { "revert", 2, VERB_ANY, 0, enable_unit }, - { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root }, - { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies }, - { "set-default", 2, 2, 0, set_default }, - { "get-default", VERB_ANY, 1, 0, get_default }, - { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property }, - { "is-system-running", VERB_ANY, 1, 0, is_system_running }, - { "add-wants", 3, VERB_ANY, 0, add_dependency }, - { "add-requires", 3, VERB_ANY, 0, add_dependency }, - { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit }, + { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, + { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets }, + { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers }, + { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs }, + { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines }, + { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method }, + { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job }, + { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ + { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */ + { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */ + { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ + { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */ + { "isolate", 2, 2, VERB_NOCHROOT, start_unit }, + { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit }, + { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, + { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, + { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed }, + { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat }, + { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment }, + { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, + { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, + { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment }, + { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_system_special }, + { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_system_special }, + { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special }, + { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed }, + { "enable", 2, VERB_ANY, 0, enable_unit }, + { "disable", 2, VERB_ANY, 0, enable_unit }, + { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled }, + { "reenable", 2, VERB_ANY, 0, enable_unit }, + { "preset", 2, VERB_ANY, 0, enable_unit }, + { "preset-all", VERB_ANY, 1, 0, preset_all }, + { "mask", 2, VERB_ANY, 0, enable_unit }, + { "unmask", 2, VERB_ANY, 0, enable_unit }, + { "link", 2, VERB_ANY, 0, enable_unit }, + { "revert", 2, VERB_ANY, 0, enable_unit }, + { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root }, + { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies }, + { "set-default", 2, 2, 0, set_default }, + { "get-default", VERB_ANY, 1, 0, get_default }, + { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property }, + { "is-system-running", VERB_ANY, 1, 0, is_system_running }, + { "add-wants", 3, VERB_ANY, 0, add_dependency }, + { "add-requires", 3, VERB_ANY, 0, add_dependency }, + { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit }, {} }; -- cgit v1.2.3-54-g00ecf From 2065ca699b38d97b2a4ebd34a7c2d2c186970d20 Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Mon, 13 Jun 2016 12:50:12 +0200 Subject: core/execute: pass env vars to PAM session setup (#3503) Move the merger of environment variables before setting up the PAM session and pass the aggregate environment to PAM setup. This allows control over the PAM session hooks through environment variables. PAM session initiation may update the environment. On successful initiation of a PAM session, we adopt the environment of the PAM context. --- src/core/execute.c | 73 +++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 802f14d575..c20650626c 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -799,7 +799,7 @@ static int setup_pam( const char *user, uid_t uid, const char *tty, - char ***pam_env, + char ***env, int fds[], unsigned n_fds) { static const struct pam_conv conv = { @@ -818,7 +818,7 @@ static int setup_pam( assert(name); assert(user); - assert(pam_env); + assert(env); /* We set up PAM in the parent process, then fork. The child * will then stay around until killed via PR_GET_PDEATHSIG or @@ -846,6 +846,12 @@ static int setup_pam( goto fail; } + STRV_FOREACH(e, *env) { + pam_code = pam_putenv(handle, *e); + if (pam_code != PAM_SUCCESS) + goto fail; + } + pam_code = pam_acct_mgmt(handle, flags); if (pam_code != PAM_SUCCESS) goto fail; @@ -966,8 +972,8 @@ static int setup_pam( if (!barrier_place_and_sync(&barrier)) log_error("PAM initialization failed"); - *pam_env = e; - e = NULL; + strv_free(*env); + *env = e; return 0; @@ -1464,7 +1470,7 @@ static int exec_child( char **files_env, int *exit_status) { - _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; + _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; const char *username = NULL, *home = NULL, *shell = NULL, *wd; uid_t uid = UID_INVALID; @@ -1715,6 +1721,30 @@ static int exec_child( } } + r = build_environment(context, params, n_fds, home, username, shell, &our_env); + if (r < 0) { + *exit_status = EXIT_MEMORY; + return r; + } + + r = build_pass_environment(context, &pass_env); + if (r < 0) { + *exit_status = EXIT_MEMORY; + return r; + } + + accum_env = strv_env_merge(5, + params->environment, + our_env, + pass_env, + context->environment, + files_env, + NULL); + if (!accum_env) { + *exit_status = EXIT_MEMORY; + return -ENOMEM; + } + umask(context->umask); if (params->apply_permissions && !command->privileged) { @@ -1751,7 +1781,7 @@ static int exec_child( #endif #ifdef HAVE_PAM if (context->pam_name && username) { - r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds); + r = setup_pam(context->pam_name, username, uid, context->tty_path, &accum_env, fds, n_fds); if (r < 0) { *exit_status = EXIT_PAM; return r; @@ -1997,38 +2027,13 @@ static int exec_child( #endif } - r = build_environment(context, params, n_fds, home, username, shell, &our_env); - if (r < 0) { - *exit_status = EXIT_MEMORY; - return r; - } - - r = build_pass_environment(context, &pass_env); - if (r < 0) { - *exit_status = EXIT_MEMORY; - return r; - } - - final_env = strv_env_merge(6, - params->environment, - our_env, - pass_env, - context->environment, - files_env, - pam_env, - NULL); - if (!final_env) { - *exit_status = EXIT_MEMORY; - return -ENOMEM; - } - - final_argv = replace_env_argv(argv, final_env); + final_argv = replace_env_argv(argv, accum_env); if (!final_argv) { *exit_status = EXIT_MEMORY; return -ENOMEM; } - final_env = strv_env_clean(final_env); + accum_env = strv_env_clean(accum_env); if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { _cleanup_free_ char *line; @@ -2045,7 +2050,7 @@ static int exec_child( } } - execve(command->path, final_argv, final_env); + execve(command->path, final_argv, accum_env); *exit_status = EXIT_EXEC; return -errno; } -- cgit v1.2.3-54-g00ecf From 1c4b11794bdf54480a69a55645e60d5996dcb454 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 13 Jun 2016 19:27:17 +0530 Subject: networkd: route priority replace parsing config_parse_uint32 with safe_atou32 (#3522) --- src/network/networkd-route.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 52037f9c6d..cedaf47cf8 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -795,6 +795,7 @@ int config_parse_route_priority(const char *unit, void *userdata) { Network *network = userdata; _cleanup_route_free_ Route *n = NULL; + uint32_t k; int r; assert(filename); @@ -807,12 +808,14 @@ int config_parse_route_priority(const char *unit, if (r < 0) return r; - r = config_parse_uint32(unit, filename, line, section, - section_line, lvalue, ltype, - rvalue, &n->priority, userdata); - if (r < 0) - return r; + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + n->priority = k; n = NULL; return 0; -- cgit v1.2.3-54-g00ecf From 357bb46af6633f7f03cfa4a23619b5a20a29a8b8 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 13 Jun 2016 19:27:38 +0530 Subject: networkd: fix NULL pointer (#3523) Not every link has kind associated with it. (gdb) r Starting program: /home/sus/tt/systemd/systemd-networkd Missing separate debuginfos, use: dnf debuginfo-install glibc-2.23.1-7.fc24.x86_64 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". vboxnet0: Gained IPv6LL wlp3s0: Gained IPv6LL enp0s25: Gained IPv6LL Enumeration completed Program received signal SIGSEGV, Segmentation fault. 0x00007ffff6e27ade in __strcmp_sse2_unaligned () from /lib64/libc.so.6 (gdb) bt src/network/networkd-link.c:2008 src/network/networkd-link.c:2059 src/network/networkd-link.c:2442 m=0x555555704a30, userdata=0x55555570bfe0) at src/network/networkd-link.c:2497 at src/libsystemd/sd-netlink/sd-netlink.c:347 src/libsystemd/sd-netlink/sd-netlink.c:402 src/libsystemd/sd-netlink/sd-netlink.c:432 userdata=0x5555556f7470) at src/libsystemd/sd-netlink/sd-netlink.c:739 src/libsystemd/sd-event/sd-event.c:2275 src/libsystemd/sd-event/sd-event.c:2626 timeout=18446744073709551615) at src/libsystemd/sd-event/sd-event.c:2685 bus=0x5555556f9af0, name=0x555555692315 "org.freedesktop.network1", timeout=30000000, check_idle=0x55555556ac84 , userdata=0x5555556f6b20) at src/shared/bus-util.c:134 src/network/networkd-manager.c:1128 src/network/networkd.c:127 (gdb) f 1 src/network/networkd-link.c:2008 2008 if (link->network->bridge || streq("bridge", link->kind)) { (gdb) p link->kind $1 = 0x0 --- src/network/networkd-link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0302f57f26..044f934e5f 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2005,7 +2005,7 @@ static int link_joined(Link *link) { log_link_error_errno(link, r, "Could not set bridge message: %m"); } - if (link->network->bridge || streq("bridge", link->kind)) { + if (link->network->bridge || streq_ptr("bridge", link->kind)) { r = link_set_bridge_vlan(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge vlan: %m"); -- cgit v1.2.3-54-g00ecf From aac57b3539608c28e714643de3cf581a6f6322e5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 13 Jun 2016 10:24:48 -0400 Subject: resolved: use single message for both dbus and signal calls (#3515) Follow-up for #3502. --- src/resolve/resolved-manager.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index a46f13b92f..23101cb760 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -474,7 +474,6 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si assert(m); manager_flush_caches(m); - log_info("Flushed all caches."); return 0; } @@ -1257,4 +1256,6 @@ void manager_flush_caches(Manager *m) { LIST_FOREACH(scopes, scope, m->dns_scopes) dns_cache_flush(&scope->cache); + + log_info("Flushed all caches."); } -- cgit v1.2.3-54-g00ecf From 50b52222f2d54a3c4d81e0e5987a0400cbcefb53 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 17:31:06 +0200 Subject: nspawn: order caps to retain alphabetically --- src/nspawn/nspawn.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ea24de7608..73c56d7310 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -137,6 +137,8 @@ static bool arg_ephemeral = false; static LinkJournal arg_link_journal = LINK_AUTO; static bool arg_link_journal_try = false; static uint64_t arg_caps_retain = + (1ULL << CAP_AUDIT_CONTROL) | + (1ULL << CAP_AUDIT_WRITE) | (1ULL << CAP_CHOWN) | (1ULL << CAP_DAC_OVERRIDE) | (1ULL << CAP_DAC_READ_SEARCH) | @@ -146,23 +148,21 @@ static uint64_t arg_caps_retain = (1ULL << CAP_KILL) | (1ULL << CAP_LEASE) | (1ULL << CAP_LINUX_IMMUTABLE) | + (1ULL << CAP_MKNOD) | (1ULL << CAP_NET_BIND_SERVICE) | (1ULL << CAP_NET_BROADCAST) | (1ULL << CAP_NET_RAW) | - (1ULL << CAP_SETGID) | (1ULL << CAP_SETFCAP) | + (1ULL << CAP_SETGID) | (1ULL << CAP_SETPCAP) | (1ULL << CAP_SETUID) | (1ULL << CAP_SYS_ADMIN) | + (1ULL << CAP_SYS_BOOT) | (1ULL << CAP_SYS_CHROOT) | (1ULL << CAP_SYS_NICE) | (1ULL << CAP_SYS_PTRACE) | - (1ULL << CAP_SYS_TTY_CONFIG) | (1ULL << CAP_SYS_RESOURCE) | - (1ULL << CAP_SYS_BOOT) | - (1ULL << CAP_AUDIT_WRITE) | - (1ULL << CAP_AUDIT_CONTROL) | - (1ULL << CAP_MKNOD); + (1ULL << CAP_SYS_TTY_CONFIG); static CustomMount *arg_custom_mounts = NULL; static unsigned arg_n_custom_mounts = 0; static char **arg_setenv = NULL; -- cgit v1.2.3-54-g00ecf From 1f9ac68b5bc671f1f8b0a32084810d39394208a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 17:43:38 +0200 Subject: core: improve seccomp syscall grouping a bit This adds three new seccomp syscall groups: @keyring for kernel keyring access, @cpu-emulation for CPU emulation features, for exampe vm86() for dosemu and suchlike, and @debug for ptrace() and related calls. Also, the @clock group is updated with more syscalls that alter the system clock. capset() is added to @privileged, and pciconfig_iobase() is added to @raw-io. Finally, @obsolete is a cleaned up. A number of syscalls that never existed on Linux and have no number assigned on any architecture are removed, as they only exist in the man pages and other operating sytems, but not in code at all. create_module() is moved from @module to @obsolete, as it is an obsolete system call. mem_getpolicy() is removed from the @obsolete list, as it is not obsolete, but simply a NUMA API. --- man/systemd.exec.xml | 38 ++++++++++++++++++-------------- src/shared/seccomp-util.c | 55 +++++++++++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 1c3256a662..a39e800854 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1218,49 +1218,55 @@ @clock - System calls for changing the system clock (adjtimex(), - settimeofday()) + System calls for changing the system clock (adjtimex2, settimeofday2, and related calls) + + + @cpu-emulation + System calls for CPU emulation functionality (vm862 and related calls) + + + @debug + Debugging, performance monitoring and tracing functionality (ptrace2, perf_event_open2 and related calls) @io-event - Event loop use (poll(), select(), - epoll7, - eventfd()...) + Event loop system calls (poll2, select2, epoll7, eventfd2 and related calls) @ipc - SysV IPC, POSIX Message Queues or other IPC (mq_overview7, - svipc7) + SysV IPC, POSIX Message Queues or other IPC (mq_overview7, svipc7) + + + @keyring + Kernel keyring access (keyctl2 and related calls) @module - Kernel module control (create_module(), init_module()...) + Kernel module control (init_module2, delete_module2 and related calls) @mount - File system mounting and unmounting (chroot(), mount()...) + File system mounting and unmounting (mount2, chroot2, and related calls) @network-io - Socket I/O (including local AF_UNIX): - socket7, - unix7 + Socket I/O (including local AF_UNIX): socket7, unix7 @obsolete - Unusual, obsolete or unimplemented (fattach(), gtty(), vm86()...) + Unusual, obsolete or unimplemented (create_module2, gtty2, …) @privileged - All system calls which need superuser capabilities (capabilities7) + All system calls which need super-user capabilities (capabilities7) @process - Process control, execution, namespaces (execve(), kill(), namespaces7...) + Process control, execution, namespaces (execve2, kill2, namespaces7, … @raw-io - Raw I/O ports (ioperm(), iopl(), pciconfig_read()...) + Raw I/O port access (ioperm2, iopl2, pciconfig_read(), … diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 30d22d2242..8656d112b8 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -95,7 +95,31 @@ const SystemCallFilterSet syscall_filter_sets[] = { .set_name = "@clock", .value = "adjtimex\0" + "clock_adjtime\0" + "clock_settime\0" "settimeofday\0" + "stime\0" + }, { + /* CPU emulation calls */ + .set_name = "@cpu-emulation", + .value = + "modify_ldt\0" + "subpage_prot\0" + "switch_endian\0" + "vm86\0" + "vm86old\0" + }, { + /* Debugging/Performance Monitoring/Tracing */ + .set_name = "@debug", + .value = + "lookup_dcookie\0" + "perf_event_open\0" + "process_vm_readv\0" + "process_vm_writev\0" + "ptrace\0" + "rtas\0" + "s390_runtime_instr\0" + "sys_debug_setcontext\0" }, { /* Default list */ .set_name = "@default", @@ -147,11 +171,17 @@ const SystemCallFilterSet syscall_filter_sets[] = { "shmctl\0" "shmdt\0" "shmget\0" + }, { + /* Keyring */ + .set_name = "@keyring", + .value = + "add_key\0" + "keyctl\0" + "request_key\0" }, { /* Kernel module control */ .set_name = "@module", .value = - "create_module\0" "delete_module\0" "finit_module\0" "init_module\0" @@ -197,40 +227,26 @@ const SystemCallFilterSet syscall_filter_sets[] = { "_sysctl\0" "afs_syscall\0" "break\0" - "fattach\0" - "fdetach\0" + "create_module\0" "ftime\0" "get_kernel_syms\0" - "get_mempolicy\0" - "getmsg\0" "getpmsg\0" "gtty\0" - "isastream\0" "lock\0" - "madvise1\0" - "modify_ldt\0" "mpx\0" - "pciconfig_iobase\0" - "perf_event_open\0" "prof\0" "profil\0" - "putmsg\0" "putpmsg\0" "query_module\0" - "rtas\0" - "s390_runtime_instr\0" "security\0" "sgetmask\0" "ssetmask\0" "stty\0" - "subpage_prot\0" - "switch_endian\0" - "sys_debug_setcontext\0" + "sysfs\0" "tuxcall\0" "ulimit\0" "uselib\0" - "vm86\0" - "vm86old\0" + "ustat\0" "vserver\0" }, { /* Nice grab-bag of all system calls which need superuser capabilities */ @@ -242,6 +258,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { "acct\0" "bdflush\0" "bpf\0" + "capset\0" "chown32\0" "chown\0" "chroot\0" @@ -268,7 +285,6 @@ const SystemCallFilterSet syscall_filter_sets[] = { "setreuid\0" "setuid32\0" "setuid\0" - "stime\0" "swapoff\0" "swapon\0" "sysctl\0" @@ -295,6 +311,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { .value = "ioperm\0" "iopl\0" + "pciconfig_iobase\0" "pciconfig_read\0" "pciconfig_write\0" "s390_pci_mmio_read\0" -- cgit v1.2.3-54-g00ecf From 54a17e01de048a2275f8861b211f10d11e56407d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 18:04:02 +0200 Subject: nspawn: lock down system call filter a bit Let's block access to the kernel keyring and a number of obsolete system calls. Also, update list of syscalls that may alter the system clock, and do raw IO access. Filter ptrace() if CAP_SYS_PTRACE is not passed to the container and acct() if CAP_SYS_PACCT is not passed. This also changes things so that kexec(), some profiling calls, the swap calls and quotactl() is never available to containers, not even if CAP_SYS_ADMIN is passed. After all we currently permit CAP_SYS_ADMIN to containers by default, but these calls should not be available, even then. --- src/nspawn/nspawn-seccomp.c | 78 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 2d145b68a7..54db1b47f8 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -44,20 +44,76 @@ static int seccomp_add_default_syscall_filter(scmp_filter_ctx ctx, uint64_t capability; int syscall_num; } blacklist[] = { - { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, - { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, - { CAP_SYS_BOOT, SCMP_SYS(kexec_load) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapon) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapoff) }, - { CAP_SYS_ADMIN, SCMP_SYS(open_by_handle_at) }, - { CAP_SYS_MODULE, SCMP_SYS(init_module) }, - { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, - { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, - { CAP_SYSLOG, SCMP_SYS(syslog) }, + { 0, SCMP_SYS(_sysctl) }, /* obsolete syscall */ + { 0, SCMP_SYS(add_key) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(afs_syscall) }, /* obsolete syscall */ + { 0, SCMP_SYS(bdflush) }, +#ifdef __NR_bpf + { 0, SCMP_SYS(bpf) }, +#endif + { 0, SCMP_SYS(break) }, /* obsolete syscall */ + { 0, SCMP_SYS(create_module) }, /* obsolete syscall */ + { 0, SCMP_SYS(ftime) }, /* obsolete syscall */ + { 0, SCMP_SYS(get_kernel_syms) }, /* obsolete syscall */ + { 0, SCMP_SYS(getpmsg) }, /* obsolete syscall */ + { 0, SCMP_SYS(gtty) }, /* obsolete syscall */ +#ifdef __NR_kexec_file_load + { 0, SCMP_SYS(kexec_file_load) }, +#endif + { 0, SCMP_SYS(kexec_load) }, + { 0, SCMP_SYS(keyctl) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(lock) }, /* obsolete syscall */ + { 0, SCMP_SYS(lookup_dcookie) }, + { 0, SCMP_SYS(mpx) }, /* obsolete syscall */ + { 0, SCMP_SYS(nfsservctl) }, /* obsolete syscall */ + { 0, SCMP_SYS(open_by_handle_at) }, + { 0, SCMP_SYS(perf_event_open) }, + { 0, SCMP_SYS(prof) }, /* obsolete syscall */ + { 0, SCMP_SYS(profil) }, /* obsolete syscall */ + { 0, SCMP_SYS(putpmsg) }, /* obsolete syscall */ + { 0, SCMP_SYS(query_module) }, /* obsolete syscall */ + { 0, SCMP_SYS(quotactl) }, + { 0, SCMP_SYS(request_key) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(security) }, /* obsolete syscall */ + { 0, SCMP_SYS(sgetmask) }, /* obsolete syscall */ + { 0, SCMP_SYS(ssetmask) }, /* obsolete syscall */ + { 0, SCMP_SYS(stty) }, /* obsolete syscall */ + { 0, SCMP_SYS(swapoff) }, + { 0, SCMP_SYS(swapon) }, + { 0, SCMP_SYS(sysfs) }, /* obsolete syscall */ + { 0, SCMP_SYS(tuxcall) }, /* obsolete syscall */ + { 0, SCMP_SYS(ulimit) }, /* obsolete syscall */ + { 0, SCMP_SYS(uselib) }, /* obsolete syscall */ + { 0, SCMP_SYS(ustat) }, /* obsolete syscall */ + { 0, SCMP_SYS(vserver) }, /* obsolete syscall */ + { CAP_SYSLOG, SCMP_SYS(syslog) }, + { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, + { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, + { CAP_SYS_MODULE, SCMP_SYS(init_module) }, + { CAP_SYS_PACCT, SCMP_SYS(acct) }, + { CAP_SYS_PTRACE, SCMP_SYS(process_vm_readv) }, + { CAP_SYS_PTRACE, SCMP_SYS(process_vm_writev) }, + { CAP_SYS_PTRACE, SCMP_SYS(ptrace) }, + { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, + { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_iobase) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_read) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_write) }, +#ifdef __NR_s390_pci_mmio_read + { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_read) }, +#endif +#ifdef __NR_s390_pci_mmio_write + { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_write) }, +#endif + { CAP_SYS_TIME, SCMP_SYS(adjtimex) }, + { CAP_SYS_TIME, SCMP_SYS(clock_adjtime) }, + { CAP_SYS_TIME, SCMP_SYS(clock_settime) }, + { CAP_SYS_TIME, SCMP_SYS(settimeofday) }, + { CAP_SYS_TIME, SCMP_SYS(stime) }, }; for (i = 0; i < ELEMENTSOF(blacklist); i++) { - if (cap_list_retain & (1ULL << blacklist[i].capability)) + if (blacklist[i].capability != 0 && (cap_list_retain & (1ULL << blacklist[i].capability))) continue; r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0); -- cgit v1.2.3-54-g00ecf From dcd61450026c281c916f12c2affa220e0994ba19 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Mon, 13 Jun 2016 18:28:42 +0400 Subject: core: parse `rd.rescue` and `rd.emergency` as initrd-specific shorthands (#3488) Typing `rd.rescue` is easier than `rd.systemd.unit=rescue.target`. --- man/kernel-command-line.xml | 4 +++- man/systemd.xml | 14 ++++++++------ src/basic/proc-cmdline.c | 18 +++++++++++++++--- src/basic/util.c | 18 +++++++++++------- src/basic/util.h | 1 + src/core/main.c | 2 +- src/test/test-proc-cmdline.c | 11 +++++++++++ 7 files changed, 50 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 9c04849f66..3ecc969c10 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -146,7 +146,9 @@ -b + rd.emergency emergency + rd.rescue rescue single s @@ -158,7 +160,7 @@ 5 Parameters understood by the system and service - manager, as compatibility options. For details, see + manager, as compatibility and convenience options. For details, see systemd1. diff --git a/man/systemd.xml b/man/systemd.xml index b8d91b8943..65f55199e2 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -1024,25 +1024,27 @@ emergency + rd.emergency -b Boot into emergency mode. This is equivalent - to systemd.unit=emergency.target and - provided for compatibility reasons and to be easier to - type. + to systemd.unit=emergency.target or + rd.systemd.unit=emergency.target, respectively, and + provided for compatibility reasons and to be easier to type. rescue + rd.rescue single s S 1 Boot into rescue mode. This is equivalent to - systemd.unit=rescue.target and provided for - compatibility reasons and to be easier to - type. + systemd.unit=rescue.target or + rd.systemd.unit=rescue.target, respectively, and + provided for compatibility reasons and to be easier to type. diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 3505fa9c9a..0430beadaa 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -160,17 +160,29 @@ static const char * const rlmap[] = { "3", SPECIAL_MULTI_USER_TARGET, "4", SPECIAL_MULTI_USER_TARGET, "5", SPECIAL_GRAPHICAL_TARGET, + NULL +}; + +static const char * const rlmap_initrd[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + NULL }; const char* runlevel_to_target(const char *word) { size_t i; + const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd + : rlmap; if (!word) return NULL; - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) - return rlmap[i+1]; + if (in_initrd() && (word = startswith(word, "rd.")) == NULL) + return NULL; + + for (i = 0; rlmap_ptr[i] != NULL; i += 2) + if (streq(word, rlmap_ptr[i])) + return rlmap_ptr[i+1]; return NULL; } diff --git a/src/basic/util.c b/src/basic/util.c index 756c663be4..f2f92fb3b7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -64,6 +64,7 @@ assert_cc(EAGAIN == EWOULDBLOCK); int saved_argc = 0; char **saved_argv = NULL; +static int saved_in_initrd = -1; size_t page_size(void) { static thread_local size_t pgsz = 0; @@ -454,11 +455,10 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa } bool in_initrd(void) { - static int saved = -1; struct statfs s; - if (saved >= 0) - return saved; + if (saved_in_initrd >= 0) + return saved_in_initrd; /* We make two checks here: * @@ -470,11 +470,15 @@ bool in_initrd(void) { * emptying when transititioning to the main systemd. */ - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); - return saved; + return saved_in_initrd; +} + +void in_initrd_force(bool value) { + saved_in_initrd = value; } /* hey glibc, APIs with callbacks without a user pointer are so useless */ diff --git a/src/basic/util.h b/src/basic/util.h index 1c032c15c9..9e6df19ef1 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -86,6 +86,7 @@ int prot_from_flags(int flags) _const_; int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); bool in_initrd(void); +void in_initrd_force(bool value); void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), diff --git a/src/core/main.c b/src/core/main.c index 93098daa9b..2785a3aa0b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -409,7 +409,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (detect_container() > 0) log_set_target(LOG_TARGET_CONSOLE); - } else if (!in_initrd() && !value) { + } else if (!value) { const char *target; /* SysV compatibility */ diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index a7a8f621a2..80ad5ed98b 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -23,6 +23,7 @@ #include "proc-cmdline.h" #include "special.h" #include "string-util.h" +#include "util.h" static int parse_item(const char *key, const char *value) { assert_se(key); @@ -36,9 +37,19 @@ static void test_parse_proc_cmdline(void) { } static void test_runlevel_to_target(void) { + in_initrd_force(false); assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); + + in_initrd_force(true); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); } int main(void) { -- cgit v1.2.3-54-g00ecf From f256aa8853ad5d856457aa427224a585df54b00b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Jun 2016 18:47:42 +0200 Subject: unit-name: remove spurious newline --- src/basic/unit-name.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index f209a84634..44eadf0347 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -195,7 +195,6 @@ typedef enum SwapState { _SWAP_STATE_INVALID = -1 } SwapState; - typedef enum TargetState { TARGET_DEAD, TARGET_ACTIVE, -- cgit v1.2.3-54-g00ecf From 51e22f8851fae578188bd190510a205f0e4487f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Jun 2016 18:54:36 +0200 Subject: systemctl: fix assertion hit when showing state of a unit without control group --- src/systemctl/systemctl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 784c1cd7b5..74ef2d7ba1 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3847,14 +3847,13 @@ static void print_status_info( printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); } - if (i->control_group) - printf(" CGroup: %s\n", i->control_group); - - { + if (i->control_group) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; static const char prefix[] = " "; unsigned c; + printf(" CGroup: %s\n", i->control_group); + c = columns(); if (c > sizeof(prefix) - 1) c -= sizeof(prefix) - 1; -- cgit v1.2.3-54-g00ecf From 3dced37b7c2c9a5c733817569d2bbbaa397adaf7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Jun 2016 19:11:26 +0200 Subject: systemctl: rework "systemctl status" a bit This reworks "systemctl status" and "systemctl show" a bit. It removes the definition of the `property_info` structure, because we can simply reuse the existing UnitStatusInfo type for that. The "could not be found" message is now printed by show_one() itself (and not its caller), so that it is shown regardless by who the function is called. (This makes it necessary to pass the unit name to the function.) This also adds all properties found to a set, and then checks if any of the properties passed via "--property=" is mising in it, if so, a proper error is generated. Support for checking the PID file of a unit is removed, as this cannot be done reasonably client side (since the systemd instance we are talking to might sit on another host) Replaces: #3411 Fixes: #3425 Also see: #3504 --- src/systemctl/systemctl.c | 120 +++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 74ef2d7ba1..feb93cad8e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4558,12 +4558,20 @@ static int show_one( const char *verb, sd_bus *bus, const char *path, + const char *unit, bool show_properties, bool *new_line, bool *ellipsized) { + static const struct bus_properties_map property_map[] = { + { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, + { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) }, + {} + }; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_set_free_ Set *found_properties = NULL; UnitStatusInfo info = { .memory_current = (uint64_t) -1, .memory_high = CGROUP_LIMIT_MAX, @@ -4573,14 +4581,6 @@ static int show_one( .tasks_current = (uint64_t) -1, .tasks_max = (uint64_t) -1, }; - struct property_info { - const char *load_state, *active_state; - } property_info = {}; - static const struct bus_properties_map property_map[] = { - { "LoadState", "s", NULL, offsetof(struct property_info, load_state) }, - { "ActiveState", "s", NULL, offsetof(struct property_info, active_state) }, - {} - }; ExecStatusInfo *p; int r; @@ -4601,16 +4601,24 @@ static int show_one( if (r < 0) return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); - r = bus_message_map_all_properties(reply, property_map, &property_info); - if (r < 0) - return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); + if (unit) { + r = bus_message_map_all_properties(reply, property_map, &info); + if (r < 0) + return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); - if (streq_ptr(property_info.load_state, "not-found") && streq_ptr(property_info.active_state, "inactive")) - return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) { + log_error("Unit %s could not be found.", unit); - r = sd_bus_message_rewind(reply, true); - if (r < 0) - return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); + if (streq(verb, "status")) + return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + + return -ENOENT; + } + + r = sd_bus_message_rewind(reply, true); + if (r < 0) + return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); + } r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); if (r < 0) @@ -4636,9 +4644,17 @@ static int show_one( if (r < 0) return bus_log_parse_error(r); - if (show_properties) + if (show_properties) { + r = set_ensure_allocated(&found_properties, &string_hash_ops); + if (r < 0) + return log_oom(); + + r = set_put(found_properties, name); + if (r < 0 && r != EEXIST) + return log_oom(); + r = print_property(name, reply, contents); - else + } else r = status_property(name, reply, &info, contents); if (r < 0) return r; @@ -4660,35 +4676,30 @@ static int show_one( r = 0; - if (!show_properties) { - if (streq(verb, "help")) - show_unit_help(&info); + if (show_properties) { + char **pp; + + STRV_FOREACH(pp, arg_properties) { + if (!set_contains(found_properties, *pp)) { + log_warning("Property %s does not exist.", *pp); + r = -ENXIO; + } + } + } else if (streq(verb, "help")) + show_unit_help(&info); + else if (streq(verb, "status")) { + print_status_info(bus, &info, ellipsized); + + if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) + r = EXIT_PROGRAM_NOT_RUNNING; else - print_status_info(bus, &info, ellipsized); + r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; } strv_free(info.documentation); strv_free(info.dropin_paths); strv_free(info.listen); - if (!streq_ptr(info.active_state, "active") && - !streq_ptr(info.active_state, "reloading") && - streq(verb, "status")) { - /* According to LSB: "program not running" */ - /* 0: program is running or service is OK - * 1: program is dead and /run PID file exists - * 2: program is dead and /run/lock lock file exists - * 3: program is not running - * 4: program or service status is unknown - */ - if (info.pid_file && access(info.pid_file, F_OK) == 0) - r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; - else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) - r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; - else - r = EXIT_PROGRAM_NOT_RUNNING; - } - while ((p = info.exec)) { LIST_REMOVE(exec, info.exec, p); exec_status_info_free(p); @@ -4761,7 +4772,7 @@ static int show_all( if (!p) return log_oom(); - r = show_one(verb, bus, p, show_properties, new_line, ellipsized); + r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4857,7 +4868,7 @@ static int show(int argc, char *argv[], void *userdata) { /* If no argument is specified inspect the manager itself */ if (show_properties && argc <= 1) - return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); + return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized); if (show_status && argc <= 1) { @@ -4872,7 +4883,7 @@ static int show(int argc, char *argv[], void *userdata) { char **name; STRV_FOREACH(name, strv_skip(argv, 1)) { - _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *path = NULL, *unit = NULL; uint32_t id; if (safe_atou32(*name, &id) < 0) { @@ -4882,19 +4893,23 @@ static int show(int argc, char *argv[], void *userdata) { continue; } else if (show_properties) { /* Interpret as job id */ - if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) + if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0) return log_oom(); } else { /* Interpret as PID */ - r = get_unit_dbus_path_by_pid(bus, id, &unit); + r = get_unit_dbus_path_by_pid(bus, id, &path); if (r < 0) { ret = r; continue; } + + r = unit_name_from_dbus_path(path, &unit); + if (r < 0) + return log_oom(); } - r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); + r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4909,20 +4924,17 @@ static int show(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - _cleanup_free_ char *unit; + _cleanup_free_ char *path; - unit = unit_dbus_path_from_name(*name); - if (!unit) + path = unit_dbus_path_from_name(*name); + if (!path) return log_oom(); - r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); + r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized); if (r < 0) return r; - else if (r > 0 && ret == 0) + if (r > 0 && ret == 0) ret = r; - - if (r == EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN) - log_error("Can't display property %s. Unit %s does not exist.", *patterns, *name); } } } -- cgit v1.2.3-54-g00ecf From f4f5e50a0ab828991ff54e7013acc6917a9510fa Mon Sep 17 00:00:00 2001 From: Andrew Jeddeloh Date: Tue, 14 Jun 2016 02:09:06 -0700 Subject: build: fix missing symbol for old kernel headers (#3530) Fix issue where IN6_ADDR_GEN_MODE_STABLE_PRIVACY is undefined but IFLA_INET6_ADDR_GEN_MODE is defined and thus the former does not get fixed in missing.h. This occurs with kernel headers new enough to have the IFLA_INET6_ADDR_GEN_MODE but old enough to not yet have IN6_ADDR_GEN_MODE_STABLE_PRIVACY (e.g. 3.18). --- configure.ac | 1 + src/basic/missing.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/configure.ac b/configure.ac index 329861a291..ffc6eedcdd 100644 --- a/configure.ac +++ b/configure.ac @@ -324,6 +324,7 @@ AC_CHECK_TYPES([char16_t, char32_t, key_serial_t], ]]) AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY, IFLA_MACVLAN_FLAGS, IFLA_IPVLAN_MODE, IFLA_VTI_REMOTE, diff --git a/src/basic/missing.h b/src/basic/missing.h index 8b977871e9..53dfa1c801 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -577,6 +577,9 @@ struct btrfs_ioctl_quota_ctl_args { #define IN6_ADDR_GEN_MODE_EUI64 0 #define IN6_ADDR_GEN_MODE_NONE 1 +#endif + +#if !HAVE_DECL_IN6_ADDR_GEN_MODE_STABLE_PRIVACY #define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 #endif -- cgit v1.2.3-54-g00ecf From bbc85a16e12083fdf13215c07a57ad7a5fb56ef8 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 14 Jun 2016 15:08:01 +0300 Subject: core: on unified we don't need to check u->pids: we can use proper notifications (#3531) Fixes: #3483 --- src/core/scope.c | 5 +++-- src/core/service.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/scope.c b/src/core/scope.c index 238f63a729..decd1a1f3f 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -428,8 +428,9 @@ static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_tidy_watch_pids(u, 0, 0); unit_watch_all_pids(u); - /* If the PID set is empty now, then let's finish this off */ - if (set_isempty(u->pids)) + /* If the PID set is empty now, then let's finish this off + (On unified we use proper notifications) */ + if (cg_unified() <= 0 && set_isempty(u->pids)) scope_notify_cgroup_empty_event(u); } diff --git a/src/core/service.c b/src/core/service.c index 7ebabca5d6..14da6a58a9 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2800,8 +2800,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_tidy_watch_pids(u, s->main_pid, s->control_pid); unit_watch_all_pids(u); - /* If the PID set is empty now, then let's finish this off */ - if (set_isempty(u->pids)) + /* If the PID set is empty now, then let's finish this off + (On unified we use proper notifications) */ + if (cg_unified() <= 0 && set_isempty(u->pids)) service_notify_cgroup_empty_event(u); } -- cgit v1.2.3-54-g00ecf From 4892084f096c19da0e83f28f250ca187b58c22b2 Mon Sep 17 00:00:00 2001 From: Lukáš Nykrýn Date: Tue, 14 Jun 2016 14:20:56 +0200 Subject: manager: reduce complexity of unit_gc_sweep (#3507) When unit is marked as UNSURE, we are trying to find if it state was changed over and over again. So lets not go through the UNSURE states again. Also when we find a GOOD unit lets propagate the GOOD state to all units that this unit reference. This is a problem on machines with a lot of initscripts with different starting priority, since those units will reference each other and the original algorithm might get to n! complexity. Thanks HATAYAMA Daisuke for the expand_good_state code. --- src/core/manager.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index ec8acdff5b..5c0fee935d 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -877,6 +877,19 @@ enum { _GC_OFFSET_MAX }; +static void unit_gc_mark_good(Unit *u, unsigned gc_marker) +{ + Iterator i; + Unit *other; + + u->gc_marker = gc_marker + GC_OFFSET_GOOD; + + /* Recursively mark referenced units as GOOD as well */ + SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) + if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) + unit_gc_mark_good(other, gc_marker); +} + static void unit_gc_sweep(Unit *u, unsigned gc_marker) { Iterator i; Unit *other; @@ -886,6 +899,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || u->gc_marker == gc_marker + GC_OFFSET_BAD || + u->gc_marker == gc_marker + GC_OFFSET_UNSURE || u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) return; @@ -926,7 +940,7 @@ bad: return; good: - u->gc_marker = gc_marker + GC_OFFSET_GOOD; + unit_gc_mark_good(u, gc_marker); } static unsigned manager_dispatch_gc_queue(Manager *m) { -- cgit v1.2.3-54-g00ecf From 1d7100298c2a696d99f6fbd6ab858762aeb51ac7 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 14 Jun 2016 22:41:57 +0530 Subject: networkd: Tunnel add support to configure key for VTI/VTI6 (#3532) fixes #3298 --- man/systemd.netdev.xml | 27 ++++++++++++ src/network/networkd-netdev-gperf.gperf | 3 ++ src/network/networkd-netdev-tunnel.c | 75 +++++++++++++++++++++++++++++++++ src/network/networkd-netdev-tunnel.h | 9 ++++ 4 files changed, 114 insertions(+) (limited to 'src') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index cde5d65949..3cc58ca854 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -638,6 +638,33 @@ + + Key= + + The Key= parameter specifies the same key to use in + both directions (InputKey= and OutputKey=). + The Key= is either a number or an IPv4 address-like dotted quad. + It is used as mark-configured SAD/SPD entry as part of the lookup key (both in data + and control path) in ip xfrm (framework used to implement IPsec protocol). + See + ip-xfrm - transform configuration for details. It is only used for VTI/VTI6 + tunnels. + + + + InputKey= + + The InputKey= parameter specifies the key to use for input. + The format is same as Key=. It is only used for VTI/VTI6 tunnels. + + + + OutputKey= + + The OutputKey= parameter specifies the key to use for output. + The format is same as Key=. It is only used for VTI/VTI6 tunnels. + + Mode= diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index a9512cd77b..bf93b0d9fa 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -42,6 +42,9 @@ Tunnel.Local, config_parse_tunnel_address, 0, Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote) Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos) Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl) +Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key) +Tunnel.InputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, ikey) +Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey) Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 7aaa041ba3..58dec36c9a 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -200,6 +200,33 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl return r; } +static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_message *m) { + Tunnel *t = VTI(netdev); + uint32_t ikey, okey; + int r; + + assert(link); + assert(m); + assert(t); + + if (t->key != 0) + ikey = okey = htobe32(t->key); + else { + ikey = htobe32(t->ikey); + okey = htobe32(t->okey); + } + + r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m"); + + r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m"); + + return 0; +} + static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { Tunnel *t = VTI(netdev); int r; @@ -214,6 +241,10 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -239,6 +270,10 @@ static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -413,6 +448,46 @@ int config_parse_tunnel_address(const char *unit, return 0; } +int config_parse_tunnel_key(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) { + union in_addr_union buffer; + Tunnel *t = userdata; + uint32_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_from_string(AF_INET, rvalue, &buffer); + if (r < 0) { + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue); + return 0; + } + } else + k = be32toh(buffer.in.s_addr); + + if (streq(lvalue, "Key")) + t->key = k; + else if (streq(lvalue, "InputKey")) + t->ikey = k; + else + t->okey = k; + + return 0; +} + int config_parse_ipv6_flowlabel(const char* unit, const char *filename, unsigned line, diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 7d31e7b687..32a46bd82f 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -49,6 +49,10 @@ typedef struct Tunnel { unsigned tos; unsigned flags; + uint32_t key; + uint32_t ikey; + uint32_t okey; + union in_addr_union local; union in_addr_union remote; @@ -108,3 +112,8 @@ int config_parse_encap_limit(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_tunnel_key(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); -- cgit v1.2.3-54-g00ecf From d9ab2bcf0591b496f1a4750c7ff790b33f9c7e59 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 18:56:20 +0200 Subject: util: when determining the amount of memory on this system, take cgroup limit into account When determining the amount of RAM in the system, let's make sure we also read the root-level cgroup memory limit into account. This isn't particularly useful on the host, but in containers it makes sure that whatever memory the container got assigned is actually used for RAM size calculations. --- src/basic/util.c | 35 +++++++++++++++++++++++++++++------ src/test/test-util.c | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/util.c b/src/basic/util.c index f2f92fb3b7..88d58cd94a 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -36,6 +36,7 @@ #include "alloc-util.h" #include "build.h" +#include "cgroup-util.h" #include "def.h" #include "dirent-util.h" #include "fd-util.h" @@ -771,15 +772,37 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int } uint64_t physical_memory(void) { - long mem; + _cleanup_free_ char *root = NULL, *value = NULL; + uint64_t mem, lim; + size_t ps; + long sc; - /* We return this as uint64_t in case we are running as 32bit - * process on a 64bit kernel with huge amounts of memory */ + /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of + * memory. + * + * In order to support containers nicely that have a configured memory limit we'll take the minimum of the + * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ + + sc = sysconf(_SC_PHYS_PAGES); + assert(sc > 0); + + ps = page_size(); + mem = (uint64_t) sc * (uint64_t) ps; + + if (cg_get_root_path(&root) < 0) + return mem; + + if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + return mem; + + if (safe_atou64(value, &lim) < 0) + return mem; - mem = sysconf(_SC_PHYS_PAGES); - assert(mem > 0); + /* Make sure the limit is a multiple of our own page size */ + lim /= ps; + lim *= ps; - return (uint64_t) mem * (uint64_t) page_size(); + return MIN(mem, lim); } int update_reboot_parameter_and_warn(const char *param) { diff --git a/src/test/test-util.c b/src/test/test-util.c index 9b6d2a7968..5b3fbcff53 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -26,6 +26,7 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "parse-util.h" #include "raw-clone.h" #include "rm-rf.h" #include "string-util.h" @@ -263,6 +264,18 @@ static void test_raw_clone(void) { } } +static void test_physical_memory(void) { + uint64_t p; + char buf[FORMAT_BYTES_MAX]; + + p = physical_memory(); + assert_se(p > 0); + assert_se(p < UINT64_MAX); + assert_se(p % page_size() == 0); + + log_info("Memory: %s", format_bytes(buf, sizeof(buf), p)); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -277,6 +290,7 @@ int main(int argc, char *argv[]) { test_log2i(); test_execute_directory(); test_raw_clone(); + test_physical_memory(); return 0; } -- cgit v1.2.3-54-g00ecf From 9184ca48ea43e009cd6f379f319926109a30926c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 19:25:38 +0200 Subject: util-lib: introduce parse_percent() for parsing percent specifications And port a couple of users over to it. --- src/basic/parse-util.c | 19 +++++++++++++++++++ src/basic/parse-util.h | 2 ++ src/core/load-fragment.c | 15 +++++---------- src/login/logind-user.c | 29 ++++++++--------------------- src/shared/bus-unit-util.c | 15 ++++++--------- src/test/test-parse-util.c | 19 +++++++++++++++++++ 6 files changed, 59 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 6c11b605a9..503a895731 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -532,3 +532,22 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } + +int parse_percent(const char *p) { + const char *pc, *n; + unsigned v; + int r; + + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + n = strndupa(p, pc - p); + r = safe_atou(n, &v); + if (r < 0) + return r; + if (v > 100) + return -ERANGE; + + return (int) v; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 7dc579a159..73441bb6fd 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -105,3 +105,5 @@ static inline int safe_atozu(const char *s, size_t *ret_u) { int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); + +int parse_percent(const char *p); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 17c72aed88..fe60bee789 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2774,7 +2774,7 @@ int config_parse_cpu_quota( void *userdata) { CGroupContext *c = data; - double percent; + int r; assert(filename); assert(lvalue); @@ -2785,18 +2785,13 @@ int config_parse_cpu_quota( return 0; } - if (!endswith(rvalue, "%")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); + r = parse_percent(rvalue); + if (r <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue); return 0; } - if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue); - return 0; - } - - c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100); - + c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U; return 0; } diff --git a/src/login/logind-user.c b/src/login/logind-user.c index a826321bf0..6d0904f5ca 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -843,7 +843,6 @@ int config_parse_tmpfs_size( void *userdata) { size_t *sz = data; - const char *e; int r; assert(filename); @@ -851,29 +850,17 @@ int config_parse_tmpfs_size( assert(rvalue); assert(data); - e = endswith(rvalue, "%"); - if (e) { - unsigned long ul; - char *f; - - errno = 0; - ul = strtoul(rvalue, &f, 10); - if (errno > 0 || f != e) { - log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue); - return 0; - } - - if (ul <= 0 || ul >= 100) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue); - return 0; - } - - *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100)); - } else { + /* First, try to parse as percentage */ + r = parse_percent(rvalue); + if (r > 0 && r < 100) + *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) r) / 100U)); + else { uint64_t k; + /* If the passed argument was not a percentage, or out of range, parse as byte size */ + r = parse_size(rvalue, 1024, &k); - if (r < 0 || (uint64_t) (size_t) k != k) { + if (r < 0 || k <= 0 || (uint64_t) (size_t) k != k) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8f4f93ee0c..778c79b3cf 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -83,18 +83,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (isempty(eq)) r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); - else if (endswith(eq, "%")) { - double percent; - - if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { - log_error("CPU quota '%s' invalid.", eq); + else { + r = parse_percent(eq); + if (r <= 0) { + log_error_errno(r, "CPU quota '%s' invalid.", eq); return -EINVAL; } - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100); - } else { - log_error("CPU quota needs to be in percent."); - return -EINVAL; + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U); } goto finish; @@ -110,6 +106,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen char *n; usec_t t; size_t l; + r = parse_sec(eq, &t); if (r < 0) return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 7d8677e17c..0a76308f72 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -475,6 +475,24 @@ static void test_safe_atod(void) { assert_se(*e == ','); } +static void test_parse_percent(void) { + assert_se(parse_percent("") == -EINVAL); + assert_se(parse_percent("foo") == -EINVAL); + assert_se(parse_percent("0") == -EINVAL); + assert_se(parse_percent("50") == -EINVAL); + assert_se(parse_percent("100") == -EINVAL); + assert_se(parse_percent("-1") == -EINVAL); + assert_se(parse_percent("0%") == 0); + assert_se(parse_percent("55%") == 55); + assert_se(parse_percent("100%") == 100); + assert_se(parse_percent("-7%") == -ERANGE); + assert_se(parse_percent("107%") == -ERANGE); + assert_se(parse_percent("%") == -EINVAL); + assert_se(parse_percent("%%") == -EINVAL); + assert_se(parse_percent("%1") == -EINVAL); + assert_se(parse_percent("1%%") == -EINVAL); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -488,6 +506,7 @@ int main(int argc, char *argv[]) { test_safe_atou16(); test_safe_atoi16(); test_safe_atod(); + test_parse_percent(); return 0; } -- cgit v1.2.3-54-g00ecf From 875ae5661a011b757f0eaa468dea6ba91cbe5437 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 19:36:09 +0200 Subject: core: optionally, accept a percentage value for MemoryLimit= and related settings If a percentage is used, it is taken relative to the installed RAM size. This should make it easier to write generic unit files that adapt to the local system. --- man/systemd.resource-control.xml | 36 +++++++++++++++++++----------------- src/core/load-fragment.c | 16 +++++++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index d4c8fa7091..0551d75026 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -228,9 +228,11 @@ reclaimed as long as memory can be reclaimed from unprotected units. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. This controls the - memory.low control group attribute. For details about this control group attribute, see - cgroup-v2.txt. + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the + system. This controls the memory.low control group attribute. For details about this + control group attribute, see cgroup-v2.txt. Implies MemoryAccounting=true. @@ -247,7 +249,9 @@ aggressively in such cases. This is the main mechanism to control memory usage of a unit. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the + system. If assigned the special value infinity, no memory limit is applied. This controls the memory.high control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -268,8 +272,9 @@ last line of defense. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value infinity, no memory limit is applied. This controls the + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the system. If + assigned the special value infinity, no memory limit is applied. This controls the memory.max control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -284,17 +289,14 @@ MemoryLimit=bytes - Specify the limit on maximum memory usage of the - executed processes. The limit specifies how much process and - kernel memory can be used by tasks in this unit. Takes a - memory size in bytes. If the value is suffixed with K, M, G - or T, the specified memory size is parsed as Kilobytes, - Megabytes, Gigabytes, or Terabytes (with the base 1024), - respectively. If assigned the special value - infinity, no memory limit is applied. This - controls the memory.limit_in_bytes - control group attribute. For details about this control - group attribute, see Specify the limit on maximum memory usage of the executed processes. The limit specifies how much + process and kernel memory can be used by tasks in this unit. Takes a memory size in bytes. If the value is + suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or + Terabytes (with the base 1024), respectively. Alternatively, a percentage value may be specified, which is + taken relative to the installed physical memory on the system. If assigned the special value + infinity, no memory limit is applied. This controls the + memory.limit_in_bytes control group attribute. For details about this control group + attribute, see memory.txt. Implies MemoryAccounting=true. diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index fe60bee789..05852cc7e3 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2812,9 +2812,19 @@ int config_parse_memory_limit( int r; if (!isempty(rvalue) && !streq(rvalue, "infinity")) { - r = parse_size(rvalue, 1024, &bytes); - if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + + r = parse_percent(rvalue); + if (r < 0) { + r = parse_size(rvalue, 1024, &bytes); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + } else + bytes = (((physical_memory() / page_size()) * (uint64_t) r) / 100) * page_size(); + + if (bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue); return 0; } } -- cgit v1.2.3-54-g00ecf From cd0a7a8e58cf7e9f273bf446bb50bf982a8cf29c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 20:04:22 +0200 Subject: core: when receiving a memory limit via the bus, refuse 0 When parsing unit files we already refuse unit memory limits of zero, let's also refuse it when the value is set via the bus. --- src/core/dbus-cgroup.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 8525fa1bf1..5b94b5e575 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -641,7 +641,7 @@ int bus_cgroup_set_property( return 1; - } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { + } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { const char *path; bool read = true; unsigned n = 0; @@ -835,6 +835,8 @@ int bus_cgroup_set_property( r = sd_bus_message_read(message, "t", &v); if (r < 0) return r; + if (v <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { if (streq(name, "MemoryLow")) @@ -860,6 +862,8 @@ int bus_cgroup_set_property( r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (limit <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { c->memory_limit = limit; -- cgit v1.2.3-54-g00ecf From 799ec13412e2f6649fd69ce4f1ca1674a40039b0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 20:05:14 +0200 Subject: core: make sure to use "infinity" in unit files, not "max" THe latter is a kernelism, we only understand "infinity". --- src/core/dbus-cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 5b94b5e575..fe035109e3 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -849,7 +849,7 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (v == CGROUP_LIMIT_MAX) - unit_write_drop_in_private_format(u, mode, name, "%s=max", name); + unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name); else unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v); } -- cgit v1.2.3-54-g00ecf From d8cf2ac79b524d7784bccb428295ebc9c5e8548c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 20:45:32 +0200 Subject: util: introduce physical_memory_scale() to unify how we scale by physical memory The various bits of code did the scaling all different, let's unify this, given that the code is not trivial. --- src/basic/util.c | 27 +++++++++++++++++++++++++++ src/basic/util.h | 1 + src/core/load-fragment.c | 2 +- src/login/logind-user.c | 2 +- src/login/logind.c | 2 +- src/test/test-util.c | 38 +++++++++++++++++++++++++++++++++++++- 6 files changed, 68 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/util.c b/src/basic/util.c index 88d58cd94a..09d16697b7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -805,6 +805,33 @@ uint64_t physical_memory(void) { return MIN(mem, lim); } +uint64_t physical_memory_scale(uint64_t v, uint64_t max) { + uint64_t p, m, ps, r; + + assert(max > 0); + + /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success + * the result is a multiple of the page size (rounds down). */ + + ps = page_size(); + assert(ps > 0); + + p = physical_memory() / ps; + assert(p > 0); + + m = p * v; + if (m / p != v) + return UINT64_MAX; + + m /= max; + + r = m * ps; + if (r / ps != m) + return UINT64_MAX; + + return r; +} + int update_reboot_parameter_and_warn(const char *param) { int r; diff --git a/src/basic/util.h b/src/basic/util.h index 9e6df19ef1..db105197e8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -184,6 +184,7 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); uint64_t physical_memory(void); +uint64_t physical_memory_scale(uint64_t v, uint64_t max); int update_reboot_parameter_and_warn(const char *param); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 05852cc7e3..58d7275a96 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2821,7 +2821,7 @@ int config_parse_memory_limit( return 0; } } else - bytes = (((physical_memory() / page_size()) * (uint64_t) r) / 100) * page_size(); + bytes = physical_memory_scale(r, 100U); if (bytes < 1) { log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 6d0904f5ca..de44d369cf 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -853,7 +853,7 @@ int config_parse_tmpfs_size( /* First, try to parse as percentage */ r = parse_percent(rvalue); if (r > 0 && r < 100) - *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) r) / 100U)); + *sz = physical_memory_scale(r, 100U); else { uint64_t k; diff --git a/src/login/logind.c b/src/login/logind.c index caf149cfb7..d01dd110ea 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -61,7 +61,7 @@ static void manager_reset_config(Manager *m) { m->idle_action_usec = 30 * USEC_PER_MINUTE; m->idle_action = HANDLE_IGNORE; - m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ + m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */ m->user_tasks_max = 12288; m->sessions_max = 8192; m->inhibitors_max = 8192; diff --git a/src/test/test-util.c b/src/test/test-util.c index 5b3fbcff53..e177612a9f 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -273,7 +273,42 @@ static void test_physical_memory(void) { assert_se(p < UINT64_MAX); assert_se(p % page_size() == 0); - log_info("Memory: %s", format_bytes(buf, sizeof(buf), p)); + log_info("Memory: %s (%" PRIu64 ")", format_bytes(buf, sizeof(buf), p), p); +} + +static void test_physical_memory_scale(void) { + uint64_t p; + + p = physical_memory(); + + assert_se(physical_memory_scale(0, 100) == 0); + assert_se(physical_memory_scale(100, 100) == p); + + log_info("Memory original: %" PRIu64, physical_memory()); + log_info("Memory scaled by 50%%: %" PRIu64, physical_memory_scale(50, 100)); + log_info("Memory divided by 2: %" PRIu64, physical_memory() / 2); + log_info("Page size: %zu", page_size()); + + /* There might be an uneven number of pages, hence permit these calculations to be half a page off... */ + assert_se(page_size()/2 + physical_memory_scale(50, 100) - p/2 <= page_size()); + assert_se(physical_memory_scale(200, 100) == p*2); + + assert_se(physical_memory_scale(0, 1) == 0); + assert_se(physical_memory_scale(1, 1) == p); + assert_se(physical_memory_scale(2, 1) == p*2); + + assert_se(physical_memory_scale(0, 2) == 0); + + assert_se(page_size()/2 + physical_memory_scale(1, 2) - p/2 <= page_size()); + assert_se(physical_memory_scale(2, 2) == p); + assert_se(physical_memory_scale(4, 2) == p*2); + + assert_se(physical_memory_scale(0, UINT32_MAX) == 0); + assert_se(physical_memory_scale(UINT32_MAX, UINT32_MAX) == p); + + /* overflow */ + assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); + } int main(int argc, char *argv[]) { @@ -291,6 +326,7 @@ int main(int argc, char *argv[]) { test_execute_directory(); test_raw_clone(); test_physical_memory(); + test_physical_memory_scale(); return 0; } -- cgit v1.2.3-54-g00ecf From d58d600efdcbefa38247861a1df032d1a8fda606 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 20:52:06 +0200 Subject: systemctl: allow percent-based MemoryLimit= settings via systemctl set-property The unit files already accept relative, percent-based memory limit specification, let's make sure "systemctl set-property" support this too. Since we want the physical memory size of the destination machine to apply we pass the percentage in a new set of properties that only exist for this purpose, and can only be set. --- src/core/dbus-cgroup.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/bus-unit-util.c | 43 +++++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index fe035109e3..27bbe2d26d 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -856,6 +856,38 @@ int bus_cgroup_set_property( return 1; + } else if (STR_IN_SET(name, "MemoryLowByPhysicalMemory", "MemoryHighByPhysicalMemory", "MemoryMaxByPhysicalMemory")) { + uint32_t raw; + uint64_t v; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + v = physical_memory_scale(raw, UINT32_MAX); + if (v <= 0 || v == UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + const char *e; + + /* Chop off suffix */ + assert_se(e = endswith(name, "ByPhysicalMemory")); + name = strndupa(name, e - name); + + if (streq(name, "MemoryLow")) + c->memory_low = v; + else if (streq(name, "MemoryHigh")) + c->memory_high = v; + else + c->memory_max = v; + + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + } + + return 1; + } else if (streq(name, "MemoryLimit")) { uint64_t limit; @@ -877,6 +909,26 @@ int bus_cgroup_set_property( return 1; + } else if (streq(name, "MemoryLimitByPhysicalMemory")) { + uint64_t limit; + uint32_t raw; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + limit = physical_memory_scale(raw, UINT32_MAX); + if (limit <= 0 || limit == UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + c->memory_limit = limit; + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + } + + return 1; + } else if (streq(name, "DevicePolicy")) { const char *policy; CGroupDevicePolicy p; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 778c79b3cf..6fc201b885 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -120,6 +120,34 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen strcpy(mempcpy(n, field, l - 3), "USec"); r = sd_bus_message_append(m, "sv", n, "t", t); goto finish; + + } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { + uint64_t bytes; + + if (isempty(eq) || streq(eq, "infinity")) + bytes = CGROUP_LIMIT_MAX; + else { + r = parse_percent(eq); + if (r >= 0) { + char *n; + + /* When this is a percentage we'll convert this into a relative value in the range + * 0…UINT32_MAX and pass it in the MemoryLowByPhysicalMemory property (and related + * ones). This way the physical memory size can be determined server-side */ + + n = strjoina(field, "ByPhysicalMemory"); + r = sd_bus_message_append(m, "sv", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); + goto finish; + + } else { + r = parse_size(eq, 1024, &bytes); + if (r < 0) + return log_error_errno(r, "Failed to parse bytes specification %s", assignment); + } + } + + r = sd_bus_message_append(m, "sv", field, "t", bytes); + goto finish; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -163,21 +191,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { - uint64_t bytes; - - if (isempty(eq) || streq(eq, "infinity")) - bytes = CGROUP_LIMIT_MAX; - else { - r = parse_size(eq, 1024, &bytes); - if (r < 0) { - log_error("Failed to parse bytes specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", bytes); - } else if (streq(field, "TasksMax")) { uint64_t n; -- cgit v1.2.3-54-g00ecf From a48072b7032997458c2d3e736a27193633639926 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 19:49:48 +0200 Subject: sd-ndisc: add missing cast Apparently newer gcc versions are a bit more forgiving when assigning an "unsigned char*" pointer to something of a different type. Let's add the missing cast so that old gcc versions are fine, too. --- src/libsystemd-network/sd-ndisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index ea3fe369ce..07b0d7f704 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -307,7 +307,7 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) - triple_timestamp_from_realtime(&rt->timestamp, timeval_load(CMSG_DATA(cmsg))); + triple_timestamp_from_realtime(&rt->timestamp, timeval_load((struct timeval*) CMSG_DATA(cmsg))); } if (!triple_timestamp_is_set(&rt->timestamp)) -- cgit v1.2.3-54-g00ecf From 3f71dec5d7210e3b21e79bde446fc2ba003486f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jun 2016 19:53:45 +0200 Subject: unit: properly comment generated comments in unit files Fix-up for 2a9a6f8ac04a69ca36d645f9305a33645f22a22b --- src/core/unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index e98086a3f6..581962eba6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3375,7 +3375,7 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co return -EINVAL; wrapped = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\"\n" - "or an equivalent operation. Do not edit.\n", + "# or an equivalent operation. Do not edit.\n", data, "\n"); -- cgit v1.2.3-54-g00ecf From 19a29798bc44b377513c9e31eaf70b5ef520d54e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 14 Jun 2016 17:05:42 -0400 Subject: udevadm: trivial simplification --- src/udev/udevadm-info.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 66b51c1209..6753c52005 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -433,17 +433,13 @@ static int uinfo(struct udev *udev, int argc, char *argv[]) { case QUERY_PROPERTY: list_entry = udev_device_get_properties_list_entry(device); while (list_entry != NULL) { - if (export) { - const char *prefix = export_prefix; - - if (prefix == NULL) - prefix = ""; - printf("%s%s='%s'\n", prefix, + if (export) + printf("%s%s='%s'\n", strempty(export_prefix), udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - } else { + else printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - } + list_entry = udev_list_entry_get_next(list_entry); } break; -- cgit v1.2.3-54-g00ecf From 145fab1eaef581ecfe353f1dc7da9fd7779f365a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 23:27:30 +0200 Subject: resolve: port resolve tool to in_addr_ifindex_{from_string_auto|to_string}() We can reuse some code here, so let's do it. --- src/resolve/resolve-tool.c | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index bc6dcf04a4..2cb2e42b23 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -199,7 +199,7 @@ static int resolve_host(sd_bus *bus, const char *name) { if (ifindex > 0 && !if_indextoname(ifindex, ifname)) log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - r = in_addr_to_string(family, a, &pretty); + r = in_addr_ifindex_to_string(family, a, ifindex, &pretty); if (r < 0) return log_error_errno(r, "Failed to print address for %s: %m", name); @@ -253,7 +253,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a if (ifindex <= 0) ifindex = arg_ifindex; - r = in_addr_to_string(family, address, &pretty); + r = in_addr_ifindex_to_string(family, address, ifindex, &pretty); if (r < 0) return log_oom(); @@ -345,31 +345,6 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a return 0; } -static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) { - const char *percent, *a; - int ifi = 0; - int r; - - percent = strchr(s, '%'); - if (percent) { - if (parse_ifindex(percent+1, &ifi) < 0) { - ifi = if_nametoindex(percent+1); - if (ifi <= 0) - return -EINVAL; - } - - a = strndupa(s, percent - s); - } else - a = s; - - r = in_addr_from_string_auto(a, family, address); - if (r < 0) - return r; - - *ifindex = ifi; - return 0; -} - static int output_rr_packet(const void *d, size_t l, int ifindex) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; @@ -1392,7 +1367,7 @@ int main(int argc, char **argv) { if (startswith(argv[optind], "dns:")) k = resolve_rfc4501(bus, argv[optind]); else { - k = parse_address(argv[optind], &family, &a, &ifindex); + k = in_addr_ifindex_from_string_auto(argv[optind], &family, &a, &ifindex); if (k >= 0) k = resolve_address(bus, family, &a, ifindex); else -- cgit v1.2.3-54-g00ecf From 97ebebbc9c229cb7ac46e5c27228c9e2478c56bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 23:28:54 +0200 Subject: resolved: make sure we initialize the ifindex of direct zone answers properly Previously, after checking the local zone for a reply and finding one we'd not initialize the answer ifindex from that. Let's fix that. --- src/resolve/resolved-dns-answer.c | 4 ++-- src/resolve/resolved-dns-answer.h | 2 +- src/resolve/resolved-dns-scope.c | 11 ++++++++++- src/resolve/resolved-dns-scope.h | 2 ++ src/resolve/resolved-dns-transaction.c | 17 ++++++----------- src/resolve/resolved-dns-zone.c | 13 ++++++++----- src/resolve/resolved-dns-zone.h | 2 +- 7 files changed, 30 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 0dadf8b1dd..13dcba8421 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -185,7 +185,7 @@ int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, Dns return dns_answer_add(*a, rr, ifindex, flags); } -int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { +int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL; soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name); @@ -208,7 +208,7 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { soa->soa.expire = 1; soa->soa.minimum = ttl; - return dns_answer_add(a, soa, 0, DNS_ANSWER_AUTHENTICATED); + return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED); } int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) { diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 0679c610f5..b2b86d1772 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -56,7 +56,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a); int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); -int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl); +int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex); int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags); int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *combined_flags); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 6a69d7b7c2..9d484d0a48 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -721,7 +721,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { assert(p->question->n_keys == 1); key = p->question->keys[0]; - r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative); + r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative); if (r < 0) { log_debug_errno(r, "Failed to lookup key: %m"); return; @@ -1029,3 +1029,12 @@ bool dns_scope_network_good(DnsScope *s) { return manager_routable(s->manager, AF_UNSPEC); } + +int dns_scope_ifindex(DnsScope *s) { + assert(s); + + if (s->link) + return s->link->ifindex; + + return 0; +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 291e5817d0..538bc61f81 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -107,3 +107,5 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); bool dns_scope_network_good(DnsScope *s); + +int dns_scope_ifindex(DnsScope *s); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index a4a67623e7..ed18df35cb 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -557,8 +557,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { /* The interface index is difficult to determine if we are * connecting to the local host, hence fill this in right away * instead of determining it from the socket */ - if (t->scope->link) - t->stream->ifindex = t->scope->link->ifindex; + t->stream->ifindex = dns_scope_ifindex(t->scope); dns_transaction_reset_answer(t); @@ -798,12 +797,9 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { switch (t->scope->protocol) { case DNS_PROTOCOL_LLMNR: - assert(t->scope->link); + /* For LLMNR we will not accept any packets from other interfaces */ - /* For LLMNR we will not accept any packets from other - * interfaces */ - - if (p->ifindex != t->scope->link->ifindex) + if (p->ifindex != dns_scope_ifindex(t->scope)) return; if (p->family != t->scope->family) @@ -820,10 +816,9 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { break; case DNS_PROTOCOL_MDNS: - assert(t->scope->link); - /* For mDNS we will not accept any packets from other interfaces */ - if (p->ifindex != t->scope->link->ifindex) + + if (p->ifindex != dns_scope_ifindex(t->scope)) return; if (p->family != t->scope->family) @@ -1246,7 +1241,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { * for probing or verifying a zone item. */ if (set_isempty(t->notify_zone_items)) { - r = dns_zone_lookup(&t->scope->zone, t->key, &t->answer, NULL, NULL); + r = dns_zone_lookup(&t->scope->zone, t->key, dns_scope_ifindex(t->scope), &t->answer, NULL, NULL); if (r < 0) return r; if (r > 0) { diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 850eed8cb8..746a979f47 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -287,13 +287,16 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) { return 0; } -int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; unsigned n_answer = 0; DnsZoneItem *j, *first; bool tentative = true, need_soa = false; int r; + /* Note that we don't actually need the ifindex for anything. However when it is passed we'll initialize the + * ifindex field in the answer with it */ + assert(z); assert(key); assert(ret_answer); @@ -389,7 +392,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns if (k < 0) return k; if (k > 0) { - r = dns_answer_add(answer, j->rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(answer, j->rr, ifindex, DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; @@ -398,7 +401,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (found && !added) { - r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex); if (r < 0) return r; } @@ -415,7 +418,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns if (j->state != DNS_ZONE_ITEM_PROBING) tentative = false; - r = dns_answer_add(answer, j->rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(answer, j->rr, ifindex, DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -435,7 +438,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (add_soa) { - r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex); if (r < 0) return r; } diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index 408833c359..a41df37e6b 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -65,7 +65,7 @@ void dns_zone_flush(DnsZone *z); int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe); void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr); -int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); void dns_zone_item_conflict(DnsZoneItem *i); void dns_zone_item_notify(DnsZoneItem *i); -- cgit v1.2.3-54-g00ecf From 94831eaeec479b5f32e7941b355857dd95a58b51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 23:37:16 +0200 Subject: resolved: in the ResolveHostname() bus call, accept IP addresses with scope When we get a literal IP address as string that includes a zone suffix, process this properly and return the parsed ifindex back to the client, and include it in the canonical name in case of a link-local IP address. --- src/resolve/resolved-bus.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6d86cbf123..f08c6c0637 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -245,17 +245,22 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *canonical = NULL; union in_addr_union parsed; - int r, ff; + int r, ff, parsed_ifindex = 0; /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it, * let's not attempt to look it up. */ - r = in_addr_from_string_auto(hostname, &ff, &parsed); + r = in_addr_ifindex_from_string_auto(hostname, &ff, &parsed, &parsed_ifindex); if (r < 0) /* not an address */ return 0; if (family != AF_UNSPEC && ff != family) return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family."); + if (ifindex > 0 && parsed_ifindex > 0 && parsed_ifindex != ifindex) + return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address interface index does not match requested interface."); + + if (parsed_ifindex > 0) + ifindex = parsed_ifindex; r = sd_bus_message_new_method_return(m, &reply); if (r < 0) @@ -288,7 +293,7 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner * omissions are always done the same way). */ - r = in_addr_to_string(ff, &parsed, &canonical); + r = in_addr_ifindex_to_string(ff, &parsed, ifindex, &canonical); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 69281c49eb824b2cc854fdb5b97f134b1371be8d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 23:52:29 +0200 Subject: util-lib: rework get_process_cmdline() (#3529) This reworks get_process_cmdline() quite substantially, fixing the following: - Fixes: https://github.com/systemd/systemd/pull/3512/commits/a4e3bf4d7ac2de51191ce136ee9361ba319e106c#r66837630 - The passed max_length is also applied to the "comm" name, if comm_fallback is set. - The right thing happens if max_length == 1 is specified - when the cmdline "foobar" is abbreviated to 6 characters the result is not "foobar" instead of "foo...". - trailing whitespace are removed before the ... suffix is appended. The 7 character abbreviation of "foo barz" is hence "foo..." instead of "foo ...". - leading whitespace are suppressed from the cmdline - a comprehensive test case is added --- src/basic/process-util.c | 90 +++++++++++++++++--- src/test/test-process-util.c | 192 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 08fa98bb9e..b5b068ad38 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -110,6 +110,15 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * assert(line); assert(pid >= 0); + /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing + * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most + * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If + * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a + * command line that resolves to the empty string will return the "comm" name of the process instead. + * + * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and + * comm_fallback is false). */ + p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); @@ -119,12 +128,22 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } - if (max_length == 0) { + if (max_length == 1) { + + /* If there's only room for one byte, return the empty string */ + r = new0(char, 1); + if (!r) + return -ENOMEM; + + *line = r; + return 0; + + } else if (max_length == 0) { size_t len = 0, allocated = 0; while ((c = getc(f)) != EOF) { - if (!GREEDY_REALLOC(r, allocated, len+2)) { + if (!GREEDY_REALLOC(r, allocated, len+3)) { free(r); return -ENOMEM; } @@ -136,7 +155,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } r[len++] = c; - } else + } else if (len > 0) space = true; } @@ -144,6 +163,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * r[len] = 0; } else { + bool dotdotdot = false; size_t left; r = new(char, max_length); @@ -155,28 +175,46 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * while ((c = getc(f)) != EOF) { if (isprint(c)) { + if (space) { - if (left <= 4) + if (left <= 2) { + dotdotdot = true; break; + } *(k++) = ' '; left--; space = false; } - if (left <= 4) + if (left <= 1) { + dotdotdot = true; break; + } *(k++) = (char) c; left--; - } else + } else if (k > r) space = true; } - if (left <= 4) { - size_t n = MIN(left-1, 3U); - memcpy(k, "...", n); - k[n] = 0; + if (dotdotdot) { + if (max_length <= 4) { + k = r; + left = max_length; + } else { + k = r + max_length - 4; + left = 4; + + /* Eat up final spaces */ + while (k > r && isspace(k[-1])) { + k--; + left++; + } + } + + strncpy(k, "...", left-1); + k[left] = 0; } else *k = 0; } @@ -195,7 +233,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (h < 0) return h; - r = strjoin("[", t, "]", NULL); + if (max_length == 0) + r = strjoin("[", t, "]", NULL); + else { + size_t l; + + l = strlen(t); + + if (l + 3 <= max_length) + r = strjoin("[", t, "]", NULL); + else if (max_length <= 6) { + + r = new(char, max_length); + if (!r) + return -ENOMEM; + + memcpy(r, "[...]", max_length-1); + r[max_length-1] = 0; + } else { + char *e; + + t[max_length - 6] = 0; + + /* Chop off final spaces */ + e = strchr(t, 0); + while (e > t && isspace(e[-1])) + e--; + *e = 0; + + r = strjoin("[", t, "...]", NULL); + } + } if (!r) return -ENOMEM; } diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 8bb5f6e3a3..af2c9282d4 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,7 +18,10 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include #include #include #include @@ -26,6 +29,7 @@ #include "alloc-util.h" #include "architecture.h" +#include "fd-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" @@ -59,7 +63,11 @@ static void test_get_process_comm(pid_t pid) { log_info("PID"PID_FMT" cmdline: '%s'", pid, c); assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); - log_info("PID"PID_FMT" cmdline truncated: '%s'", pid, d); + log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d); + + free(d); + assert_se(get_process_cmdline(pid, 1, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); assert_se(get_process_ppid(pid, &e) >= 0); log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); @@ -147,6 +155,187 @@ static void test_personality(void) { #endif } +static void test_get_process_cmdline_harder(void) { + char path[] = "/tmp/test-cmdlineXXXXXX"; + _cleanup_close_ int fd = -1; + _cleanup_free_ char *line = NULL; + pid_t pid; + + if (geteuid() != 0) + return; + + pid = fork(); + if (pid > 0) { + siginfo_t si; + + (void) wait_for_terminate(pid, &si); + + assert_se(si.si_code == CLD_EXITED); + assert_se(si.si_status == 0); + + return; + } + + assert_se(pid == 0); + assert_se(unshare(CLONE_NEWNS) >= 0); + + fd = mkostemp(path, O_CLOEXEC); + assert_se(fd >= 0); + assert_se(mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) >= 0); + assert_se(unlink(path) >= 0); + + assert_se(prctl(PR_SET_NAME, "testa") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, "[")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "[.")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "[..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "[...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "[...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "[t...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(write(fd, "quux", 4) == 4); + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, ".")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "f...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "fo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0); + assert_se(streq(line, "foo b...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "foo ba...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(ftruncate(fd, 0) >= 0); + assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[aaaa bbbb cccc]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "[aaaa b...]")); + line = mfree(line); + + safe_close(fd); + _exit(0); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -164,6 +353,7 @@ int main(int argc, char *argv[]) { test_pid_is_unwaited(); test_pid_is_alive(); test_personality(); + test_get_process_cmdline_harder(); return 0; } -- cgit v1.2.3-54-g00ecf From 8e38570ebed346c00e58c3fcc998a4b305e83a36 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 01:26:01 +0200 Subject: tree-wide: htonl() is weird, let's use htobe32() instead (#3538) Super-important change, yeah! --- CODING_STYLE | 7 +++++++ coccinelle/htonl.cocci | 20 ++++++++++++++++++++ src/basic/socket-util.c | 22 ++++++++++------------ src/core/socket.c | 16 ++++++++-------- src/libsystemd-network/arp-util.c | 10 +++++----- src/libsystemd-network/dhcp-network.c | 4 ++-- src/libsystemd-network/lldp-network.c | 3 ++- src/libsystemd-network/sd-dhcp-server.c | 2 +- src/libsystemd/sd-daemon/sd-daemon.c | 4 ++-- src/libudev/libudev-monitor.c | 14 +++++++------- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-netdev-tunnel.c | 4 ++-- src/nss-myhostname/nss-myhostname.c | 10 +++++----- src/test/test-nss.c | 4 ++-- src/test/test-socket-util.c | 8 ++++---- 15 files changed, 78 insertions(+), 52 deletions(-) create mode 100644 coccinelle/htonl.cocci (limited to 'src') diff --git a/CODING_STYLE b/CODING_STYLE index e762d42edb..f31d76f8ce 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -399,3 +399,10 @@ least initially), but it needs to be there. This is particularly important for objects that unprivileged users may allocate, but also matters for everything else any user may allocated. + +- htonl()/ntohl() and htons()/ntohs() are weird. Please use htobe32() and + htobe16() instead, it's much more descriptive, and actually says what really + is happening, after all htonl() and htons() don't operation on longs and + shorts as their name would suggest, but on uint32_t and uint16_t. Also, + "network byte order" is just a weird name for "big endian", hence we might + want to call it "big endian" right-away. diff --git a/coccinelle/htonl.cocci b/coccinelle/htonl.cocci new file mode 100644 index 0000000000..4e69bb7090 --- /dev/null +++ b/coccinelle/htonl.cocci @@ -0,0 +1,20 @@ +@@ +expression s; +@@ +- htonl(s) ++ htobe32(s) +@@ +expression s; +@@ +- htons(s) ++ htobe16(s) +@@ +expression s; +@@ +- ntohl(s) ++ be32toh(s) +@@ +expression s; +@@ +- ntohs(s) ++ be16toh(s) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c8769a54f4..2aa4daca49 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -85,7 +85,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in6); } else if (*s == '/') { @@ -133,7 +133,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r > 0) { /* Gotcha, it's a traditional IPv4 address */ a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in); } else { unsigned idx; @@ -147,7 +147,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); @@ -164,12 +164,12 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (socket_ipv6_is_supported()) { a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } else { a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; a->size = sizeof(struct sockaddr_in); } @@ -488,9 +488,7 @@ int sockaddr_port(const struct sockaddr *_sa) { if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - return ntohs(sa->sa.sa_family == AF_INET6 ? - sa->in6.sin6_port : - sa->in.sin_port); + return be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port); } int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { @@ -506,13 +504,13 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ case AF_INET: { uint32_t a; - a = ntohl(sa->in.sin_addr.s_addr); + a = be32toh(sa->in.sin_addr.s_addr); if (include_port) r = asprintf(&p, "%u.%u.%u.%u:%u", a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(sa->in.sin_port)); + be16toh(sa->in.sin_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -534,7 +532,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "%u.%u.%u.%u:%u", a[0], a[1], a[2], a[3], - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -550,7 +548,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "[%s]:%u", a, - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); if (r < 0) return -ENOMEM; } else { diff --git a/src/core/socket.c b/src/core/socket.c index f6204d04bf..e098055885 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -730,16 +730,16 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { case AF_INET: { uint32_t - a = ntohl(local.in.sin_addr.s_addr), - b = ntohl(remote.in.sin_addr.s_addr); + a = be32toh(local.in.sin_addr.s_addr), + b = be32toh(remote.in.sin_addr.s_addr); if (asprintf(&r, "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", nr, a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(local.in.sin_port), + be16toh(local.in.sin_port), b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF, - ntohs(remote.in.sin_port)) < 0) + be16toh(remote.in.sin_port)) < 0) return -ENOMEM; break; @@ -760,9 +760,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", nr, a[0], a[1], a[2], a[3], - ntohs(local.in6.sin6_port), + be16toh(local.in6.sin6_port), b[0], b[1], b[2], b[3], - ntohs(remote.in6.sin6_port)) < 0) + be16toh(remote.in6.sin6_port)) < 0) return -ENOMEM; } else { char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN]; @@ -771,9 +771,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { "%u-%s:%u-%s:%u", nr, inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)), - ntohs(local.in6.sin6_port), + be16toh(local.in6.sin6_port), inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)), - ntohs(remote.in6.sin6_port)) < 0) + be16toh(remote.in6.sin6_port)) < 0) return -ENOMEM; } diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c index 4660c7ea09..02028bf28a 100644 --- a/src/libsystemd-network/arp-util.c +++ b/src/libsystemd-network/arp-util.c @@ -79,7 +79,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ }; union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, @@ -112,17 +112,17 @@ static int arp_send_packet(int fd, int ifindex, bool announce) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; struct ether_arp arp = { - .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */ - .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */ + .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */ + .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ - .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */ + .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */ }; int r; diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index fac25e0fa2..a9f5a0a5de 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -107,9 +107,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, return -errno; link->ll.sll_family = AF_PACKET; - link->ll.sll_protocol = htons(ETH_P_IP); + link->ll.sll_protocol = htobe16(ETH_P_IP); link->ll.sll_ifindex = ifindex; - link->ll.sll_hatype = htons(arp_type); + link->ll.sll_hatype = htobe16(arp_type); link->ll.sll_halen = mac_addr_len; memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index f031760351..59c25598e9 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -57,7 +57,8 @@ int lldp_network_bind_raw_socket(int ifindex) { assert(ifindex > 0); - fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP)); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, + htobe16(ETHERTYPE_LLDP)); if (fd < 0) return -errno; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index ea4f03df1d..11ee2e252e 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -260,7 +260,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket *packet, size_t len) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_IP), + .ll.sll_protocol = htobe16(ETH_P_IP), .ll.sll_ifindex = server->ifindex, .ll.sll_halen = ETH_ALEN, }; diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 4da9dbfd63..b20a7ebb4c 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -310,12 +310,12 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint if (l < sizeof(struct sockaddr_in)) return -EINVAL; - return htons(port) == sockaddr.in.sin_port; + return htobe16(port) == sockaddr.in.sin_port; } else { if (l < sizeof(struct sockaddr_in6)) return -EINVAL; - return htons(port) == sockaddr.in6.sin6_port; + return htobe16(port) == sockaddr.in6.sin6_port; } } diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index f870eba9eb..1f9d16c450 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -650,9 +650,9 @@ retry: if (memcmp(buf.raw, "libudev", 8) == 0) { /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { + if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) { log_debug("unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); + buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC)); return NULL; } if (buf.nlh.properties_off+32 > (size_t)buflen) { @@ -715,7 +715,7 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, ssize_t blen, count; struct udev_monitor_netlink_header nlh = { .prefix = "libudev", - .magic = htonl(UDEV_MONITOR_MAGIC), + .magic = htobe32(UDEV_MONITOR_MAGIC), .header_size = sizeof nlh, }; struct iovec iov[2] = { @@ -736,19 +736,19 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, /* fill in versioned header */ val = udev_device_get_subsystem(udev_device); - nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); + nlh.filter_subsystem_hash = htobe32(util_string_hash32(val)); val = udev_device_get_devtype(udev_device); if (val != NULL) - nlh.filter_devtype_hash = htonl(util_string_hash32(val)); + nlh.filter_devtype_hash = htobe32(util_string_hash32(val)); /* add tag bloom filter */ tag_bloom_bits = 0; udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); + nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff); } /* add properties list */ diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 735c231a4c..2d81311e81 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -138,7 +138,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { ll_addr->family = AF_INET; ll_addr->in_addr.in = address; ll_addr->prefixlen = 16; - ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); + ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); ll_addr->scope = RT_SCOPE_LINK; r = address_configure(ll_addr, link, ipv4ll_address_handler, false); diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 58dec36c9a..77a4734df8 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -35,7 +35,7 @@ #include "util.h" #define DEFAULT_TNL_HOP_LIMIT 64 -#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) +#define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF) static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = { [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6", @@ -519,7 +519,7 @@ int config_parse_ipv6_flowlabel(const char* unit, if (k > 0xFFFFF) log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); else { - *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; + *ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL; t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 2b83d127b7..9a6e157e12 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -38,7 +38,7 @@ * IPv6 we use ::1 which unfortunately will not translate back to the * hostname but instead something like "localhost" or so. */ -#define LOCALADDRESS_IPV4 (htonl(0x7F000002)) +#define LOCALADDRESS_IPV4 (htobe32(0x7F000002)) #define LOCALADDRESS_IPV6 &in6addr_loopback NSS_GETHOSTBYNAME_PROTOTYPES(myhostname); @@ -75,7 +75,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( * is optional */ canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); } else if (is_gateway_hostname(name)) { @@ -348,7 +348,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r( if (is_localhost(name)) { canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); } else if (is_gateway_hostname(name)) { @@ -437,9 +437,9 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) goto found; - if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) { + if ((*(uint32_t*) addr) == htobe32(INADDR_LOOPBACK)) { canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); goto found; } diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 55af592287..c43bda5917 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -400,8 +400,8 @@ int main(int argc, char **argv) { _cleanup_free_ char *dir = NULL, *hostname = NULL; const char *module; - const uint32_t local_address_ipv4 = htonl(0x7F000001); - const uint32_t local_address_ipv4_2 = htonl(0x7F000002); + const uint32_t local_address_ipv4 = htobe32(0x7F000001); + const uint32_t local_address_ipv4_2 = htobe32(0x7F000002); _cleanup_free_ struct local_address *addresses = NULL; int n_addresses; diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 1a439bd0d4..1f853a7f16 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -353,7 +353,7 @@ static void test_nameinfo_pretty(void) { union sockaddr_union s = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; int r; @@ -391,17 +391,17 @@ static void test_sockaddr_equal(void) { union sockaddr_union a = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union b = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union c = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(1234), + .in.sin_addr.s_addr = htobe32(1234), }; union sockaddr_union d = { .in6.sin6_family = AF_INET6, -- cgit v1.2.3-54-g00ecf From 77d4acf332abd24025f31455f492fa83d97cb2e1 Mon Sep 17 00:00:00 2001 From: Kai Ruhnau Date: Wed, 15 Jun 2016 12:33:24 +0200 Subject: socket-util: Run the fallback when the kernel complains about the null buffer (#3541) Calling recv with a NULL buffer returns EFAULT instead of EOPNOTSUPP on older kernels (3.14). Fixes #3407 Signed-off-by: Kai Ruhnau --- src/basic/socket-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 2aa4daca49..385c3e4df3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -986,7 +986,7 @@ ssize_t next_datagram_size_fd(int fd) { l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC); if (l < 0) { - if (errno == EOPNOTSUPP) + if (errno == EOPNOTSUPP || errno == EFAULT) goto fallback; return -errno; -- cgit v1.2.3-54-g00ecf From 193edd61c30fab64662578f25d8cb9122c89c672 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 Jun 2016 08:21:15 -0400 Subject: systemctl: do not open pager twice Second attempt had no effect anyway. --- src/systemctl/systemctl.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index feb93cad8e..862eb17082 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4872,7 +4872,6 @@ static int show(int argc, char *argv[], void *userdata) { if (show_status && argc <= 1) { - pager_open(arg_no_pager, false); show_system_status(bus); new_line = true; -- cgit v1.2.3-54-g00ecf From 33d52725f5e90f278fec675a8c34e3accaa6ad97 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 Jun 2016 10:03:33 -0400 Subject: systemctl: also fall back to ListUnitsFiltered on access denied When running systemctl from git on systemd from systemd-229-8.fc24.x86_64, ListUnitsByPatterns results in org.freedesktop.DBus.Error.AccessDenied. --- src/systemctl/systemctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 862eb17082..ecd875fa2d 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -588,7 +588,8 @@ static int get_unit_list( return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { + if (r < 0 && (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || + sd_bus_error_has_name(&error, SD_BUS_ERROR_ACCESS_DENIED))) { /* Fallback to legacy ListUnitsFiltered method */ fallback = true; log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r)); -- cgit v1.2.3-54-g00ecf From fd1f9c89f72ebbe5d071cccf7754299fc87b9b26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 16:50:35 +0200 Subject: execute: minor coding style improvements --- src/core/execute.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index c20650626c..b5a5997f15 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -289,7 +289,15 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { return r; } -static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) { +static int connect_logger_as( + const ExecContext *context, + ExecOutput output, + const char *ident, + const char *unit_id, + int nfd, + uid_t uid, + gid_t gid) { + int fd, r; assert(context); @@ -310,7 +318,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons return -errno; } - fd_inc_sndbuf(fd, SNDBUF_SIZE); + (void) fd_inc_sndbuf(fd, SNDBUF_SIZE); dprintf(fd, "%s\n" @@ -328,11 +336,11 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE, is_terminal_output(output)); - if (fd != nfd) { - r = dup2(fd, nfd) < 0 ? -errno : nfd; - safe_close(fd); - } else - r = nfd; + if (fd == nfd) + return nfd; + + r = dup2(fd, nfd) < 0 ? -errno : nfd; + safe_close(fd); return r; } -- cgit v1.2.3-54-g00ecf From 7bce046bcf076e9cb359f1c78951b879430edb9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 16:50:45 +0200 Subject: core: set $JOURNAL_STREAM to the dev_t/ino_t of the journal stream of executed services This permits services to detect whether their stdout/stderr is connected to the journal, and if so talk to the journal directly, thus permitting carrying of metadata. As requested by the gtk folks: #2473 --- configure.ac | 1 + man/systemd.exec.xml | 20 +++++++++++++++++++ src/basic/formats-util.h | 16 ++++++++++++++++ src/core/execute.c | 50 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 80 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/configure.ac b/configure.ac index ffc6eedcdd..7fd78bfb60 100644 --- a/configure.ac +++ b/configure.ac @@ -249,6 +249,7 @@ AC_CHECK_SIZEOF(uid_t) AC_CHECK_SIZEOF(gid_t) AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(dev_t) +AC_CHECK_SIZEOF(ino_t) AC_CHECK_SIZEOF(rlim_t,,[ #include #include diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index a39e800854..dbfc7692f7 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1539,6 +1539,26 @@ termcap5. + + + $JOURNAL_STREAM + + If the standard output or standard error output of the executed processes are connected to the + journal (for example, by setting StandardError=journal) $JOURNAL_STREAM + contains the device and inode numbers of the connection file descriptor, formatted in decimal, separated by a + colon (:). This permits invoked processes to safely detect whether their standard output or + standard error output are connected to the journal. The device and inode numbers of the file descriptors should + be compared with the values set in the environment variable to determine whether the process output is still + connected to the journal. Note that it is generally not sufficient to only check whether + $JOURNAL_STREAM is set at all as services might invoke external processes replacing their + standard output or standard error output, without unsetting the environment variable. + + This environment variable is primarily useful to allow services to optionally upgrade their used log + protocol to the native journal protocol (using + sd_journal_print3 and other + functions) if their standard output or standard error output is connected to the journal anyway, thus enabling + delivery of structured metadata along with logged messages. + Additional variables may be configured by the following diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index 9b4e8e98fa..39a185f59b 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -61,3 +61,19 @@ #else # error Unknown rlim_t size #endif + +#if SIZEOF_DEV_T == 8 +# define DEV_FMT "%" PRIu64 +#elif SIZEOF_DEV_T == 4 +# define DEV_FMT "%" PRIu32 +#else +# error Unknown dev_t size +#endif + +#if SIZEOF_INO_T == 8 +# define INO_FMT "%" PRIu64 +#elif SIZEOF_INO_T == 4 +# define INO_FMT "%" PRIu32 +#else +# error Unknown ino_t size +#endif diff --git a/src/core/execute.c b/src/core/execute.c index b5a5997f15..3c3369373f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -454,7 +454,10 @@ static int setup_output( int fileno, int socket_fd, const char *ident, - uid_t uid, gid_t gid) { + uid_t uid, + gid_t gid, + dev_t *journal_stream_dev, + ino_t *journal_stream_ino) { ExecOutput o; ExecInput i; @@ -464,6 +467,8 @@ static int setup_output( assert(context); assert(params); assert(ident); + assert(journal_stream_dev); + assert(journal_stream_ino); if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) { @@ -543,6 +548,17 @@ static int setup_output( if (r < 0) { log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr"); r = open_null_as(O_WRONLY, fileno); + } else { + struct stat st; + + /* If we connected this fd to the journal via a stream, patch the device/inode into the passed + * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits + * services to detect whether they are connected to the journal or not. */ + + if (fstat(fileno, &st) >= 0) { + *journal_stream_dev = st.st_dev; + *journal_stream_ino = st.st_ino; + } } return r; @@ -1286,6 +1302,8 @@ static int build_environment( const char *home, const char *username, const char *shell, + dev_t journal_stream_dev, + ino_t journal_stream_ino, char ***ret) { _cleanup_strv_free_ char **our_env = NULL; @@ -1295,7 +1313,7 @@ static int build_environment( assert(c); assert(ret); - our_env = new0(char*, 11); + our_env = new0(char*, 12); if (!our_env) return -ENOMEM; @@ -1367,8 +1385,15 @@ static int build_environment( our_env[n_env++] = x; } + if (journal_stream_dev != 0 && journal_stream_ino != 0) { + if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT ":" INO_FMT, journal_stream_dev, journal_stream_ino) < 0) + return -ENOMEM; + + our_env[n_env++] = x; + } + our_env[n_env++] = NULL; - assert(n_env <= 11); + assert(n_env <= 12); *ret = our_env; our_env = NULL; @@ -1481,10 +1506,12 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; const char *username = NULL, *home = NULL, *shell = NULL, *wd; + dev_t journal_stream_dev = 0; + ino_t journal_stream_ino = 0; + bool needs_mount_namespace; uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; int i, r; - bool needs_mount_namespace; assert(unit); assert(command); @@ -1584,13 +1611,13 @@ static int exec_child( return r; } - r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDOUT; return r; } - r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDERR; return r; @@ -1729,7 +1756,16 @@ static int exec_child( } } - r = build_environment(context, params, n_fds, home, username, shell, &our_env); + r = build_environment( + context, + params, + n_fds, + home, + username, + shell, + journal_stream_dev, + journal_stream_ino, + &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; -- cgit v1.2.3-54-g00ecf From a1feacf77f324f8af43de7f994372fbc72d58ae9 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 Jun 2016 17:02:27 -0400 Subject: load-fragment: ignore ENOTDIR/EACCES errors (#3510) If for whatever reason the file system is "corrupted", we want to be resilient and ignore the error, as long as we can load the units from a different place. Arch bug https://bugs.archlinux.org/task/49547. A user had an ntfs symlink (essentially a file) instead of a directory after restoring from backup. We should just ignore that like we would treat a missing directory, for general resiliency. We should treat permission errors similarly. For example an unreadable /usr/local/lib directory would prevent (user) instances of systemd from loading any units. It seems better to continue. --- src/core/load-fragment.c | 10 +++++++++- src/shared/install.c | 10 +++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 17c72aed88..d42f517354 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3830,7 +3830,15 @@ static int load_from_path(Unit *u, const char *path) { if (r >= 0) break; filename = mfree(filename); - if (r != -ENOENT) + + /* ENOENT means that the file is missing or is a dangling symlink. + * ENOTDIR means that one of paths we expect to be is a directory + * is not a directory, we should just ignore that. + * EACCES means that the directory or file permissions are wrong. + */ + if (r == -EACCES) + log_debug_errno(r, "Cannot access \"%s\": %m", filename); + else if (!IN_SET(r, -ENOENT, -ENOTDIR)) return r; /* Empty the symlink names for the next run */ diff --git a/src/shared/install.c b/src/shared/install.c index 64d66a45d3..23cab96c50 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -779,7 +779,7 @@ static int find_symlinks( fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); if (fd < 0) { - if (errno == ENOENT) + if (IN_SET(errno, ENOENT, ENOTDIR, EACCES)) return 0; return -errno; } @@ -1271,7 +1271,7 @@ static int unit_file_search( info->path = path; path = NULL; return r; - } else if (r != -ENOENT) + } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)) return r; } @@ -1296,7 +1296,7 @@ static int unit_file_search( info->path = path; path = NULL; return r; - } else if (r != -ENOENT) + } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)) return r; } } @@ -2870,6 +2870,10 @@ int unit_file_get_list( if (!d) { if (errno == ENOENT) continue; + if (IN_SET(errno, ENOTDIR, EACCES)) { + log_debug("Failed to open \"%s\": %m", *i); + continue; + } return -errno; } -- cgit v1.2.3-54-g00ecf From 20897a0d6ea12bbc08f70146cc7ad4540b65a0fa Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Fri, 10 Jun 2016 01:57:51 +0200 Subject: networkd: added support for vrf interfaces (#3316) --- Makefile.am | 2 ++ configure.ac | 1 + man/systemd.netdev.xml | 13 ++++++++ src/basic/missing.h | 4 +++ src/libsystemd/sd-netlink/netlink-types.c | 8 +++++ src/libsystemd/sd-netlink/netlink-types.h | 1 + src/network/networkd-netdev-gperf.gperf | 2 ++ src/network/networkd-netdev-vrf.c | 50 +++++++++++++++++++++++++++++++ src/network/networkd-netdev-vrf.h | 33 ++++++++++++++++++++ src/network/networkd-netdev.c | 4 +++ src/network/networkd-netdev.h | 1 + src/network/networkd.h | 1 + 12 files changed, 120 insertions(+) create mode 100644 src/network/networkd-netdev-vrf.c create mode 100644 src/network/networkd-netdev-vrf.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 8960513ffe..50e01af667 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5462,6 +5462,8 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ src/network/networkd-netdev.c \ + src/network/networkd-netdev-vrf.h \ + src/network/networkd-netdev-vrf.c \ src/network/networkd-netdev-tunnel.h \ src/network/networkd-netdev-tunnel.c \ src/network/networkd-netdev-veth.h \ diff --git a/configure.ac b/configure.ac index ffc6eedcdd..f4fcc4f113 100644 --- a/configure.ac +++ b/configure.ac @@ -325,6 +325,7 @@ AC_CHECK_TYPES([char16_t, char32_t, key_serial_t], AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IN6_ADDR_GEN_MODE_STABLE_PRIVACY, + IFLA_VRF_TABLE, IFLA_MACVLAN_FLAGS, IFLA_IPVLAN_MODE, IFLA_VTI_REMOTE, diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 3cc58ca854..2be1efee2f 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -161,6 +161,10 @@ vxlan A virtual extensible LAN (vxlan), for connecting Cloud computing deployments. + + vrf + A Virtual Routing and Forwarding (VRF) interface to create seperate routing and forwarding domains. + @@ -1137,7 +1141,16 @@ Name=dummy-test Kind=dummy MACAddress=12:34:56:78:9a:bc + + /etc/systemd/network/25-vrf.netdev + Create an VRF interface with table 42. + [NetDev] +Name=vrf-test +Kind=vrf +[VRF] +TableId=42 + See Also diff --git a/src/basic/missing.h b/src/basic/missing.h index 53dfa1c801..b1272f8799 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -837,6 +837,10 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRPORT_PROXYARP 10 #endif +#if !HAVE_DECL_IFLA_VRF_TABLE +#define IFLA_VRF_TABLE 1 +#endif + #if !HAVE_DECL_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 3a4bac2ced..566a050432 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -278,6 +278,10 @@ static const NLType rtnl_link_info_data_ip6tnl_types[] = { [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, }; +static const NLType rtnl_link_info_data_vrf_types[] = { + [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, +}; + /* these strings must match the .kind entries in the kernel */ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_BOND] = "bond", @@ -298,6 +302,7 @@ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti", [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6", [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl", + [NL_UNION_LINK_INFO_DATA_VRF] = "vrf", }; DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); @@ -338,6 +343,9 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = { [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types), .types = rtnl_link_info_data_ip6tnl_types }, + [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types), + .types = rtnl_link_info_data_vrf_types }, + }; static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index ecb20bfcdc..7c0e598b26 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -86,6 +86,7 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_VTI_TUNNEL, NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL, NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL, + NL_UNION_LINK_INFO_DATA_VRF, _NL_UNION_LINK_INFO_DATA_MAX, _NL_UNION_LINK_INFO_DATA_INVALID = -1 } NLUnionLinkInfoData; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index bf93b0d9fa..9d69f61376 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -11,6 +11,7 @@ #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev.h" #include "vlan-util.h" %} @@ -105,3 +106,4 @@ Bridge.ForwardDelaySec, config_parse_sec, 0, Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering) +VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id) diff --git a/src/network/networkd-netdev-vrf.c b/src/network/networkd-netdev-vrf.c new file mode 100644 index 0000000000..8bbb0aecb1 --- /dev/null +++ b/src/network/networkd-netdev-vrf.c @@ -0,0 +1,50 @@ +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold + + 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 . +***/ + +#include + +#include "sd-netlink.h" +#include "missing.h" +#include "networkd-netdev-vrf.h" + +static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + Vrf *v; + int r; + + assert(netdev); + assert(!link); + assert(m); + + v = VRF(netdev); + + assert(v); + + r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table_id); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IPLA_VRF_TABLE attribute: %m"); + + return r; +} + +const NetDevVTable vrf_vtable = { + .object_size = sizeof(Vrf), + .sections = "Match\0NetDev\0VRF\0", + .fill_message_create = netdev_vrf_fill_message_create, + .create_type = NETDEV_CREATE_MASTER, +}; diff --git a/src/network/networkd-netdev-vrf.h b/src/network/networkd-netdev-vrf.h new file mode 100644 index 0000000000..3d92a26a4d --- /dev/null +++ b/src/network/networkd-netdev-vrf.h @@ -0,0 +1,33 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold + + 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 . +***/ + +typedef struct Vrf Vrf; + +#include "networkd-netdev.h" + +struct Vrf { + NetDev meta; + + uint32_t table_id; +}; + +DEFINE_NETDEV_CAST(VRF, Vrf); +extern const NetDevVTable vrf_vtable; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 851a36290c..b55d76a53c 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -55,6 +55,8 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = &tun_vtable, [NETDEV_KIND_TAP] = &tap_vtable, [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable, + [NETDEV_KIND_VRF] = &vrf_vtable, + }; static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { @@ -78,6 +80,8 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = "tun", [NETDEV_KIND_TAP] = "tap", [NETDEV_KIND_IP6TNL] = "ip6tnl", + [NETDEV_KIND_VRF] = "vrf", + }; DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 20244c0309..b92a973b85 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -55,6 +55,7 @@ typedef enum NetDevKind { NETDEV_KIND_DUMMY, NETDEV_KIND_TUN, NETDEV_KIND_TAP, + NETDEV_KIND_VRF, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetDevKind; diff --git a/src/network/networkd.h b/src/network/networkd.h index ab512f0d08..c4bd712147 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -41,6 +41,7 @@ #include "networkd-netdev-tuntap.h" #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" -- cgit v1.2.3-54-g00ecf From 6cb955c6a18d7e122ca24ca4873343ca41feeb50 Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Mon, 13 Jun 2016 01:05:49 +0200 Subject: networkd: vrf: add support for enslaving devices to VRFs --- man/systemd.network.xml | 17 +++++++++++++++++ src/network/networkd-link.c | 23 ++++++++++++++++++++++- src/network/networkd-netdev-vrf.c | 2 +- src/network/networkd-netdev.c | 4 ++-- src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 6 +++++- src/network/networkd-network.h | 1 + 7 files changed, 49 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index ea98c821fa..edf227c134 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -578,6 +578,12 @@ The name of the bond to add the link to. + + VRF= + + The name of the VRF to add the link to. + + VLAN= @@ -1276,6 +1282,17 @@ Name=bond1 [Network] DHCP=yes + + + + + /etc/systemd/network/25-vrf.network + Add the bond1 interface to the VRF master interface vrf-test. This will redirect routes generated on this interface to be within the routing table defined during VRF creation. Traffic won't be redirected towards the VRFs routing table unless specific ip-rules are added. + [Match] +Name=bond1 + +[Network] +VRF=vrf-test diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 044f934e5f..1842685180 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1600,7 +1600,7 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); /* set it free if not enslaved with networkd */ - if (!link->network->bridge && !link->network->bond) { + if (!link->network->bridge && !link->network->bond && !link->network->vrf) { r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m"); @@ -2055,6 +2055,7 @@ static int link_enter_join_netdev(Link *link) { if (!link->network->bridge && !link->network->bond && + !link->network->vrf && hashmap_isempty(link->network->stacked_netdevs)) return link_joined(link); @@ -2101,6 +2102,26 @@ static int link_enter_join_netdev(Link *link) { link->enslaving++; } + if (link->network->vrf) { + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname), + NULL); + r = netdev_join(link->network->vrf, link, netdev_join_handler); + if (r < 0) { + log_struct_errno(LOG_WARNING, r, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->vrf->ifname), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving++; + } + HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { log_struct(LOG_DEBUG, diff --git a/src/network/networkd-netdev-vrf.c b/src/network/networkd-netdev-vrf.c index 8bbb0aecb1..89bd142e8c 100644 --- a/src/network/networkd-netdev-vrf.c +++ b/src/network/networkd-netdev-vrf.c @@ -44,7 +44,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink const NetDevVTable vrf_vtable = { .object_size = sizeof(Vrf), - .sections = "Match\0NetDev\0VRF\0", + .sections = "NetDev\0VRF\0", .fill_message_create = netdev_vrf_fill_message_create, .create_type = NETDEV_CREATE_MASTER, }; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index b55d76a53c..b192884fd9 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -202,7 +202,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h assert(netdev->state == NETDEV_STATE_READY); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); assert(link); assert(callback); @@ -285,7 +285,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call assert(netdev); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); if (netdev->state == NETDEV_STATE_READY) { r = netdev_enslave_ready(netdev, link, callback); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 0b0aa58f67..affc0d00e9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -37,6 +37,7 @@ Network.MACVTAP, config_parse_netdev, Network.IPVLAN, config_parse_netdev, 0, 0 Network.VXLAN, config_parse_netdev, 0, 0 Network.Tunnel, config_parse_tunnel, 0, 0 +Network.VRF, config_parse_netdev, 0, 0 Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 84bdf75b38..2b764d4f24 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -244,8 +244,8 @@ void network_free(Network *network) { strv_free(network->bind_carrier); netdev_unref(network->bridge); - netdev_unref(network->bond); + netdev_unref(network->vrf); HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) { hashmap_remove(network->stacked_netdevs, netdev->ifname); @@ -470,6 +470,10 @@ int config_parse_netdev(const char *unit, case NETDEV_KIND_BOND: network->bond = netdev; + break; + case NETDEV_KIND_VRF: + network->vrf = netdev; + break; case NETDEV_KIND_VLAN: case NETDEV_KIND_MACVLAN: diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 38688cc400..08ee939faa 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -104,6 +104,7 @@ struct Network { NetDev *bridge; NetDev *bond; + NetDev *vrf; Hashmap *stacked_netdevs; /* DHCP Client Support */ -- cgit v1.2.3-54-g00ecf From cf647b69baee4c478d3909c327e3d917e1563f44 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Jun 2016 15:29:16 +0200 Subject: systemctl: make sure we terminate the bus connection first, and then close the pager (#3550) If "systemctl -H" is used, let's make sure we first terminate the bus connection, and only then close the pager. If done in this order ssh will get an EOF on stdin (as we speak D-Bus through ssh's stdin/stdout), and then terminate. This makes sure the standard error we were invoked on is released by ssh, and only that makes sure we don't deadlock on the pager which waits for all clients closing its input pipe. (Similar fixes for the various other xyzctl tools that support both pagers and -H) Fixes: #3543 --- src/libsystemd/sd-bus/busctl.c | 3 ++- src/locale/localectl.c | 3 ++- src/login/loginctl.c | 4 +++- src/machine/machinectl.c | 3 ++- src/systemctl/systemctl.c | 4 ++-- src/timedate/timedatectl.c | 3 ++- 6 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index bfe967bfb0..eb042e9c81 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1987,7 +1987,7 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; log_parse_environment(); @@ -2078,6 +2078,7 @@ int main(int argc, char *argv[]) { r = busctl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); strv_free(arg_matches); diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 4865335349..81afb4909f 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -656,7 +656,7 @@ static int localectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char*argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -676,6 +676,7 @@ int main(int argc, char*argv[]) { r = localectl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 1c75565636..0fc2720b43 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1554,7 +1554,7 @@ static int loginctl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -1576,6 +1576,8 @@ int main(int argc, char *argv[]) { r = loginctl_main(argc, argv, bus); finish: + sd_bus_flush_close_unref(bus); + pager_close(); polkit_agent_close(); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index afe5026373..583d2a21e7 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2751,7 +2751,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char*argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -2773,6 +2773,7 @@ int main(int argc, char*argv[]) { r = machinectl_main(argc, argv, bus); finish: + sd_bus_flush_close_unref(bus); pager_close(); polkit_agent_close(); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index feb93cad8e..4b34d24ee8 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7938,6 +7938,8 @@ int main(int argc, char*argv[]) { } finish: + release_busses(); + pager_close(); ask_password_agent_close(); polkit_agent_close(); @@ -7949,8 +7951,6 @@ finish: strv_free(arg_wall); free(arg_root); - release_busses(); - /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */ return r < 0 ? EXIT_FAILURE : r; } diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index b7871f81aa..7f61cf0181 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -480,7 +480,7 @@ static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -500,6 +500,7 @@ int main(int argc, char *argv[]) { r = timedatectl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.2.3-54-g00ecf From d2ad7e1ba5c9e68367e0eedbbfdadfc3adf94af2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 Jun 2016 09:11:32 -0400 Subject: systemctl: delay pager/polkit agent opening as much as possible In https://github.com/systemd/systemd/issues/3543, we would open the pager before starting ssh, and the pipe fd was "leaked" into the ssh child as the stderr fd. Previous commit fixes bus-socket to nullify stderr before launching the child, but it seems reasonable to also delay starting the pager. If we are going to croak when trying to open the transport, it seems better to do this before starting the pager. This commit would also fix #3543 on its own. --- src/systemctl/systemctl.c | 100 +++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ecd875fa2d..f69c858bd6 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -735,12 +735,12 @@ static int list_units(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (r < 0) return r; @@ -947,12 +947,12 @@ static int list_sockets(int argc, char *argv[], void *userdata) { int r = 0, n; sd_bus *bus; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -1254,12 +1254,12 @@ static int list_timers(int argc, char *argv[], void *userdata) { sd_bus *bus; int r = 0; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -1425,8 +1425,6 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { int r; bool fallback = false; - pager_open(arg_no_pager, false); - if (install_client_side()) { Hashmap *h; UnitFileList *u; @@ -1541,6 +1539,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); } + pager_open(arg_no_pager, false); + qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); output_unit_file_list(units, c); @@ -1789,12 +1789,12 @@ static int list_dependencies(int argc, char *argv[], void *userdata) { } else u = SPECIAL_DEFAULT_TARGET; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + puts(u); return list_dependencies_one(bus, u, 0, &units, 0); @@ -2020,8 +2020,6 @@ static int list_machines(int argc, char *argv[], void *userdata) { return -EPERM; } - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; @@ -2030,6 +2028,8 @@ static int list_machines(int argc, char *argv[], void *userdata) { if (r < 0) return r; + pager_open(arg_no_pager, false); + qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info); output_machines_list(machine_infos, r); free_machines_list(machine_infos, r); @@ -2233,8 +2233,6 @@ static int list_jobs(int argc, char *argv[], void *userdata) { int r; bool skipped = false; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; @@ -2275,6 +2273,8 @@ static int list_jobs(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); + pager_open(arg_no_pager, false); + output_jobs_list(jobs, c, skipped); return 0; } @@ -2287,12 +2287,12 @@ static int cancel_job(int argc, char *argv[], void *userdata) { if (argc <= 1) return trivial_method(argc, argv, userdata); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + STRV_FOREACH(name, strv_skip(argv, 1)) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; uint32_t id; @@ -2828,13 +2828,13 @@ static int start_unit(int argc, char *argv[], void *userdata) { char **name; int r = 0; - ask_password_agent_open_if_enabled(); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + ask_password_agent_open_if_enabled(); + polkit_agent_open_if_enabled(); + if (arg_action == ACTION_SYSTEMCTL) { enum action action; @@ -2954,9 +2954,6 @@ static int logind_reboot(enum action a) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - (void) logind_set_wall_message(); - r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; @@ -2992,6 +2989,9 @@ static int logind_reboot(enum action a) { return -EINVAL; } + polkit_agent_open_if_enabled(); + (void) logind_set_wall_message(); + r = sd_bus_call_method( bus, "org.freedesktop.login1", @@ -3338,12 +3338,12 @@ static int kill_unit(int argc, char *argv[], void *userdata) { sd_bus *bus; int r, q; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + if (!arg_kill_who) arg_kill_who = "all"; @@ -4855,6 +4855,10 @@ static int show(int argc, char *argv[], void *userdata) { return -EINVAL; } + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + pager_open(arg_no_pager, false); if (show_status) @@ -4863,10 +4867,6 @@ static int show(int argc, char *argv[], void *userdata) { * be split up into many files. */ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); - r = acquire_bus(BUS_MANAGER, &bus); - if (r < 0) - return r; - /* If no argument is specified inspect the manager itself */ if (show_properties && argc <= 1) return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized); @@ -5029,12 +5029,12 @@ static int set_property(int argc, char *argv[], void *userdata) { char **i; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5081,12 +5081,12 @@ static int daemon_reload(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + switch (arg_action) { case ACTION_RELOAD: @@ -5141,12 +5141,12 @@ static int trivial_method(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + method = streq(argv[0], "clear-jobs") || streq(argv[0], "cancel") ? "ClearJobs" : @@ -5184,12 +5184,12 @@ static int reset_failed(int argc, char *argv[], void *userdata) { if (argc <= 1) return trivial_method(argc, argv, userdata); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) return log_error_errno(r, "Failed to expand names: %m"); @@ -5223,12 +5223,12 @@ static int show_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + r = sd_bus_get_property( bus, "org.freedesktop.systemd1", @@ -5332,12 +5332,12 @@ static int set_environment(int argc, char *argv[], void *userdata) { assert(argc > 1); assert(argv); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + method = streq(argv[0], "set-environment") ? "SetEnvironment" : "UnsetEnvironment"; @@ -5369,12 +5369,12 @@ static int import_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5666,12 +5666,12 @@ static int enable_unit(int argc, char *argv[], void *userdata) { const char *method; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + if (streq(verb, "enable")) { method = "EnableUnitFiles"; expect_carries_install_info = true; @@ -5832,12 +5832,12 @@ static int add_dependency(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5894,12 +5894,12 @@ static int preset_all(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -7720,8 +7720,6 @@ static int logind_schedule_shutdown(void) { sd_bus *bus; int r; - (void) logind_set_wall_message(); - r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; @@ -7748,6 +7746,8 @@ static int logind_schedule_shutdown(void) { if (arg_dry) action = strjoina("dry-", action); + (void) logind_set_wall_message(); + r = sd_bus_call_method( bus, "org.freedesktop.login1", -- cgit v1.2.3-54-g00ecf From 5278bbfe0c79c1f2b5bf8a215d8e7d63f1900ce9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Jun 2016 18:37:11 +0200 Subject: resolved: when restarting a transaction make sure to not touch it anymore (#3553) dns_transaction_maybe_restart() is supposed to return 1 if the the transaction has been restarted and 0 otherwise. dns_transaction_process_dnssec() relies on this behaviour. Before this change in case of restart we'd call dns_transaction_go() when restarting the lookup, returning its return value unmodified. This is wrong however, as that function returns 1 if the transaction is pending, and 0 if it completed immediately, which is a very different set of return values. Fix this, by always returning 1 on redirection. The wrong return value resulted in all kinds of bad memory accesses as we might continue processing a transaction that was redirected and completed immediately (and thus freed). This patch also adds comments to the two functions to clarify the return values for the future. Most likely fixes: #2942 #3475 #3484 --- src/resolve/resolved-dns-transaction.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index ed18df35cb..bcb1b6d8a7 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -404,8 +404,12 @@ static void dns_transaction_retry(DnsTransaction *t) { } static int dns_transaction_maybe_restart(DnsTransaction *t) { + int r; + assert(t); + /* Returns > 0 if the transaction was restarted, 0 if not */ + if (!t->server) return 0; @@ -420,7 +424,12 @@ static int dns_transaction_maybe_restart(DnsTransaction *t) { log_debug("Server feature level is now lower than when we began our transaction. Restarting with new ID."); dns_transaction_shuffle_id(t); - return dns_transaction_go(t); + + r = dns_transaction_go(t); + if (r < 0) + return r; + + return 1; } static int on_stream_complete(DnsStream *s, int error) { @@ -1421,6 +1430,9 @@ int dns_transaction_go(DnsTransaction *t) { assert(t); + /* Returns > 0 if the transaction is now pending, returns 0 if could be processed immediately and has finished + * now. */ + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); r = dns_transaction_prepare(t, ts); -- cgit v1.2.3-54-g00ecf From b09df4e21dd191dabe382d702744df57d9d448a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Jun 2016 22:46:44 +0200 Subject: process-util: fix two bugs in get_process_cmdline() (#3555) See: https://github.com/systemd/systemd/pull/3529#issuecomment-226421007 --- src/basic/process-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index b5b068ad38..20768b715a 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -161,6 +161,8 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (len > 0) r[len] = 0; + else + r = mfree(r); } else { bool dotdotdot = false; @@ -214,7 +216,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } strncpy(k, "...", left-1); - k[left] = 0; + k[left-1] = 0; } else *k = 0; } -- cgit v1.2.3-54-g00ecf From 222953e87f34545a3f9c6d3c18216e222bf6ea94 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Fri, 10 Jun 2016 09:50:16 -0400 Subject: Ensure kdbus isn't used (#3501) Delete the dbus1 generator and some critical wiring. This prevents kdbus from being loaded or detected. As such, it will never be used, even if the user still has a useful kdbus module loaded on their system. Sort of fixes #3480. Not really, but it's better than the current state. --- Makefile.am | 20 -- autogen.sh | 12 +- configure.ac | 10 - src/core/busname.c | 7 +- src/core/kmod-setup.c | 3 - src/core/manager.c | 23 --- src/core/mount-setup.c | 2 - src/core/service.c | 17 +- src/dbus1-generator/dbus1-generator.c | 331 ---------------------------------- src/login/pam_systemd.c | 31 ++-- src/shared/bus-util.c | 34 ---- src/shared/bus-util.h | 3 - 12 files changed, 23 insertions(+), 470 deletions(-) delete mode 100644 src/dbus1-generator/dbus1-generator.c (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 50e01af667..3c13acf28d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2902,29 +2902,9 @@ systemd_gpt_auto_generator_CFLAGS = \ endif # ------------------------------------------------------------------------------ -systemgenerator_PROGRAMS += \ - systemd-dbus1-generator - -systemd_dbus1_generator_SOURCES = \ - src/dbus1-generator/dbus1-generator.c - -systemd_dbus1_generator_LDADD = \ - libshared.la - -dbus1-generator-install-hook: - $(AM_V_at)$(MKDIR_P) $(DESTDIR)$(usergeneratordir) - $(AM_V_RM)rm -f $(DESTDIR)$(usergeneratordir)/systemd-dbus1-generator - $(AM_V_LN)$(LN_S) --relative -f $(DESTDIR)$(systemgeneratordir)/systemd-dbus1-generator $(DESTDIR)$(usergeneratordir)/systemd-dbus1-generator - -dbus1-generator-uninstall-hook: - rm -f $(DESTDIR)$(usergeneratordir)/systemd-dbus1-generator - dist_xinitrc_SCRIPTS = \ xorg/50-systemd-user.sh -INSTALL_EXEC_HOOKS += dbus1-generator-install-hook -UNINSTALL_EXEC_HOOKS += dbus1-generator-uninstall-hook - # ------------------------------------------------------------------------------ systemd_sysv_generator_SOURCES = \ src/sysv-generator/sysv-generator.c diff --git a/autogen.sh b/autogen.sh index 3a0695816e..4ec1b2be79 100755 --- a/autogen.sh +++ b/autogen.sh @@ -55,19 +55,19 @@ fi cd $oldpwd if [ "x$1" = "xc" ]; then - $topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args + $topdir/configure CFLAGS='-g -O0 -ftrapv' $args make clean elif [ "x$1" = "xg" ]; then - $topdir/configure CFLAGS='-g -Og -ftrapv' --enable-kdbus $args + $topdir/configure CFLAGS='-g -Og -ftrapv' $args make clean elif [ "x$1" = "xa" ]; then - $topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' --enable-kdbus $args + $topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' $args make clean elif [ "x$1" = "xl" ]; then - $topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args + $topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' $args make clean elif [ "x$1" = "xs" ]; then - scan-build $topdir/configure CFLAGS='-std=gnu99 -g -O0 -ftrapv' --enable-kdbus $args + scan-build $topdir/configure CFLAGS='-std=gnu99 -g -O0 -ftrapv' $args scan-build make else echo @@ -75,6 +75,6 @@ else echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo - echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args" + echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' $args" echo fi diff --git a/configure.ac b/configure.ac index 072b17f01a..1326eebc6a 100644 --- a/configure.ac +++ b/configure.ac @@ -1279,16 +1279,6 @@ AC_ARG_WITH(tpm-pcrindex, AC_DEFINE_UNQUOTED(SD_TPM_PCR, [$SD_TPM_PCR], [TPM PCR register number to use]) -# ------------------------------------------------------------------------------ -have_kdbus=no -AC_ARG_ENABLE(kdbus, AS_HELP_STRING([--disable-kdbus], [do not connect to kdbus by default])) -if test "x$enable_kdbus" != "xno"; then - AC_DEFINE(ENABLE_KDBUS, 1, [Define if kdbus is to be connected to by default]) - have_kdbus=yes - M4_DEFINES="$M4_DEFINES -DENABLE_KDBUS" -fi -AM_CONDITIONAL(ENABLE_KDBUS, [test "$have_kdbus" = "yes"]) - # ------------------------------------------------------------------------------ AC_ARG_WITH(rc-local-script-path-start, AS_HELP_STRING([--with-rc-local-script-path-start=PATH], diff --git a/src/core/busname.c b/src/core/busname.c index f03a95c24e..730be2ee14 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -998,12 +998,7 @@ static int busname_get_timeout(Unit *u, usec_t *timeout) { } static bool busname_supported(void) { - static int supported = -1; - - if (supported < 0) - supported = is_kdbus_available(); - - return supported; + return false; } static int busname_control_pid(Unit *u) { diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 3503db52ed..fd1021f706 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -64,9 +64,6 @@ int kmod_setup(void) { /* this should never be a module */ { "unix", "/proc/net/unix", true, true, NULL }, - /* IPC is needed before we bring up any other services */ - { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted }, - #ifdef HAVE_LIBIPTC /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */ { "ip_tables", "/proc/net/ip_tables_names", false, false, NULL }, diff --git a/src/core/manager.c b/src/core/manager.c index 5c0fee935d..012aa6cd53 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -814,28 +814,6 @@ static int manager_setup_cgroups_agent(Manager *m) { return 0; } -static int manager_setup_kdbus(Manager *m) { - _cleanup_free_ char *p = NULL; - - assert(m); - - if (m->test_run || m->kdbus_fd >= 0) - return 0; - if (!is_kdbus_available()) - return -ESOCKTNOSUPPORT; - - m->kdbus_fd = bus_kernel_create_bus( - MANAGER_IS_SYSTEM(m) ? "system" : "user", - MANAGER_IS_SYSTEM(m), &p); - - if (m->kdbus_fd < 0) - return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m"); - - log_debug("Successfully set up kdbus on %s", p); - - return 0; -} - static int manager_connect_bus(Manager *m, bool reexecuting) { bool try_bus_connect; @@ -1244,7 +1222,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { /* We might have deserialized the kdbus control fd, but if we * didn't, then let's create the bus now. */ - manager_setup_kdbus(m); manager_connect_bus(m, !!serialization); bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 40fc548b42..f9c9b4a91f 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -108,8 +108,6 @@ static const MountPoint mount_table[] = { { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, is_efi_boot, MNT_NONE }, #endif - { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, - is_kdbus_wanted, MNT_IN_CONTAINER }, }; /* These are API file systems that might be mounted by other software, diff --git a/src/core/service.c b/src/core/service.c index 14da6a58a9..78c33b1530 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -574,20 +574,9 @@ static int service_setup_bus_name(Service *s) { if (!s->bus_name) return 0; - if (is_kdbus_available()) { - const char *n; - - n = strjoina(s->bus_name, ".busname"); - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m"); - - } else { - /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); - } + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true); diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c deleted file mode 100644 index 717cb9558e..0000000000 --- a/src/dbus1-generator/dbus1-generator.c +++ /dev/null @@ -1,331 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2013 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 . -***/ - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-util.h" -#include "cgroup-util.h" -#include "conf-parser.h" -#include "dirent-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "mkdir.h" -#include "special.h" -#include "unit-name.h" -#include "util.h" - -static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; - -static int create_dbus_files( - const char *path, - const char *name, - const char *service, - const char *exec, - const char *user, - const char *type) { - - _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL; - _cleanup_fclose_ FILE *f = NULL; - int r; - - assert(path); - assert(name); - assert(service || exec); - - if (!service) { - _cleanup_free_ char *a = NULL; - - s = strjoin("dbus-", name, ".service", NULL); - if (!s) - return log_oom(); - - a = strjoin(arg_dest_late, "/", s, NULL); - if (!a) - return log_oom(); - - f = fopen(a, "wxe"); - if (!f) - return log_error_errno(errno, "Failed to create %s: %m", a); - - fprintf(f, - "# Automatically generated by systemd-dbus1-generator\n\n" - "[Unit]\n" - "SourcePath=%s\n" - "Description=DBUS1: %s\n" - "Documentation=man:systemd-dbus1-generator(8)\n\n" - "[Service]\n" - "ExecStart=%s\n" - "Type=dbus\n" - "BusName=%s\n", - path, - name, - exec, - name); - - if (user) - fprintf(f, "User=%s\n", user); - - - if (type) { - fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type); - - if (streq(type, "system")) - fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n"); - else if (streq(type, "session")) { - char *run; - - run = getenv("XDG_RUNTIME_DIR"); - if (!run) { - log_error("XDG_RUNTIME_DIR not set."); - return -EINVAL; - } - - fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n", - getuid(), run); - } - } - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", a); - - f = safe_fclose(f); - - service = s; - } - - b = strjoin(arg_dest_late, "/", name, ".busname", NULL); - if (!b) - return log_oom(); - - f = fopen(b, "wxe"); - if (!f) - return log_error_errno(errno, "Failed to create %s: %m", b); - - fprintf(f, - "# Automatically generated by systemd-dbus1-generator\n\n" - "[Unit]\n" - "SourcePath=%s\n" - "Description=DBUS1: %s\n" - "Documentation=man:systemd-dbus1-generator(8)\n\n" - "[BusName]\n" - "Name=%s\n" - "Service=%s\n" - "AllowWorld=talk\n", - path, - name, - name, - service); - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", b); - - lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL); - if (!lnk) - return log_oom(); - - mkdir_parents_label(lnk, 0755); - if (symlink(b, lnk)) - return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); - - return 0; -} - -static int add_dbus(const char *path, const char *fname, const char *type) { - _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; - - const ConfigTableItem table[] = { - { "D-BUS Service", "Name", config_parse_string, 0, &name }, - { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, - { "D-BUS Service", "User", config_parse_string, 0, &user }, - { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, - { }, - }; - - char *p; - int r; - - assert(path); - assert(fname); - - p = strjoina(path, "/", fname); - r = config_parse(NULL, p, NULL, - "D-BUS Service\0", - config_item_table_lookup, table, - true, false, true, NULL); - if (r < 0) - return r; - - if (!name) { - log_warning("Activation file %s lacks name setting, ignoring.", p); - return 0; - } - - if (!service_name_is_valid(name)) { - log_warning("Bus service name %s is not valid, ignoring.", name); - return 0; - } - - if (streq(name, "org.freedesktop.systemd1")) { - log_debug("Skipping %s, identified as systemd.", p); - return 0; - } - - if (service) { - if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { - log_warning("Unit name %s is not valid, ignoring.", service); - return 0; - } - if (!endswith(service, ".service")) { - log_warning("Bus names can only activate services, ignoring %s.", p); - return 0; - } - } else { - if (streq(exec, "/bin/false") || !exec) { - log_warning("Neither service name nor binary path specified, ignoring %s.", p); - return 0; - } - - if (exec[0] != '/') { - log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); - return 0; - } - } - - return create_dbus_files(p, name, service, exec, user, type); -} - -static int parse_dbus_fragments(const char *path, const char *type) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r; - - assert(path); - assert(type); - - d = opendir(path); - if (!d) { - if (errno == -ENOENT) - return 0; - - return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); - } - - r = 0; - FOREACH_DIRENT(de, d, goto fail) { - int q; - - if (!endswith(de->d_name, ".service")) - continue; - - q = add_dbus(path, de->d_name, type); - if (q < 0) - r = q; - } - - return r; - -fail: - return log_error_errno(errno, "Failed to read D-Bus services directory: %m"); -} - -static int link_busnames_target(const char *units) { - const char *f, *t; - - f = strjoina(units, "/" SPECIAL_BUSNAMES_TARGET); - t = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET); - - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - return 0; -} - -static int link_compatibility(const char *units) { - const char *f, *t; - - f = strjoina(units, "/systemd-bus-proxyd.socket"); - t = strjoina(arg_dest, "/" SPECIAL_DBUS_SOCKET); - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - f = strjoina(units, "/systemd-bus-proxyd.socket"); - t = strjoina(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket"); - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - t = strjoina(arg_dest, "/" SPECIAL_DBUS_SERVICE); - if (symlink("/dev/null", t) < 0) - return log_error_errno(errno, "Failed to mask %s: %m", t); - - return 0; -} - -int main(int argc, char *argv[]) { - const char *path, *type, *units; - int r, q; - - if (argc > 1 && argc != 4) { - log_error("This program takes three or no arguments."); - return EXIT_FAILURE; - } - - if (argc > 1) { - arg_dest = argv[1]; - arg_dest_late = argv[3]; - } - - log_set_target(LOG_TARGET_SAFE); - log_parse_environment(); - log_open(); - - umask(0022); - - if (!is_kdbus_available()) - return 0; - - r = cg_pid_get_owner_uid(0, NULL); - if (r >= 0) { - path = "/usr/share/dbus-1/services"; - type = "session"; - units = USER_DATA_UNIT_PATH; - } else if (r == -ENXIO) { - path = "/usr/share/dbus-1/system-services"; - type = "system"; - units = SYSTEM_DATA_UNIT_PATH; - } else - return log_error_errno(r, "Failed to determine whether we are running as user or system instance: %m"); - - r = parse_dbus_fragments(path, type); - - /* FIXME: One day this should just be pulled in statically from basic.target */ - q = link_busnames_target(units); - if (q < 0) - r = q; - - q = link_compatibility(units); - if (q < 0) - r = q; - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 98dc201340..4f023640f6 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -182,25 +182,20 @@ static int export_legacy_dbus_address( _cleanup_free_ char *s = NULL; int r = PAM_BUF_ERR; - if (is_kdbus_available()) { - if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0) - goto error; - } else { - /* FIXME: We *really* should move the access() check into the - * daemons that spawn dbus-daemon, instead of forcing - * DBUS_SESSION_BUS_ADDRESS= here. */ - - s = strjoin(runtime, "/bus", NULL); - if (!s) - goto error; - - if (access(s, F_OK) < 0) - return PAM_SUCCESS; + /* FIXME: We *really* should move the access() check into the + * daemons that spawn dbus-daemon, instead of forcing + * DBUS_SESSION_BUS_ADDRESS= here. */ - s = mfree(s); - if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0) - goto error; - } + s = strjoin(runtime, "/bus", NULL); + if (!s) + goto error; + + if (access(s, F_OK) < 0) + return PAM_SUCCESS; + + s = mfree(s); + if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0) + goto error; r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0); if (r != PAM_SUCCESS) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 8cfa936347..8e3307dc24 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1505,40 +1505,6 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send return 1; } -bool is_kdbus_wanted(void) { - _cleanup_free_ char *value = NULL; -#ifdef ENABLE_KDBUS - const bool configured = true; -#else - const bool configured = false; -#endif - - int r; - - if (get_proc_cmdline_key("kdbus", NULL) > 0) - return true; - - r = get_proc_cmdline_key("kdbus=", &value); - if (r <= 0) - return configured; - - return parse_boolean(value) == 1; -} - -bool is_kdbus_available(void) { - _cleanup_close_ int fd = -1; - struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE }; - - if (!is_kdbus_wanted()) - return false; - - fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); - if (fd < 0) - return false; - - return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; -} - int bus_property_get_rlimit( sd_bus *bus, const char *path, diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index d792258ecd..db6b1acba2 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -157,7 +157,4 @@ int bus_log_create_error(int r); int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path); int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external); -bool is_kdbus_wanted(void); -bool is_kdbus_available(void); - int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); -- cgit v1.2.3-54-g00ecf From b774852ae6442eb50ca6e098d19d486cbcc82a12 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 19 Jun 2016 15:02:51 +0000 Subject: tests: fix memory leak in test-keymap-util Fixes: ==27917== 3 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==27917== at 0x4C28BF6: malloc (vg_replace_malloc.c:299) ==27917== by 0x55083D9: strdup (in /usr/lib64/libc-2.22.so) ==27917== by 0x1140DA: find_converted_keymap (keymap-util.c:524) ==27917== by 0x110844: test_find_converted_keymap (test-keymap-util.c:52) ==27917== by 0x1124FE: main (test-keymap-util.c:213) ==27917== --- src/locale/test-keymap-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c index 7e2c9e505a..2adda3da2b 100644 --- a/src/locale/test-keymap-util.c +++ b/src/locale/test-keymap-util.c @@ -58,8 +58,8 @@ static void test_find_converted_keymap(void) { assert_se(r == 1); assert_se(streq(ans, "pl")); - assert_se(find_converted_keymap("pl", "dvorak", &ans) == 1); - assert_se(streq(ans, "pl-dvorak")); + assert_se(find_converted_keymap("pl", "dvorak", &ans2) == 1); + assert_se(streq(ans2, "pl-dvorak")); } static void test_find_legacy_keymap(void) { -- cgit v1.2.3-54-g00ecf From b3d69149bd03b1b42ded4661bfd799778844e4c1 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 19 Jun 2016 23:43:35 +0000 Subject: tests: don't run test_get_process_cmdline_harder under valgrind See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 --- src/test/test-process-util.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index af2c9282d4..99c92780b8 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -26,6 +26,9 @@ #include #include #include +#ifdef HAVE_VALGRIND_VALGRIND_H +#include +#endif #include "alloc-util.h" #include "architecture.h" @@ -164,6 +167,14 @@ static void test_get_process_cmdline_harder(void) { if (geteuid() != 0) return; +#ifdef HAVE_VALGRIND_VALGRIND_H + /* valgrind patches open(/proc//cmdline) + * so, test_get_process_cmdline_harder fails always + * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */ + if (RUNNING_ON_VALGRIND) + return; +#endif + pid = fork(); if (pid > 0) { siginfo_t si; -- cgit v1.2.3-54-g00ecf From affd7ed1a923b0df8479cff1bd9eafb625fdaa66 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 13 Jun 2016 16:10:06 +0200 Subject: pid1: reconnect to the console before being re-executed When re-executed, reconnect the console to PID1's stdios as it was the case when PID1 was initially started by the kernel. --- src/core/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 93098daa9b..cef7575937 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1967,6 +1967,9 @@ finish: log_error_errno(r, "Failed to switch root, trying to continue: %m"); } + /* Reopen the console */ + (void) make_console_stdio(); + args_size = MAX(6, argc+1); args = newa(const char*, args_size); @@ -2018,9 +2021,6 @@ finish: arg_serialization = safe_fclose(arg_serialization); fds = fdset_free(fds); - /* Reopen the console */ - (void) make_console_stdio(); - for (j = 1, i = 1; j < (unsigned) argc; j++) args[i++] = argv[j]; args[i++] = NULL; -- cgit v1.2.3-54-g00ecf From 8ce0611e42c2b0d11007e2172edaa86ce4e4125d Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 20 Jun 2016 18:54:21 +0200 Subject: Revert "do not pass-along the environment from the kernel or initrd" This reverts commit ce8aba568156f2b9d0d3b023e960cda3d9d7db81. We should pass an environment as close as possible to what we originally got. --- src/core/main.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index cef7575937..40d7ff9be5 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1995,10 +1995,6 @@ finish: args[i++] = sfd; args[i++] = NULL; - /* do not pass along the environment we inherit from the kernel or initrd */ - if (switch_root_dir) - (void) clearenv(); - assert(i <= args_size); /* -- cgit v1.2.3-54-g00ecf From eee0a1e48e55b05ab28af0603db64bb10c690782 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 20 Jun 2016 21:40:46 +0300 Subject: core: log the right set of the supported controllers (#3558) Jun 16 05:12:08 systemd[1]: Controller 'io' supported: yes Jun 16 05:12:08 systemd[1]: Controller 'memory' supported: yes Jun 16 05:12:08 systemd[1]: Controller 'pids' supported: yes instead of Jun 16 04:06:50 systemd[1]: Controller 'memory' supported: yes Jun 16 04:06:50 systemd[1]: Controller 'devices' supported: yes Jun 16 04:06:50 systemd[1]: Controller 'pids' supported: yes --- src/core/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index f3e0c54b76..799296ad28 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1723,7 +1723,7 @@ int manager_setup_cgroup(Manager *m) { return log_error_errno(r, "Failed to determine supported controllers: %m"); for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) - log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c)); + log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & CGROUP_CONTROLLER_TO_MASK(c))); return 0; } -- cgit v1.2.3-54-g00ecf From 5733d88dc10508b8eb023d0cb2a4661355a0bbf7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 21:36:57 +0200 Subject: networkd: fix bad memory access when parsing DNSSECNegativeTrustAnchors= --- src/network/networkd-network-gperf.gperf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index affc0d00e9..5172a7b5e9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -52,7 +52,7 @@ Network.DNS, config_parse_strv, Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr) Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns) Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode) -Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, offsetof(Network, dnssec_negative_trust_anchors) +Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, 0 Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) -- cgit v1.2.3-54-g00ecf From 476798b17d41d5f79768051a7f708bc351721223 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 21:37:51 +0200 Subject: resolved: export global NTAs on the bus We export them per-link, hence let's export the global NTAs too. --- src/resolve/resolved-bus.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index f08c6c0637..1fe473ff76 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1414,6 +1414,36 @@ static int bus_property_get_dnssec_supported( return sd_bus_message_append(reply, "b", manager_dnssec_supported(m)); } +static int bus_property_get_ntas( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + const char *domain; + Iterator i; + int r; + + assert(reply); + assert(m); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + SET_FOREACH(domain, m->trust_anchor.negative_by_name, i) { + r = sd_bus_message_append(reply, "s", domain); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; DnsScope *s; @@ -1540,6 +1570,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0), SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0), + SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0), SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED), -- cgit v1.2.3-54-g00ecf From a37129796c3f5b932a2cd974f102409e6871e4e3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 21:38:41 +0200 Subject: resolved: export the effective per-link DNSSEC setting, not the internal one Internally, we store the per-link DNSSEC setting as -1 (invalid) if there's no link-specific setting configured, and the global setting should be used. When exporting this one the bus we really should export the effective DNSSEC setting however, i.e. return the global one if there's non set per-link. --- src/resolve/resolved-link-bus.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index bfb87d78e7..07726c7d9e 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -28,7 +28,23 @@ #include "strv.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport); -static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_dnssec_mode, dnssec_mode, DnssecMode); + +static int property_get_dnssec_mode( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + + assert(reply); + assert(l); + + return sd_bus_message_append(reply, "s", dnssec_mode_to_string(link_get_dnssec_mode(l))); +} static int property_get_dns( sd_bus *bus, @@ -504,7 +520,7 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0), SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0), SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0), - SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0), + SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0), SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0), SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0), -- cgit v1.2.3-54-g00ecf From be371fe03937b6b3c45ee58a96622ff1849b14e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 21:43:36 +0200 Subject: resolve: add "systemd-resolve --status" command The new command shows the per-link and global DNS configuration currently in effect. This is useful to quickly see the DNS settings resolved acquired from networkd and that was pushed into it via the bus APIs. --- man/systemd-resolve.xml | 7 + src/resolve/resolve-tool.c | 522 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 526 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index b917ac20a2..b7fbee3154 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -294,8 +294,15 @@ Flushes all DNS resource record caches the service maintains locally. + + + + Shows the global and per-link DNS settings in currently in effect. + + + diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 2cb2e42b23..4e1e916669 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -21,17 +21,21 @@ #include #include "sd-bus.h" +#include "sd-netlink.h" #include "af-list.h" #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "escape.h" -#include "in-addr-util.h" #include "gcrypt-util.h" +#include "in-addr-util.h" +#include "netlink-util.h" +#include "pager.h" #include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" +#include "strv.h" #include "terminal-util.h" #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) @@ -42,6 +46,7 @@ static uint16_t arg_type = 0; static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +static bool arg_no_pager = false; typedef enum ServiceFamily { SERVICE_FAMILY_TCP, @@ -67,6 +72,7 @@ static enum { MODE_STATISTICS, MODE_RESET_STATISTICS, MODE_FLUSH_CACHES, + MODE_STATUS, } arg_mode = MODE_RESOLVE_HOST; static ServiceFamily service_family_from_string(const char *s) { @@ -1031,6 +1037,472 @@ static int flush_caches(sd_bus *bus) { return 0; } +static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(iay)"); + if (r < 0) + return r; + + for (;;) { + const void *a; + char *pretty; + int family; + size_t sz; + + r = sd_bus_message_enter_container(m, 'r', "iay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(m, "i", &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(m, 'y', &a, &sz); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("Unexpected family, ignoring."); + continue; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_debug("Address size mismatch, ignoring."); + continue; + } + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return r; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(sb)"); + if (r < 0) + return r; + + for (;;) { + const char *domain; + int route_only; + char *pretty; + + r = sd_bus_message_read(m, "(sb)", &domain, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + if (route_only) + pretty = strappend("~", domain); + else + pretty = strdup(domain); + if (!pretty) + return -ENOMEM; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empty_line) { + + struct link_info { + uint64_t scopes_mask; + char *llmnr; + char *mdns; + char *dnssec; + char **dns; + char **domains; + char **ntas; + int dnssec_supported; + } link_info = {}; + + static const struct bus_properties_map property_map[] = { + { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, + { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, + { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, + { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, + { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, + { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, + {} + }; + + _cleanup_free_ char *ifi = NULL, *p = NULL; + char ifname[IF_NAMESIZE] = ""; + char **i; + int r; + + assert(bus); + assert(ifindex > 0); + assert(empty_line); + + if (!name) { + if (!if_indextoname(ifindex, ifname)) + return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex); + + name = ifname; + } + + if (asprintf(&ifi, "%i", ifindex) < 0) + return log_oom(); + + r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p); + if (r < 0) + return log_oom(); + + r = bus_map_all_properties(bus, + "org.freedesktop.resolve1", + p, + property_map, + &link_info); + if (r < 0) { + log_error_errno(r, "Failed to get link data for %i: %m", ifindex); + goto finish; + } + + pager_open(arg_no_pager, false); + + if (*empty_line) + fputc('\n', stdout); + + printf("%sLink %i (%s)%s\n", + ansi_highlight(), ifindex, name, ansi_normal()); + + if (link_info.scopes_mask == 0) + printf(" Current Scopes: none\n"); + else + printf(" Current Scopes:%s%s%s%s%s\n", + link_info.scopes_mask & SD_RESOLVED_DNS ? " DNS" : "", + link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "", + link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "", + link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "", + link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : ""); + + printf(" LLMNR setting: %s\n" + "MulticastDNS setting: %s\n" + " DNSSEC setting: %s\n" + " DNSSEC supported: %s\n", + strna(link_info.llmnr), + strna(link_info.mdns), + strna(link_info.dnssec), + yes_no(link_info.dnssec_supported)); + + STRV_FOREACH(i, link_info.dns) { + printf(" %s %s\n", + i == link_info.dns ? "DNS Server:" : " ", + *i); + } + + STRV_FOREACH(i, link_info.domains) { + printf(" %s %s\n", + i == link_info.domains ? "DNS Domain:" : " ", + *i); + } + + STRV_FOREACH(i, link_info.ntas) { + printf(" %s %s\n", + i == link_info.ntas ? "DNSSEC NTA:" : " ", + *i); + } + + *empty_line = true; + + r = 0; + +finish: + strv_free(link_info.dns); + strv_free(link_info.domains); + free(link_info.llmnr); + free(link_info.mdns); + free(link_info.dnssec); + strv_free(link_info.ntas); + return r; +} + +static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(iiay)"); + if (r < 0) + return r; + + for (;;) { + const void *a; + char *pretty; + int family, ifindex; + size_t sz; + + r = sd_bus_message_enter_container(m, 'r', "iiay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(m, "ii", &ifindex, &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(m, 'y', &a, &sz); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (ifindex != 0) /* only show the global ones here */ + continue; + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("Unexpected family, ignoring."); + continue; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_debug("Address size mismatch, ignoring."); + continue; + } + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return r; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(isb)"); + if (r < 0) + return r; + + for (;;) { + const char *domain; + int route_only, ifindex; + char *pretty; + + r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + if (ifindex != 0) /* only show the global ones here */ + continue; + + if (route_only) + pretty = strappend("~", domain); + else + pretty = strdup(domain); + if (!pretty) + return -ENOMEM; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int status_global(sd_bus *bus, bool *empty_line) { + + struct global_info { + char **dns; + char **domains; + char **ntas; + } global_info = {}; + + static const struct bus_properties_map property_map[] = { + { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, + { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, + {} + }; + + char **i; + int r; + + assert(bus); + assert(empty_line); + + r = bus_map_all_properties(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + property_map, + &global_info); + if (r < 0) { + log_error_errno(r, "Failed to get global data: %m"); + goto finish; + } + + if (strv_isempty(global_info.dns) && strv_isempty(global_info.domains) && strv_isempty(global_info.ntas)) { + r = 0; + goto finish; + } + + pager_open(arg_no_pager, false); + + printf("%sGlobal%s\n", ansi_highlight(), ansi_normal()); + STRV_FOREACH(i, global_info.dns) { + printf(" %s %s\n", + i == global_info.dns ? "DNS Server:" : " ", + *i); + } + + STRV_FOREACH(i, global_info.domains) { + printf(" %s %s\n", + i == global_info.domains ? "DNS Domain:" : " ", + *i); + } + + strv_sort(global_info.ntas); + STRV_FOREACH(i, global_info.ntas) { + printf(" %s %s\n", + i == global_info.ntas ? "DNSSEC NTA:" : " ", + *i); + } + + *empty_line = true; + + r = 0; + +finish: + strv_free(global_info.dns); + strv_free(global_info.domains); + strv_free(global_info.ntas); + + return r; +} + +static int status_all(sd_bus *bus) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + sd_netlink_message *i; + bool empty_line = true; + int r; + + assert(bus); + + r = status_global(bus, &empty_line); + if (r < 0) + return r; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_message_request_dump(req, true); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_call(rtnl, req, 0, &reply); + if (r < 0) + return log_error_errno(r, "Failed to enumerate links: %m"); + + r = 0; + for (i = reply; i; i = sd_netlink_message_next(i)) { + const char *name; + int ifindex, q; + uint16_t type; + + q = sd_netlink_message_get_type(i, &type); + if (q < 0) + return rtnl_log_parse_error(q); + + if (type != RTM_NEWLINK) + continue; + + q = sd_rtnl_message_link_get_ifindex(i, &ifindex); + if (q < 0) + return rtnl_log_parse_error(q); + + if (ifindex == LOOPBACK_IFINDEX) + continue; + + q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); + if (q < 0) + return rtnl_log_parse_error(q); + + q = status_ifindex(bus, ifindex, name, &empty_line); + if (q < 0 && r >= 0) + r = q; + } + + return r; +} + static void help_protocol_types(void) { if (arg_legend) puts("Known protocol types:"); @@ -1038,8 +1510,8 @@ static void help_protocol_types(void) { } static void help_dns_types(void) { - int i; const char *t; + int i; if (arg_legend) puts("Known DNS RR types:"); @@ -1051,8 +1523,8 @@ static void help_dns_types(void) { } static void help_dns_classes(void) { - int i; const char *t; + int i; if (arg_legend) puts("Known DNS RR classes:"); @@ -1073,6 +1545,7 @@ static void help(void) { "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n" " -h --help Show this help\n" " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" " -4 Resolve IPv4 addresses\n" " -6 Resolve IPv6 addresses\n" " -i --interface=INTERFACE Look on interface\n" @@ -1091,6 +1564,7 @@ static void help(void) { " --legend=BOOL Print headers and additional info (default: yes)\n" " --statistics Show resolver statistics\n" " --reset-statistics Reset resolver statistics\n" + " --status Show link and server status\n" " --flush-caches Flush all local DNS caches\n" , program_invocation_short_name); } @@ -1109,7 +1583,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, + ARG_STATUS, ARG_FLUSH_CACHES, + ARG_NO_PAGER, }; static const struct option options[] = { @@ -1130,7 +1606,9 @@ static int parse_argv(int argc, char *argv[]) { { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + { "status", no_argument, NULL, ARG_STATUS }, { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, {} }; @@ -1308,6 +1786,14 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_FLUSH_CACHES; break; + case ARG_STATUS: + arg_mode = MODE_STATUS; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + case '?': return -EINVAL; @@ -1484,8 +1970,38 @@ int main(int argc, char **argv) { r = flush_caches(bus); break; + + case MODE_STATUS: + + if (argc > optind) { + char **ifname; + bool empty_line = false; + + r = 0; + STRV_FOREACH(ifname, argv + optind) { + int ifindex, q; + + q = parse_ifindex(argv[optind], &ifindex); + if (q < 0) { + ifindex = if_nametoindex(argv[optind]); + if (ifindex <= 0) { + log_error_errno(errno, "Failed to resolve interface name: %s", argv[optind]); + continue; + } + } + + q = status_ifindex(bus, ifindex, NULL, &empty_line); + if (q < 0 && r >= 0) + r = q; + } + } else + r = status_all(bus); + + break; } finish: + pager_close(); + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- cgit v1.2.3-54-g00ecf From 35ca4ce022aec65663baf9b4cf9f7f932e196237 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:25:48 +0200 Subject: string-table: make sure DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() handles NULL strings nicely xyz_from_string() functions defined with DEFINE_STRING_TABLE_LOOKUP() properly handle NULL strings already. make sure the equivalent functions defined with DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() do the same. --- src/basic/string-table.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/string-table.h b/src/basic/string-table.h index d88625fca7..369610efc8 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -48,6 +48,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ scope type name##_from_string(const char *s) { \ int b; \ + if (!s) \ + return -1; \ b = parse_boolean(s); \ if (b == 0) \ return (type) 0; \ -- cgit v1.2.3-54-g00ecf From 6f7da49d000637d164bb4b0b4d6964c3abb198de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:30:11 +0200 Subject: resolved: make sure that route-only domains are never added to /etc/resolv.conf After all, /etc/resolv.conf doesn't know the concept of "route-only domains", hence the domains should really not appear there. --- src/resolve/resolved-manager.c | 12 +++++++++++- src/resolve/resolved-manager.h | 2 +- src/resolve/resolved-resolv-conf.c | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 23101cb760..44abacb55a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1153,7 +1153,7 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { return 0; } -int manager_compile_search_domains(Manager *m, OrderedSet **domains) { +int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) { DnsSearchDomain *d; Iterator i; Link *l; @@ -1167,6 +1167,11 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains) { return r; LIST_FOREACH(domains, d, m->search_domains) { + + if (filter_route >= 0 && + d->route_only != !!filter_route) + continue; + r = ordered_set_put(*domains, d->name); if (r == -EEXIST) continue; @@ -1177,6 +1182,11 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains) { HASHMAP_FOREACH(l, m->links, i) { LIST_FOREACH(domains, d, l->search_domains) { + + if (filter_route >= 0 && + d->route_only != !!filter_route) + continue; + r = ordered_set_put(*domains, d->name); if (r == -EEXIST) continue; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index ef71202ef9..c9e6ac9d4f 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -162,7 +162,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); int manager_is_own_hostname(Manager *m, const char *name); int manager_compile_dns_servers(Manager *m, OrderedSet **servers); -int manager_compile_search_domains(Manager *m, OrderedSet **domains); +int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route); DnssecMode manager_get_dnssec_mode(Manager *m); bool manager_dnssec_supported(Manager *m); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index ae17aef3ab..4eb5bba660 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -232,7 +232,7 @@ int manager_write_resolv_conf(Manager *m) { if (r < 0) return log_warning_errno(r, "Failed to compile list of DNS servers: %m"); - r = manager_compile_search_domains(m, &domains); + r = manager_compile_search_domains(m, &domains, false); if (r < 0) return log_warning_errno(r, "Failed to compile list of search domains: %m"); -- cgit v1.2.3-54-g00ecf From 39f259e0b89da8e925c98a8571868848264c4bde Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:32:33 +0200 Subject: resolved: make use of set_put_strdupv() where appropriate --- src/resolve/resolved-link.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index b189c21920..97b5f60545 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -341,7 +341,6 @@ clear: static int link_update_dnssec_negative_trust_anchors(Link *l) { _cleanup_strv_free_ char **ntas = NULL; _cleanup_set_free_free_ Set *ns = NULL; - char **i; int r; assert(l); @@ -358,11 +357,9 @@ static int link_update_dnssec_negative_trust_anchors(Link *l) { if (!ns) return -ENOMEM; - STRV_FOREACH(i, ntas) { - r = set_put_strdup(ns, *i); - if (r < 0) - return r; - } + r = set_put_strdupv(ns, ntas); + if (r < 0) + return r; set_free_free(l->dnssec_negative_trust_anchors); l->dnssec_negative_trust_anchors = ns; @@ -379,6 +376,9 @@ static int link_update_search_domain_one(Link *l, const char *name, bool route_o DnsSearchDomain *d; int r; + assert(l); + assert(name); + r = dns_search_domain_find(l->search_domains, name, &d); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 55e99f2064e7432572ea3eb377a15e50cec525c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:33:27 +0200 Subject: resolved: rework link_update_dns_servers() a bit Let's split the code from the inner loop out, into its own function link_update_dns_server_one(). This matches how things are already handled for the search domain logic. Also, this is preparation for a later commit that persists DNS server data pushed in via the bus. --- src/resolve/resolved-link.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 97b5f60545..8cfaacafff 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -190,6 +190,27 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { return 0; } +static int link_update_dns_server_one(Link *l, const char *name) { + union in_addr_union a; + DnsServer *s; + int family, r; + + assert(l); + assert(name); + + r = in_addr_from_string_auto(name, &family, &a); + if (r < 0) + return r; + + s = dns_server_find(l->dns_servers, family, &a, 0); + if (s) { + dns_server_move_back_and_unmark(s); + return 0; + } + + return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0); +} + static int link_update_dns_servers(Link *l) { _cleanup_strv_free_ char **nameservers = NULL; char **nameserver; @@ -208,22 +229,9 @@ static int link_update_dns_servers(Link *l) { dns_server_mark_all(l->dns_servers); STRV_FOREACH(nameserver, nameservers) { - union in_addr_union a; - DnsServer *s; - int family; - - r = in_addr_from_string_auto(*nameserver, &family, &a); + r = link_update_dns_server_one(l, *nameserver); if (r < 0) goto clear; - - s = dns_server_find(l->dns_servers, family, &a, 0); - if (s) - dns_server_move_back_and_unmark(s); - else { - r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0); - if (r < 0) - goto clear; - } } dns_server_unlink_marked(l->dns_servers); -- cgit v1.2.3-54-g00ecf From b6274a0e9e3dd592826411940a71a67dbf05bcef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:35:23 +0200 Subject: resolved: fix negated boolean function It's weird having a "negative" function link_is_unmanaged(), let's invert it and get rid of the negation this way, by renaming it to link_is_managed(). Internally we stored this as a positive boolean already, hence let's do this for the function too. --- src/resolve/resolved-link.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 8cfaacafff..b321aefda9 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -447,7 +447,7 @@ clear: return r; } -static int link_is_unmanaged(Link *l) { +static int link_is_managed(Link *l) { _cleanup_free_ char *state = NULL; int r; @@ -455,11 +455,11 @@ static int link_is_unmanaged(Link *l) { r = sd_network_link_get_setup_state(l->ifindex, &state); if (r == -ENODATA) - return 1; + return 0; if (r < 0) return r; - return STR_IN_SET(state, "pending", "unmanaged"); + return !STR_IN_SET(state, "pending", "unmanaged"); } static void link_read_settings(Link *l) { @@ -469,12 +469,12 @@ static void link_read_settings(Link *l) { /* Read settings from networkd, except when networkd is not managing this interface. */ - r = link_is_unmanaged(l); + r = link_is_managed(l); if (r < 0) { log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name); return; } - if (r > 0) { + if (r == 0) { /* If this link used to be managed, but is now unmanaged, flush all our settings — but only once. */ if (l->is_managed) -- cgit v1.2.3-54-g00ecf From d97c5aeab8b9c6d871cad292c17c9b9c94736e25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:36:58 +0200 Subject: set: add new set_put_strsplit() call It's like set_put_strdup(), but splits up a string via an extract_first_word() loop. --- src/basic/hashmap.c | 25 +++++++++++++++++++++++++ src/basic/set.h | 2 ++ 2 files changed, 27 insertions(+) (limited to 'src') diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 49a0479592..50fefb0b54 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1764,6 +1764,9 @@ void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { int set_consume(Set *s, void *value) { int r; + assert(s); + assert(value); + r = set_put(s, value); if (r <= 0) free(value); @@ -1791,6 +1794,8 @@ int set_put_strdupv(Set *s, char **l) { int n = 0, r; char **i; + assert(s); + STRV_FOREACH(i, l) { r = set_put_strdup(s, *i); if (r < 0) @@ -1801,3 +1806,23 @@ int set_put_strdupv(Set *s, char **l) { return n; } + +int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) { + const char *p = v; + int r; + + assert(s); + assert(v); + + for (;;) { + char *word; + + r = extract_first_word(&p, &word, separators, flags); + if (r <= 0) + return r; + + r = set_consume(s, word); + if (r < 0) + return r; + } +} diff --git a/src/basic/set.h b/src/basic/set.h index e0d9dd001c..12f64a8c57 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include "extract-word.h" #include "hashmap.h" #include "macro.h" @@ -122,6 +123,7 @@ static inline char **set_get_strv(Set *s) { int set_consume(Set *s, void *value); int set_put_strdup(Set *s, const char *p); int set_put_strdupv(Set *s, char **l); +int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) -- cgit v1.2.3-54-g00ecf From 943ef07ce0aacbee93c721e461c02d651ee9ef6a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:38:23 +0200 Subject: resolved: make sure DNS configuration pushed in by the user stays around on restarts Let's make sure that all settings pushed in stay around when systemd-resolved is restarted. --- src/resolve/resolved-link-bus.c | 11 ++ src/resolve/resolved-link.c | 271 +++++++++++++++++++++++++++++++++++++++- src/resolve/resolved-link.h | 11 +- src/resolve/resolved-manager.c | 65 +++++++++- src/resolve/resolved-manager.h | 2 + 5 files changed, 353 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 07726c7d9e..acce8682de 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -265,6 +265,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ dns_server_unlink_marked(l->dns_servers); link_allocate_scopes(l); + (void) link_save_user(l); (void) manager_write_resolv_conf(l->manager); return sd_bus_reply_method_return(message, NULL); @@ -346,6 +347,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ dns_search_domain_unlink_marked(l->search_domains); + (void) link_save_user(l); (void) manager_write_resolv_conf(l->manager); return sd_bus_reply_method_return(message, NULL); @@ -384,6 +386,8 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er link_allocate_scopes(l); link_add_rrs(l, false); + (void) link_save_user(l); + return sd_bus_reply_method_return(message, NULL); } @@ -416,6 +420,8 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err link_allocate_scopes(l); link_add_rrs(l, false); + (void) link_save_user(l); + return sd_bus_reply_method_return(message, NULL); } @@ -446,6 +452,8 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e link_set_dnssec_mode(l, mode); + (void) link_save_user(l); + return sd_bus_reply_method_return(message, NULL); } @@ -489,6 +497,8 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v l->dnssec_negative_trust_anchors = ns; ns = NULL; + (void) link_save_user(l); + return sd_bus_reply_method_return(message, NULL); } @@ -507,6 +517,7 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error link_allocate_scopes(l); link_add_rrs(l, false); + (void) link_save_user(l); (void) manager_write_resolv_conf(l->manager); return sd_bus_reply_method_return(message, NULL); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index b321aefda9..ea4a007139 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -22,7 +22,10 @@ #include "sd-network.h" #include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "missing.h" +#include "mkdir.h" #include "parse-util.h" #include "resolved-link.h" #include "string-util.h" @@ -49,6 +52,9 @@ int link_new(Manager *m, Link **ret, int ifindex) { l->dnssec_mode = _DNSSEC_MODE_INVALID; l->operstate = IF_OPER_UNKNOWN; + if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0) + return -ENOMEM; + r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) return r; @@ -93,6 +99,8 @@ Link *link_free(Link *l) { dns_scope_free(l->mdns_ipv4_scope); dns_scope_free(l->mdns_ipv6_scope); + free(l->state_file); + free(l); return NULL; } @@ -165,7 +173,7 @@ void link_add_rrs(Link *l, bool force_remove) { link_address_add_rrs(a, force_remove); } -int link_update_rtnl(Link *l, sd_netlink_message *m) { +int link_process_rtnl(Link *l, sd_netlink_message *m) { const char *n = NULL; int r; @@ -511,10 +519,11 @@ static void link_read_settings(Link *l) { log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name); } -int link_update_monitor(Link *l) { +int link_update(Link *l) { assert(l); link_read_settings(l); + link_load_user(l); link_allocate_scopes(l); link_add_rrs(l, false); @@ -846,3 +855,261 @@ bool link_address_relevant(LinkAddress *a, bool local_multicast) { return true; } + +static bool link_needs_save(Link *l) { + assert(l); + + /* Returns true if any of the settings where set different from the default */ + + if (l->is_managed) + return false; + + if (l->llmnr_support != RESOLVE_SUPPORT_YES || + l->mdns_support != RESOLVE_SUPPORT_NO || + l->dnssec_mode != _DNSSEC_MODE_INVALID) + return true; + + if (l->dns_servers || + l->search_domains) + return true; + + if (!set_isempty(l->dnssec_negative_trust_anchors)) + return true; + + return false; +} + +int link_save_user(Link *l) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *v; + int r; + + assert(l); + assert(l->state_file); + + if (!link_needs_save(l)) { + (void) unlink(l->state_file); + return 0; + } + + r = mkdir_parents(l->state_file, 0700); + if (r < 0) + goto fail; + + r = fopen_temporary(l->state_file, &f, &temp_path); + if (r < 0) + goto fail; + + fputs("# This is private data. Do not parse.\n", f); + + v = resolve_support_to_string(l->llmnr_support); + if (v) + fprintf(f, "LLMNR=%s\n", v); + + v = resolve_support_to_string(l->mdns_support); + if (v) + fprintf(f, "MDNS=%s\n", v); + + v = dnssec_mode_to_string(l->dnssec_mode); + if (v) + fprintf(f, "DNSSEC=%s\n", v); + + if (l->dns_servers) { + DnsServer *server; + + fputs("SERVERS=", f); + LIST_FOREACH(servers, server, l->dns_servers) { + + if (server != l->dns_servers) + fputc(' ', f); + + v = dns_server_string(server); + if (!v) { + r = -ENOMEM; + goto fail; + } + + fputs(v, f); + } + fputc('\n', f); + } + + if (l->search_domains) { + DnsSearchDomain *domain; + + fputs("DOMAINS=", f); + LIST_FOREACH(domains, domain, l->search_domains) { + + if (domain != l->search_domains) + fputc(' ', f); + + if (domain->route_only) + fputc('~', f); + + fputs(DNS_SEARCH_DOMAIN_NAME(domain), f); + } + fputc('\n', f); + } + + if (!set_isempty(l->dnssec_negative_trust_anchors)) { + bool space = false; + Iterator i; + char *nta; + + fputs("NTAS=", f); + SET_FOREACH(nta, l->dnssec_negative_trust_anchors, i) { + + if (space) + fputc(' ', f); + + fputs(nta, f); + space = true; + } + fputc('\n', f); + } + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, l->state_file) < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + (void) unlink(l->state_file); + + if (temp_path) + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save link data %s: %m", l->state_file); +} + +int link_load_user(Link *l) { + _cleanup_free_ char + *llmnr = NULL, + *mdns = NULL, + *dnssec = NULL, + *servers = NULL, + *domains = NULL, + *ntas = NULL; + + ResolveSupport s; + int r; + + assert(l); + assert(l->state_file); + + /* Try to load only a single time */ + if (l->loaded) + return 0; + l->loaded = true; + + if (l->is_managed) + return 0; /* if the device is managed, then networkd is our configuration source, not the bus API */ + + r = parse_env_file(l->state_file, NEWLINE, + "LLMNR", &llmnr, + "MDNS", &mdns, + "DNSSEC", &dnssec, + "SERVERS", &servers, + "DOMAINS", &domains, + "NTAS", &ntas, + NULL); + if (r == -ENOENT) + return 0; + if (r < 0) + goto fail; + + link_flush_settings(l); + + /* If we can't recognize the LLMNR or MDNS setting we don't override the default */ + s = resolve_support_from_string(llmnr); + if (s >= 0) + l->llmnr_support = s; + + s = resolve_support_from_string(mdns); + if (s >= 0) + l->mdns_support = s; + + /* If we can't recognize the DNSSEC setting, then set it to invalid, so that the daemon default is used. */ + l->dnssec_mode = dnssec_mode_from_string(dnssec); + + if (servers) { + const char *p = servers; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r < 0) + goto fail; + if (r == 0) + break; + + r = link_update_dns_server_one(l, word); + if (r < 0) { + log_debug_errno(r, "Failed to load DNS server '%s', ignoring: %m", word); + continue; + } + } + } + + if (domains) { + const char *p = domains; + + for (;;) { + _cleanup_free_ char *word = NULL; + const char *n; + bool is_route; + + r = extract_first_word(&p, &word, NULL, 0); + if (r < 0) + goto fail; + if (r == 0) + break; + + is_route = word[0] == '~'; + n = is_route ? word + 1 : word; + + r = link_update_search_domain_one(l, n, is_route); + if (r < 0) { + log_debug_errno(r, "Failed to load search domain '%s', ignoring: %m", word); + continue; + } + } + } + + if (ntas) { + _cleanup_set_free_free_ Set *ns = NULL; + + ns = set_new(&dns_name_hash_ops); + if (!ns) { + r = -ENOMEM; + goto fail; + } + + r = set_put_strsplit(ns, ntas, NULL, 0); + if (r < 0) + goto fail; + + l->dnssec_negative_trust_anchors = ns; + ns = NULL; + } + + return 0; + +fail: + return log_error_errno(r, "Failed to load link data %s: %m", l->state_file); +} + +void link_remove_user(Link *l) { + assert(l); + assert(l->state_file); + + (void) unlink(l->state_file); +} diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index f534c12824..6a2343f9f7 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -81,12 +81,15 @@ struct Link { char name[IF_NAMESIZE]; uint32_t mtu; uint8_t operstate; + + bool loaded; + char *state_file; }; int link_new(Manager *m, Link **ret, int ifindex); Link *link_free(Link *l); -int link_update_rtnl(Link *l, sd_netlink_message *m); -int link_update_monitor(Link *l); +int link_process_rtnl(Link *l, sd_netlink_message *m); +int link_update(Link *l); bool link_relevant(Link *l, int family, bool local_multicast); LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *in_addr); void link_add_rrs(Link *l, bool force_remove); @@ -102,6 +105,10 @@ void link_next_dns_server(Link *l); DnssecMode link_get_dnssec_mode(Link *l); bool link_dnssec_supported(Link *l); +int link_save_user(Link *l); +int link_load_user(Link *l); +void link_remove_user(Link *l); + int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr); LinkAddress *link_address_free(LinkAddress *a); int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 44abacb55a..e8811fa1d8 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -23,6 +23,7 @@ #include "af-list.h" #include "alloc-util.h" +#include "dirent-util.h" #include "dns-domain.h" #include "fd-util.h" #include "fileio-label.h" @@ -78,11 +79,11 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * goto fail; } - r = link_update_rtnl(l, mm); + r = link_process_rtnl(l, mm); if (r < 0) goto fail; - r = link_update_monitor(l); + r = link_update(l); if (r < 0) goto fail; @@ -95,6 +96,7 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * case RTM_DELLINK: if (l) { log_debug("Removing link %i/%s", l->ifindex, l->name); + link_remove_user(l); link_free(l); } @@ -279,7 +281,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void * sd_network_monitor_flush(m->network_monitor); HASHMAP_FOREACH(l, m->links, i) { - r = link_update_monitor(l); + r = link_update(l); if (r < 0) log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex); } @@ -540,6 +542,8 @@ int manager_new(Manager **ret) { (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m); (void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m); + manager_cleanup_saved_user(m); + *ret = m; m = NULL; @@ -1269,3 +1273,58 @@ void manager_flush_caches(Manager *m) { log_info("Flushed all caches."); } + +void manager_cleanup_saved_user(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r; + + assert(m); + + /* Clean up all saved per-link files in /run/systemd/resolve/netif/ that don't have a matching interface + * anymore. These files are created to persist settings pushed in by the user via the bus, so that resolved can + * be restarted without losing this data. */ + + d = opendir("/run/systemd/resolve/netif/"); + if (!d) { + if (errno == ENOENT) + return; + + log_warning_errno(errno, "Failed to open interface directory: %m"); + return; + } + + FOREACH_DIRENT_ALL(de, d, log_error_errno(errno, "Failed to read interface directory: %m")) { + _cleanup_free_ char *p = NULL; + int ifindex; + Link *l; + + if (!IN_SET(de->d_type, DT_UNKNOWN, DT_REG)) + continue; + + if (STR_IN_SET(de->d_name, ".", "..")) + continue; + + r = parse_ifindex(de->d_name, &ifindex); + if (r < 0) /* Probably some temporary file from a previous run. Delete it */ + goto rm; + + l = hashmap_get(m->links, INT_TO_PTR(ifindex)); + if (!l) /* link vanished */ + goto rm; + + if (l->is_managed) /* now managed by networkd, hence the bus settings are useless */ + goto rm; + + continue; + + rm: + p = strappend("/run/systemd/resolve/netif/", de->d_name); + if (!p) { + log_oom(); + return; + } + + (void) unlink(p); + } +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index c9e6ac9d4f..eee45c94ef 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -172,3 +172,5 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource bool manager_routable(Manager *m, int family); void manager_flush_caches(Manager *m); + +void manager_cleanup_saved_user(Manager *m); -- cgit v1.2.3-54-g00ecf From 43dcc86a137b5c1192eca67c345b73a9ccc4dccb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 22:41:56 +0200 Subject: sd-bus: make sure bus_map_all_properties() handle booleans right sd-bus generally exposes bools as "int" instead of "bool" in the public API. This is relevant when unmarshaling booleans, as the relevant functions expect an int* pointer and no bool* pointer. Since sizeof(bool) is not necessarily the same as sizeof(int) this is problematic and might result in memory corruption. Let's fix this, and make sure bus_map_all_properties() handles booleans as ints, as the rest of sd-bus, and make all users of it expect the right thing. --- src/login/loginctl.c | 4 ++-- src/shared/bus-util.c | 2 +- src/timedate/timedatectl.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 0fc2720b43..0fc33cf541 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -290,7 +290,7 @@ typedef struct SessionStatusInfo { char *seat; char *tty; char *display; - bool remote; + int remote; char *remote_host; char *remote_user; char *service; @@ -304,7 +304,7 @@ typedef struct SessionStatusInfo { typedef struct UserStatusInfo { uid_t uid; - bool linger; + int linger; char *name; struct dual_timestamp timestamp; char *state; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 8e3307dc24..52410999cf 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1048,7 +1048,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ case SD_BUS_TYPE_BOOLEAN: { unsigned b; - bool *p = userdata; + int *p = userdata; r = sd_bus_message_read_basic(m, type, &b); if (r < 0) diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 7f61cf0181..553ef67011 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -57,11 +57,11 @@ typedef struct StatusInfo { char *timezone; usec_t rtc_time; - bool rtc_local; + int rtc_local; - bool ntp_enabled; - bool ntp_capable; - bool ntp_synced; + int ntp_enabled; + int ntp_capable; + int ntp_synced; } StatusInfo; static void status_info_clear(StatusInfo *info) { -- cgit v1.2.3-54-g00ecf From 0a0fc27b80796c603cb64728b38c55f8f2084f36 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Jun 2016 18:50:14 +0200 Subject: resolved: drop unused permit_domain_search variable from Manager object --- src/resolve/resolved-manager.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index eee45c94ef..0821904e84 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -72,7 +72,6 @@ struct Manager { LIST_HEAD(DnsSearchDomain, search_domains); unsigned n_search_domains; - bool permit_domain_search; bool need_builtin_fallbacks:1; -- cgit v1.2.3-54-g00ecf From 6ebd1e33e6ab3dd56e1aa34f4f0e17a752fb1233 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 19:32:51 +0200 Subject: resolved: explicitly refuse zone transfers using the bus API --- src/resolve/dns-type.c | 9 +++++++++ src/resolve/dns-type.h | 1 + src/resolve/resolved-bus.c | 2 ++ 3 files changed, 12 insertions(+) (limited to 'src') diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index 78d9d5733f..aaf5ed62c1 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -96,6 +96,15 @@ bool dns_type_is_valid_query(uint16_t type) { DNS_TYPE_RRSIG); } +bool dns_type_is_zone_transer(uint16_t type) { + + /* Zone transfers, either normal or incremental */ + + return IN_SET(type, + DNS_TYPE_AXFR, + DNS_TYPE_IXFR); +} + bool dns_type_is_valid_rr(uint16_t type) { /* The types valid as RR in packets (but not necessarily diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 7b79d29d7e..e675fe4ea3 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -136,6 +136,7 @@ bool dns_type_is_obsolete(uint16_t type); bool dns_type_may_wildcard(uint16_t type); bool dns_type_apex_only(uint16_t type); bool dns_type_needs_authentication(uint16_t type); +bool dns_type_is_zone_transer(uint16_t type); int dns_type_to_af(uint16_t type); bool dns_class_is_pseudo(uint16_t class); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 1fe473ff76..1f7883c067 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -647,6 +647,8 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (!dns_type_is_valid_query(type)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type); + if (dns_type_is_zone_transer(type)) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Zone transfers not permitted via this programming interface."); if (dns_type_is_obsolete(type)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type); -- cgit v1.2.3-54-g00ecf From 17c8de633faad3ac97012e066c6c6b2f71b83a67 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 21:24:46 +0200 Subject: resolved: when using the ResolveRecord() bus call, adjust TTL for caching time When we return the full RR wire data, let's make sure the TTL included in it is adjusted by the time the RR sat in the cache. As an optimization we do this only for ResolveRecord() and not for ResolveHostname() and friends, since adjusting the TTL means copying the RR object, and we don#t want to do that if there's no reason to. (ResolveHostname() and friends don't return the TTL hence there's no reason to in that case) --- src/basic/bitmap.c | 17 +++ src/basic/bitmap.h | 5 +- src/resolve/resolved-bus.c | 4 + src/resolve/resolved-dns-cache.c | 18 ++- src/resolve/resolved-dns-cache.h | 2 +- src/resolve/resolved-dns-query.c | 4 +- src/resolve/resolved-dns-query.h | 4 + src/resolve/resolved-dns-rr.c | 245 +++++++++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.h | 4 + src/resolve/resolved-dns-transaction.c | 2 +- src/resolve/resolved-dns-transaction.h | 2 + src/resolve/test-dns-packet.c | 17 +++ 12 files changed, 316 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index ad1fda0198..f4b12fc261 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -50,6 +50,23 @@ Bitmap *bitmap_new(void) { return new0(Bitmap, 1); } +Bitmap *bitmap_copy(Bitmap *b) { + Bitmap *ret; + + ret = bitmap_new(); + if (!ret) + return NULL; + + ret->bitmaps = newdup(uint64_t, b->bitmaps, b->n_bitmaps); + if (!ret->bitmaps) { + free(ret); + return NULL; + } + + ret->n_bitmaps = ret->bitmaps_allocated = b->n_bitmaps; + return ret; +} + void bitmap_free(Bitmap *b) { if (!b) return; diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index f5f8f2f018..63fdbe8bea 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -27,10 +27,9 @@ typedef struct Bitmap Bitmap; Bitmap *bitmap_new(void); - -void bitmap_free(Bitmap *b); - +Bitmap *bitmap_copy(Bitmap *b); int bitmap_ensure_allocated(Bitmap **b); +void bitmap_free(Bitmap *b); int bitmap_set(Bitmap *b, unsigned n); void bitmap_unset(Bitmap *b, unsigned n); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 1f7883c067..2ca65e6953 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -672,6 +672,10 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (r < 0) return r; + /* Let's request that the TTL is fixed up for locally cached entries, after all we return it in the wire format + * blob */ + q->clamp_ttl = true; + q->request = sd_bus_message_ref(message); q->complete = bus_method_resolve_record_complete; diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 77c42d7aad..0bb5a95188 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -790,7 +790,7 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D return NULL; } -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) { +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **ret, bool *authenticated) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; unsigned n = 0; @@ -798,6 +798,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r bool nxdomain = false; DnsCacheItem *j, *first, *nsec = NULL; bool have_authenticated = false, have_non_authenticated = false; + usec_t current; assert(c); assert(key); @@ -892,11 +893,24 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r if (!answer) return -ENOMEM; + if (clamp_ttl) + current = now(clock_boottime_or_monotonic()); + LIST_FOREACH(by_key, j, first) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + if (!j->rr) continue; - r = dns_answer_add(answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0); + if (clamp_ttl) { + rr = dns_resource_record_ref(j->rr); + + r = dns_resource_record_clamp_ttl(&rr, LESS_BY(j->until, current) / USEC_PER_SEC); + if (r < 0) + return r; + } + + r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0); if (r < 0) return r; } diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 2293718e86..22a7c17377 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -40,7 +40,7 @@ void dns_cache_flush(DnsCache *c); void dns_cache_prune(DnsCache *c); int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, bool authenticated, uint32_t nsec_ttl, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer, bool *authenticated); +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **answer, bool *authenticated); int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index ea04e58d61..8578774c37 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -154,6 +154,7 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource goto gc; } + t->clamp_ttl = c->query->clamp_ttl; return 1; gc: @@ -420,7 +421,8 @@ int dns_query_new( DnsQuery **ret, DnsQuestion *question_utf8, DnsQuestion *question_idna, - int ifindex, uint64_t flags) { + int ifindex, + uint64_t flags) { _cleanup_(dns_query_freep) DnsQuery *q = NULL; DnsResourceKey *key; diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index c2ac02f68b..53f48d462b 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -71,6 +71,10 @@ struct DnsQuery { * family */ bool suppress_unroutable_family; + + /* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */ + bool clamp_ttl; + DnsTransactionState state; unsigned n_cname_redirects; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 6a29a93a26..5687588a7d 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1532,6 +1532,232 @@ const struct hash_ops dns_resource_record_hash_ops = { .compare = dns_resource_record_compare_func, }; +DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *copy = NULL; + DnsResourceRecord *t; + + assert(rr); + + copy = dns_resource_record_new(rr->key); + if (!copy) + return NULL; + + copy->ttl = rr->ttl; + copy->expiry = rr->expiry; + copy->n_skip_labels_signer = rr->n_skip_labels_signer; + copy->n_skip_labels_source = rr->n_skip_labels_source; + copy->unparseable = rr->unparseable; + + switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { + + case DNS_TYPE_SRV: + copy->srv.priority = rr->srv.priority; + copy->srv.weight = rr->srv.weight; + copy->srv.port = rr->srv.port; + copy->srv.name = strdup(rr->srv.name); + if (!copy->srv.name) + return NULL; + break; + + case DNS_TYPE_PTR: + case DNS_TYPE_NS: + case DNS_TYPE_CNAME: + case DNS_TYPE_DNAME: + copy->ptr.name = strdup(rr->ptr.name); + if (!copy->ptr.name) + return NULL; + break; + + case DNS_TYPE_HINFO: + copy->hinfo.cpu = strdup(rr->hinfo.cpu); + if (!copy->hinfo.cpu) + return NULL; + + copy->hinfo.os = strdup(rr->hinfo.os); + if(!copy->hinfo.os) + return NULL; + break; + + case DNS_TYPE_TXT: + case DNS_TYPE_SPF: + copy->txt.items = dns_txt_item_copy(rr->txt.items); + if (!copy->txt.items) + return NULL; + break; + + case DNS_TYPE_A: + copy->a = rr->a; + break; + + case DNS_TYPE_AAAA: + copy->aaaa = rr->aaaa; + break; + + case DNS_TYPE_SOA: + copy->soa.mname = strdup(rr->soa.mname); + if (!copy->soa.mname) + return NULL; + copy->soa.rname = strdup(rr->soa.rname); + if (!copy->soa.rname) + return NULL; + copy->soa.serial = rr->soa.serial; + copy->soa.refresh = rr->soa.refresh; + copy->soa.retry = rr->soa.retry; + copy->soa.expire = rr->soa.expire; + copy->soa.minimum = rr->soa.minimum; + break; + + case DNS_TYPE_MX: + copy->mx.priority = rr->mx.priority; + copy->mx.exchange = strdup(rr->mx.exchange); + if (!copy->mx.exchange) + return NULL; + break; + + case DNS_TYPE_LOC: + copy->loc = rr->loc; + break; + + case DNS_TYPE_SSHFP: + copy->sshfp.algorithm = rr->sshfp.algorithm; + copy->sshfp.fptype = rr->sshfp.fptype; + copy->sshfp.fingerprint = memdup(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); + if (!copy->sshfp.fingerprint) + return NULL; + copy->sshfp.fingerprint_size = rr->sshfp.fingerprint_size; + break; + + case DNS_TYPE_DNSKEY: + copy->dnskey.flags = rr->dnskey.flags; + copy->dnskey.protocol = rr->dnskey.protocol; + copy->dnskey.algorithm = rr->dnskey.algorithm; + copy->dnskey.key = memdup(rr->dnskey.key, rr->dnskey.key_size); + if (!copy->dnskey.key) + return NULL; + copy->dnskey.key_size = rr->dnskey.key_size; + break; + + case DNS_TYPE_RRSIG: + copy->rrsig.type_covered = rr->rrsig.type_covered; + copy->rrsig.algorithm = rr->rrsig.algorithm; + copy->rrsig.labels = rr->rrsig.labels; + copy->rrsig.original_ttl = rr->rrsig.original_ttl; + copy->rrsig.expiration = rr->rrsig.expiration; + copy->rrsig.inception = rr->rrsig.inception; + copy->rrsig.key_tag = rr->rrsig.key_tag; + copy->rrsig.signer = strdup(rr->rrsig.signer); + if (!copy->rrsig.signer) + return NULL; + copy->rrsig.signature = memdup(rr->rrsig.signature, rr->rrsig.signature_size); + if (!copy->rrsig.signature) + return NULL; + copy->rrsig.signature_size = rr->rrsig.signature_size; + break; + + case DNS_TYPE_NSEC: + copy->nsec.next_domain_name = strdup(rr->nsec.next_domain_name); + if (!copy->nsec.next_domain_name) + return NULL; + copy->nsec.types = bitmap_copy(rr->nsec.types); + if (!copy->nsec.types) + return NULL; + break; + + case DNS_TYPE_DS: + copy->ds.key_tag = rr->ds.key_tag; + copy->ds.algorithm = rr->ds.algorithm; + copy->ds.digest_type = rr->ds.digest_type; + copy->ds.digest = memdup(rr->ds.digest, rr->ds.digest_size); + if (!copy->ds.digest) + return NULL; + copy->ds.digest_size = rr->ds.digest_size; + break; + + case DNS_TYPE_NSEC3: + copy->nsec3.algorithm = rr->nsec3.algorithm; + copy->nsec3.flags = rr->nsec3.flags; + copy->nsec3.iterations = rr->nsec3.iterations; + copy->nsec3.salt = memdup(rr->nsec3.salt, rr->nsec3.salt_size); + if (!copy->nsec3.salt) + return NULL; + copy->nsec3.salt_size = rr->nsec3.salt_size; + copy->nsec3.next_hashed_name = memdup(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size); + if (!copy->nsec3.next_hashed_name_size) + return NULL; + copy->nsec3.next_hashed_name_size = rr->nsec3.next_hashed_name_size; + copy->nsec3.types = bitmap_copy(rr->nsec3.types); + if (!copy->nsec3.types) + return NULL; + break; + + case DNS_TYPE_TLSA: + copy->tlsa.cert_usage = rr->tlsa.cert_usage; + copy->tlsa.selector = rr->tlsa.selector; + copy->tlsa.matching_type = rr->tlsa.matching_type; + copy->tlsa.data = memdup(rr->tlsa.data, rr->tlsa.data_size); + if (!copy->tlsa.data) + return NULL; + copy->tlsa.data_size = rr->tlsa.data_size; + break; + + case DNS_TYPE_CAA: + copy->caa.flags = rr->caa.flags; + copy->caa.tag = strdup(rr->caa.tag); + if (!copy->caa.tag) + return NULL; + copy->caa.value = memdup(rr->caa.value, rr->caa.value_size); + if (!copy->caa.value) + return NULL; + copy->caa.value_size = rr->caa.value_size; + break; + + case DNS_TYPE_OPT: + default: + copy->generic.data = memdup(rr->generic.data, rr->generic.data_size); + if (!copy->generic.data) + return NULL; + copy->generic.data_size = rr->generic.data_size; + break; + } + + t = copy; + copy = NULL; + + return t; +} + +int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) { + DnsResourceRecord *old_rr, *new_rr; + uint32_t new_ttl; + + assert(rr); + old_rr = *rr; + + if (old_rr->key->type == DNS_TYPE_OPT) + return -EINVAL; + + new_ttl = MIN(old_rr->ttl, max_ttl); + if (new_ttl == old_rr->ttl) + return 0; + + if (old_rr->n_ref == 1) { + /* Patch in place */ + old_rr->ttl = new_ttl; + return 1; + } + + new_rr = dns_resource_record_copy(old_rr); + if (!new_rr) + return -ENOMEM; + + new_rr->ttl = new_ttl; + + dns_resource_record_unref(*rr); + *rr = new_rr; + + return 1; +} + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { DnsTxtItem *n; @@ -1564,6 +1790,25 @@ bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) { return dns_txt_item_equal(a->items_next, b->items_next); } +DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) { + DnsTxtItem *i, *copy = NULL, *end = NULL; + + LIST_FOREACH(items, i, first) { + DnsTxtItem *j; + + j = memdup(i, offsetof(DnsTxtItem, data) + i->length + 1); + if (!j) { + dns_txt_item_free_all(copy); + return NULL; + } + + LIST_INSERT_AFTER(items, copy, end, j); + end = j; + } + + return copy; +} + static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 020a2abd77..8b2d4df9e7 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -318,6 +318,7 @@ int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const u int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name); int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b); const char* dns_resource_record_to_string(DnsResourceRecord *rr); +DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical); @@ -327,8 +328,11 @@ int dns_resource_record_source(DnsResourceRecord *rr, const char **ret); int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone); int dns_resource_record_is_synthetic(DnsResourceRecord *rr); +int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl); + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); +DnsTxtItem *dns_txt_item_copy(DnsTxtItem *i); void dns_resource_record_hash_func(const void *i, struct siphash *state); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index bcb1b6d8a7..2d1767be0a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1274,7 +1274,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { /* Let's then prune all outdated entries */ dns_cache_prune(&t->scope->cache); - r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer, &t->answer_authenticated); + r = dns_cache_lookup(&t->scope->cache, t->key, t->clamp_ttl, &t->answer_rcode, &t->answer, &t->answer_authenticated); if (r < 0) return r; if (r > 0) { diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index eaece91533..46a934a39b 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -74,6 +74,8 @@ struct DnsTransaction { bool initial_jitter_scheduled:1; bool initial_jitter_elapsed:1; + bool clamp_ttl:1; + DnsPacket *sent, *received; DnsAnswer *answer; diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 41e5c1caa5..956b155872 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -33,6 +33,19 @@ #define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) +static void verify_rr_copy(DnsResourceRecord *rr) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *copy = NULL; + const char *a, *b; + + assert_se(copy = dns_resource_record_copy(rr)); + assert_se(dns_resource_record_equal(copy, rr) > 0); + + assert_se(a = dns_resource_record_to_string(rr)); + assert_se(b = dns_resource_record_to_string(copy)); + + assert_se(streq(a, b)); +} + static uint64_t hash(DnsResourceRecord *rr) { struct siphash state; @@ -66,6 +79,8 @@ static void test_packet_from_file(const char* filename, bool canonical) { assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0); assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0); + verify_rr_copy(rr); + s = dns_resource_record_to_string(rr); assert_se(s); puts(s); @@ -78,6 +93,8 @@ static void test_packet_from_file(const char* filename, bool canonical) { assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0); assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0); + verify_rr_copy(rr); + s2 = dns_resource_record_to_string(rr); assert_se(s2); assert_se(streq(s, s2)); -- cgit v1.2.3-54-g00ecf From 501e8eb0549bb6c3f5d08b6f6c6ad7c6a34575ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 21:28:53 +0200 Subject: resolved: add dns_answer_is_empty() and dns_question_is_empty() helpers And make use of them at a few places. --- src/resolve/resolved-dns-answer.h | 4 ++++ src/resolve/resolved-dns-question.h | 4 ++++ src/resolve/resolved-dns-scope.c | 8 ++++---- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index b2b86d1772..4a92bd1150 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -87,6 +87,10 @@ static inline unsigned dns_answer_size(DnsAnswer *a) { return a ? a->n_rrs : 0; } +static inline bool dns_answer_isempty(DnsAnswer *a) { + return dns_answer_size(a) <= 0; +} + void dns_answer_dump(DnsAnswer *answer, FILE *f); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h index ea41478975..a9a1863b1e 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -56,6 +56,10 @@ static inline unsigned dns_question_size(DnsQuestion *q) { return q ? q->n_keys : 0; } +static inline bool dns_question_isempty(DnsQuestion *q) { + return dns_question_size(q) <= 0; +} + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref); #define _DNS_QUESTION_FOREACH(u, key, q) \ diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 9d484d0a48..6f56148732 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -610,9 +610,9 @@ static int dns_scope_make_reply_packet( assert(s); assert(ret); - if ((!q || q->n_keys <= 0) - && (!answer || answer->n_rrs <= 0) - && (!soa || soa->n_rrs <= 0)) + if (dns_question_isempty(q) && + dns_answer_isempty(answer) && + dns_answer_isempty(soa)) return -EINVAL; r = dns_packet_new(&p, s->protocol, 0); @@ -718,7 +718,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { return; } - assert(p->question->n_keys == 1); + assert(dns_question_size(p->question) == 1); key = p->question->keys[0]; r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative); -- cgit v1.2.3-54-g00ecf From f471bc11c694bcc486d0b6b14a486fb74609c0c1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 21:39:02 +0200 Subject: resolved: add dns_packet_add_{question,answer}() helper And make use of it at a couple of places. --- src/resolve/resolved-dns-packet.c | 31 +++++++++++++++++++++++++++++ src/resolve/resolved-dns-packet.h | 2 ++ src/resolve/resolved-dns-scope.c | 42 +++++++++++++-------------------------- 3 files changed, 47 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index b7907bb511..32978eb924 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -791,6 +791,7 @@ int dns_packet_truncate_opt(DnsPacket *p) { } int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) { + size_t saved_size, rdlength_offset, end, rdlength, rds; int r; @@ -1134,6 +1135,36 @@ fail: return r; } +int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) { + DnsResourceKey *key; + int r; + + assert(p); + + DNS_QUESTION_FOREACH(key, q) { + r = dns_packet_append_key(p, key, NULL); + if (r < 0) + return r; + } + + return 0; +} + +int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) { + DnsResourceRecord *rr; + int r; + + assert(p); + + DNS_ANSWER_FOREACH(rr, a) { + r = dns_packet_append_rr(p, rr, NULL, NULL); + if (r < 0) + return r; + } + + return 0; +} + int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) { assert(p); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 416335d0a2..fe2b386297 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -183,6 +183,8 @@ int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compressio int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start); int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start); +int dns_packet_append_question(DnsPacket *p, DnsQuestion *q); +int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a); void dns_packet_truncate(DnsPacket *p, size_t sz); int dns_packet_truncate_opt(DnsPacket *p); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 6f56148732..275189aeb7 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -578,6 +578,7 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in } int dns_scope_llmnr_membership(DnsScope *s, bool b) { + assert(s); if (s->protocol != DNS_PROTOCOL_LLMNR) return 0; @@ -586,6 +587,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) { } int dns_scope_mdns_membership(DnsScope *s, bool b) { + assert(s); if (s->protocol != DNS_PROTOCOL_MDNS) return 0; @@ -604,7 +606,6 @@ static int dns_scope_make_reply_packet( DnsPacket **ret) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - unsigned i; int r; assert(s); @@ -631,35 +632,20 @@ static int dns_scope_make_reply_packet( 0 /* (cd) */, rcode)); - if (q) { - for (i = 0; i < q->n_keys; i++) { - r = dns_packet_append_key(p, q->keys[i], NULL); - if (r < 0) - return r; - } - - DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys); - } - - if (answer) { - for (i = 0; i < answer->n_rrs; i++) { - r = dns_packet_append_rr(p, answer->items[i].rr, NULL, NULL); - if (r < 0) - return r; - } - - DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs); - } + r = dns_packet_append_question(p, q); + if (r < 0) + return r; + DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q)); - if (soa) { - for (i = 0; i < soa->n_rrs; i++) { - r = dns_packet_append_rr(p, soa->items[i].rr, NULL, NULL); - if (r < 0) - return r; - } + r = dns_packet_append_answer(p, answer); + if (r < 0) + return r; + DNS_PACKET_HEADER(p)->ancount = htobe16(dns_answer_size(answer)); - DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs); - } + r = dns_packet_append_answer(p, soa); + if (r < 0) + return r; + DNS_PACKET_HEADER(p)->arcount = htobe16(dns_answer_size(soa)); *ret = p; p = NULL; -- cgit v1.2.3-54-g00ecf From f2ed4c696a39d746ea2d47dec105f19e59f5a9c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 21:57:57 +0200 Subject: resolved: extend dns_packet_append_opt() so that it can set the extended rcode We don't make use of this yet, but later work will. --- src/resolve/resolved-dns-packet.c | 8 +++++--- src/resolve/resolved-dns-packet.h | 5 +++-- src/resolve/resolved-dns-server.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 32978eb924..2cf07a628b 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -676,13 +676,15 @@ fail: } /* Append the OPT pseudo-RR described in RFC6891 */ -int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start) { +int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start) { size_t saved_size; int r; assert(p); /* we must never advertise supported packet size smaller than the legacy max */ assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX); + assert(rcode >= 0); + assert(rcode <= _DNS_RCODE_MAX); if (p->opt_start != (size_t) -1) return -EBUSY; @@ -701,13 +703,13 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, si if (r < 0) goto fail; - /* maximum udp packet that can be received */ + /* class: maximum udp packet that can be received */ r = dns_packet_append_uint16(p, max_udp_size, NULL); if (r < 0) goto fail; /* extended RCODE and VERSION */ - r = dns_packet_append_uint16(p, 0, NULL); + r = dns_packet_append_uint16(p, ((uint16_t) rcode & 0x0FF0) << 4, NULL); if (r < 0) goto fail; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index fe2b386297..1216bcb72d 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -182,7 +182,7 @@ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonica int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start); -int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start); +int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start); int dns_packet_append_question(DnsPacket *p, DnsQuestion *q); int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a); @@ -234,7 +234,8 @@ enum { DNS_RCODE_BADNAME = 20, DNS_RCODE_BADALG = 21, DNS_RCODE_BADTRUNC = 22, - _DNS_RCODE_MAX_DEFINED + _DNS_RCODE_MAX_DEFINED, + _DNS_RCODE_MAX = 4095 /* 4 bit rcode in the header plus 8 bit rcode in OPT, makes 12 bit */ }; const char* dns_rcode_to_string(int i) _const_; diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 5acfcb4239..bcbfa69aff 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -517,7 +517,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature else packet_size = server->received_udp_packet_max; - return dns_packet_append_opt(packet, packet_size, edns_do, NULL); + return dns_packet_append_opt(packet, packet_size, edns_do, 0, NULL); } int dns_server_ifindex(const DnsServer *s) { -- cgit v1.2.3-54-g00ecf From 2a3900d7e484faefb14fd868d5c17ae2e7b2f21f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jun 2016 21:59:17 +0200 Subject: resolved: use DNS_{QUESTION|ANSWER}_FOREACH macros at two more places --- src/resolve/resolved-dns-scope.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 275189aeb7..66e763cb7d 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -654,17 +654,17 @@ static int dns_scope_make_reply_packet( } static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) { - unsigned n; + DnsResourceRecord *rr; + DnsResourceKey *key; assert(s); assert(p); - if (p->question) - for (n = 0; n < p->question->n_keys; n++) - dns_zone_verify_conflicts(&s->zone, p->question->keys[n]); - if (p->answer) - for (n = 0; n < p->answer->n_rrs; n++) - dns_zone_verify_conflicts(&s->zone, p->answer->items[n].rr->key); + DNS_QUESTION_FOREACH(key, p->question) + dns_zone_verify_conflicts(&s->zone, key); + + DNS_ANSWER_FOREACH(rr, p->answer) + dns_zone_verify_conflicts(&s->zone, rr->key); } void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { -- cgit v1.2.3-54-g00ecf From b30bf55d5c9942f15f27a641c2c34bbb646ec981 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jun 2016 00:58:47 +0200 Subject: resolved: respond to local resolver requests on 127.0.0.53:53 In order to improve compatibility with local clients that speak DNS directly (and do not use NSS or our bus API) listen locally on 127.0.0.53:53 and process any queries made that way. Note that resolved does not implement a full DNS server on this port, but simply enough to allow normal, local clients to resolve RRs through resolved. Specifically it does not implement queries without the RD bit set (these are requests where recursive lookups are explicitly disabled), and neither queries with DNSSEC DO set in combination with DNSSEC CD (i.e. DNSSEC lookups with validation turned off). It also refuses zone transfers and obsolete RR types. All lookups done this way will be rejected with a clean error code, so that the client side can repeat the query with a reduced feature set. The code will set the DNSSEC AD flag however, depending on whether the data resolved has been validated (or comes from a local, trusted source). Lookups made via this mechanisms are propagated to LLMNR and mDNS as necessary, but this is only partially useful as DNS packets cannot carry IP scope data (i.e. the ifindex), and hence link-local addresses returned cannot be used properly (and given that LLMNR/mDNS are mostly about link-local communication this is quite a limitation). Also, given that DNS tends to use IDNA for non-ASCII names, while LLMNR/mDNS uses UTF-8 lookups cannot be mapped 1:1. In general this should improve compatibility with clients bypassing NSS but it is highly recommended for clients to instead use NSS or our native bus API. This patch also beefs up the DnsStream logic, as it reuses the code for local TCP listening. DnsStream now provides proper reference counting for its objects. In order to avoid feedback loops resolved will no silently ignore 127.0.0.53 specified as DNS server when reading configuration. resolved listens on 127.0.0.53:53 instead of 127.0.0.1:53 in order to leave the latter free for local, external DNS servers or forwarders. This also changes the "etc.conf" tmpfiles snippet to create a symlink from /etc/resolv.conf to /usr/lib/systemd/resolv.conf by default, thus making this stub the default mode of operation if /etc is not populated. --- Makefile.am | 8 +- src/resolve/resolv.conf | 11 + src/resolve/resolved-conf.c | 4 + src/resolve/resolved-dns-packet.c | 44 ++- src/resolve/resolved-dns-packet.h | 31 +- src/resolve/resolved-dns-query.c | 10 + src/resolve/resolved-dns-query.h | 4 + src/resolve/resolved-dns-rr.h | 7 + src/resolve/resolved-dns-scope.c | 37 ++- src/resolve/resolved-dns-server.c | 14 + src/resolve/resolved-dns-server.h | 2 + src/resolve/resolved-dns-stream.c | 29 +- src/resolve/resolved-dns-stream.h | 23 +- src/resolve/resolved-dns-stub.c | 572 +++++++++++++++++++++++++++++++++ src/resolve/resolved-dns-stub.h | 31 ++ src/resolve/resolved-dns-transaction.c | 13 +- src/resolve/resolved-link-bus.c | 3 + src/resolve/resolved-llmnr.c | 33 +- src/resolve/resolved-manager.c | 62 +++- src/resolve/resolved-manager.h | 9 +- src/resolve/resolved-resolv-conf.c | 11 +- src/resolve/resolved.c | 13 +- tmpfiles.d/etc.conf.m4 | 2 +- units/systemd-resolved.service.m4.in | 2 +- 24 files changed, 896 insertions(+), 79 deletions(-) create mode 100644 src/resolve/resolv.conf create mode 100644 src/resolve/resolved-dns-stub.c create mode 100644 src/resolve/resolved-dns-stub.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 3c13acf28d..c7e4c20c49 100644 --- a/Makefile.am +++ b/Makefile.am @@ -125,6 +125,7 @@ dist_systemunit_DATA_busnames = dist_sysusers_DATA = check_PROGRAMS = check_DATA = +dist_rootlibexec_DATA = tests= manual_tests = TEST_EXTENSIONS = .py @@ -5147,7 +5148,7 @@ systemd_export_LDADD = \ $(ZLIB_LIBS) \ -lbz2 -dist_rootlibexec_DATA = \ +dist_rootlibexec_DATA += \ src/import/import-pubring.gpg nodist_systemunit_DATA += \ @@ -5259,6 +5260,8 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-stream.c \ src/resolve/resolved-dns-trust-anchor.h \ src/resolve/resolved-dns-trust-anchor.c \ + src/resolve/resolved-dns-stub.h \ + src/resolve/resolved-dns-stub.c \ src/resolve/resolved-etc-hosts.h \ src/resolve/resolved-etc-hosts.c \ src/shared/gcrypt-util.c \ @@ -5411,6 +5414,9 @@ EXTRA_DIST += \ units/systemd-resolved.service.m4.in \ src/resolve/resolved.conf.in +dist_rootlibexec_DATA += \ + src/resolve/resolv.conf + # ------------------------------------------------------------------------------ if ENABLE_NETWORKD rootlibexec_PROGRAMS += \ diff --git a/src/resolve/resolv.conf b/src/resolve/resolv.conf new file mode 100644 index 0000000000..b8034d6829 --- /dev/null +++ b/src/resolve/resolv.conf @@ -0,0 +1,11 @@ +# This is a static resolv.conf file for connecting local clients to +# systemd-resolved via its DNS stub listener on 127.0.0.53. +# +# Third party programs must not access this file directly, but only through the +# symlink at /etc/resolv.conf. To manage resolv.conf(5) in a different way, +# replace this symlink by a static file or a different symlink. +# +# See systemd-resolved.service(8) for details about the supported modes of +# operation for /etc/resolv.conf. + +nameserver 127.0.0.53 diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index fecf7ecccf..dd233e7c4a 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -37,6 +37,10 @@ int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char if (r < 0) return r; + /* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */ + if (!dns_server_address_valid(family, &address)) + return 0; + /* Filter out duplicates */ s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex); if (s) { diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 2cf07a628b..ea0be56d98 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -264,6 +264,7 @@ int dns_packet_validate_query(DnsPacket *p) { switch (p->protocol) { case DNS_PROTOCOL_LLMNR: + case DNS_PROTOCOL_DNS: /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */ if (DNS_PACKET_QDCOUNT(p) != 1) return -EBADMSG; @@ -719,9 +720,8 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, in goto fail; /* RDLENGTH */ - - if (edns0_do) { - /* If DO is on, also append RFC6975 Algorithm data */ + if (edns0_do & !DNS_PACKET_QR(p)) { + /* If DO is on and this is not a reply, also append RFC6975 Algorithm data */ static const uint8_t rfc6975[] = { @@ -752,7 +752,6 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, in r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL); } else r = dns_packet_append_uint16(p, 0, NULL); - if (r < 0) goto fail; @@ -2062,8 +2061,10 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { assert(rr->key->type == DNS_TYPE_OPT); /* Check that the version is 0 */ - if (((rr->ttl >> 16) & UINT32_C(0xFF)) != 0) - return false; + if (((rr->ttl >> 16) & UINT32_C(0xFF)) != 0) { + *rfc6975 = false; + return true; /* if it's not version 0, it's OK, but we will ignore the OPT field contents */ + } p = rr->opt.data; l = rr->opt.data_size; @@ -2186,16 +2187,27 @@ int dns_packet_extract(DnsPacket *p) { continue; } - if (has_rfc6975) { - /* If the OPT RR contains RFC6975 algorithm data, then this is indication that - * the server just copied the OPT it got from us (which contained that data) - * back into the reply. If so, then it doesn't properly support EDNS, as - * RFC6975 makes it very clear that the algorithm data should only be contained - * in questions, never in replies. Crappy Belkin routers copy the OPT data for - * example, hence let's detect this so that we downgrade early. */ - log_debug("OPT RR contained RFC6975 data, ignoring."); - bad_opt = true; - continue; + if (DNS_PACKET_QR(p)) { + /* Additional checks for responses */ + + if (!DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(rr)) { + /* If this is a reply and we don't know the EDNS version then something + * is weird... */ + log_debug("EDNS version newer that our request, bad server."); + return -EBADMSG; + } + + if (has_rfc6975) { + /* If the OPT RR contains RFC6975 algorithm data, then this is indication that + * the server just copied the OPT it got from us (which contained that data) + * back into the reply. If so, then it doesn't properly support EDNS, as + * RFC6975 makes it very clear that the algorithm data should only be contained + * in questions, never in replies. Crappy Belkin routers copy the OPT data for + * example, hence let's detect this so that we downgrade early. */ + log_debug("OPT RR contained RFC6975 data, ignoring."); + bad_opt = true; + continue; + } } p->opt = dns_resource_record_ref(rr); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 1216bcb72d..7b7d4e14c9 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -118,6 +118,8 @@ static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { #define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1) #define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1) +#define DNS_PACKET_FLAG_TC (UINT16_C(1) << 9) + static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) { uint16_t rcode; @@ -126,7 +128,34 @@ static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) { else rcode = 0; - return rcode | (be16toh(DNS_PACKET_HEADER(p)->flags) & 15); + return rcode | (be16toh(DNS_PACKET_HEADER(p)->flags) & 0xF); +} + +static inline uint16_t DNS_PACKET_PAYLOAD_SIZE_MAX(DnsPacket *p) { + + /* Returns the advertised maximum datagram size for replies, or the DNS default if there's nothing defined. */ + + if (p->opt) + return MAX(DNS_PACKET_UNICAST_SIZE_MAX, p->opt->key->class); + + return DNS_PACKET_UNICAST_SIZE_MAX; +} + +static inline bool DNS_PACKET_DO(DnsPacket *p) { + if (!p->opt) + return false; + + return !!(p->opt->ttl & (1U << 15)); +} + +static inline bool DNS_PACKET_VERSION_SUPPORTED(DnsPacket *p) { + /* Returns true if this packet is in a version we support. Which means either non-EDNS or EDNS(0), but not EDNS + * of any newer versions */ + + if (!p->opt) + return true; + + return DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(p->opt); } /* LLMNR defines some bits differently */ diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 8578774c37..c8af5579f0 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -404,6 +404,16 @@ DnsQuery *dns_query_free(DnsQuery *q) { sd_bus_message_unref(q->request); sd_bus_track_unref(q->bus_track); + dns_packet_unref(q->request_dns_packet); + + if (q->request_dns_stream) { + /* Detach the stream from our query, in case something else keeps a reference to it. */ + q->request_dns_stream->complete = NULL; + q->request_dns_stream->on_packet = NULL; + q->request_dns_stream->query = NULL; + dns_stream_unref(q->request_dns_stream); + } + free(q->request_address_string); if (q->manager) { diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 53f48d462b..49a35b846b 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -99,6 +99,10 @@ struct DnsQuery { unsigned block_all_complete; char *request_address_string; + /* DNS stub information */ + DnsPacket *request_dns_packet; + DnsStream *request_dns_stream; + /* Completion callback */ void (*complete)(DnsQuery* q); unsigned block_ready; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 8b2d4df9e7..42d39a1251 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -282,6 +282,13 @@ static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(DnsResourceRecord *rr) { return rr->wire_format_size - rr->wire_format_rdata_offset; } +static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(DnsResourceRecord *rr) { + assert(rr); + assert(rr->key->type == DNS_TYPE_OPT); + + return ((rr->ttl >> 16) & 0xFF) == 0; +} + DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name); DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname); int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 66e763cb7d..ed0c6aa105 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -232,7 +232,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { if (fd < 0) return fd; - r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, p); + r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, NULL, p); if (r < 0) return r; @@ -257,7 +257,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { if (fd < 0) return fd; - r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, p); + r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, NULL, p); if (r < 0) return r; @@ -668,11 +668,11 @@ static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) { } void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { - _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; DnsResourceKey *key = NULL; bool tentative = false; - int r, fd; + int r; assert(s); assert(p); @@ -694,7 +694,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { r = dns_packet_extract(p); if (r < 0) { - log_debug_errno(r, "Failed to extract resources from incoming packet: %m"); + log_debug_errno(r, "Failed to extract resource records from incoming packet: %m"); return; } @@ -724,9 +724,21 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { return; } - if (stream) + if (stream) { r = dns_stream_write_packet(stream, reply); - else { + if (r < 0) { + log_debug_errno(r, "Failed to enqueue reply packet: %m"); + return; + } + + /* Let's take an extra reference on this stream, so that it stays around after returning. The reference + * will be dangling until the stream is disconnected, and the default completion handler of the stream + * will then unref the stream and destroy it */ + if (DNS_STREAM_QUEUED(stream)) + dns_stream_ref(stream); + } else { + int fd; + if (!ratelimit_test(&s->ratelimit)) return; @@ -748,12 +760,11 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { * verified uniqueness for all records. Also see RFC * 4795, Section 2.7 */ - r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply); - } - - if (r < 0) { - log_debug_errno(r, "Failed to send reply packet: %m"); - return; + r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, NULL, reply); + if (r < 0) { + log_debug_errno(r, "Failed to send reply packet: %m"); + return; + } } } diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index bcbfa69aff..7226111c07 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -21,6 +21,7 @@ #include "alloc-util.h" #include "resolved-dns-server.h" +#include "resolved-dns-stub.h" #include "resolved-resolv-conf.h" #include "siphash24.h" #include "string-table.h" @@ -750,6 +751,19 @@ void manager_next_dns_server(Manager *m) { manager_set_dns_server(m, m->dns_servers); } +bool dns_server_address_valid(int family, const union in_addr_union *sa) { + + /* Refuses the 0 IP addresses as well as 127.0.0.53 (which is our own DNS stub) */ + + if (in_addr_is_null(family, sa)) + return false; + + if (family == AF_INET && sa->in.s_addr == htobe32(INADDR_DNS_STUB)) + return false; + + return true; +} + static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = { [DNS_SERVER_SYSTEM] = "system", [DNS_SERVER_FALLBACK] = "fallback", diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 463c5724a7..7d07fa3e29 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -141,6 +141,8 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s); DnsServer *manager_get_dns_server(Manager *m); void manager_next_dns_server(Manager *m); +bool dns_server_address_valid(int family, const union in_addr_union *sa); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref); extern const struct hash_ops dns_server_hash_ops; diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index a1040aeff4..dd0e0b90e3 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -56,8 +56,8 @@ static int dns_stream_complete(DnsStream *s, int error) { if (s->complete) s->complete(s, error); - else - dns_stream_free(s); + else /* the default action if no completion function is set is to close the stream */ + dns_stream_unref(s); return 0; } @@ -323,10 +323,16 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use return 0; } -DnsStream *dns_stream_free(DnsStream *s) { +DnsStream *dns_stream_unref(DnsStream *s) { if (!s) return NULL; + assert(s->n_ref > 0); + s->n_ref--; + + if (s->n_ref > 0) + return NULL; + dns_stream_stop(s); if (s->manager) { @@ -339,13 +345,23 @@ DnsStream *dns_stream_free(DnsStream *s) { free(s); - return 0; + return NULL; } -DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_unref); + +DnsStream *dns_stream_ref(DnsStream *s) { + if (!s) + return NULL; + + assert(s->n_ref > 0); + s->n_ref++; + + return s; +} int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) { - _cleanup_(dns_stream_freep) DnsStream *s = NULL; + _cleanup_(dns_stream_unrefp) DnsStream *s = NULL; int r; assert(m); @@ -358,6 +374,7 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) { if (!s) return -ENOMEM; + s->n_ref = 1; s->fd = -1; s->protocol = protocol; diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h index 5ccc842249..e6569678fa 100644 --- a/src/resolve/resolved-dns-stream.h +++ b/src/resolve/resolved-dns-stream.h @@ -26,8 +26,16 @@ typedef struct DnsStream DnsStream; #include "resolved-dns-packet.h" #include "resolved-dns-transaction.h" +/* Streams are used by three subsystems: + * + * 1. The normal transaction logic when doing a DNS or LLMNR lookup via TCP + * 2. The LLMNR logic when accepting a TCP-based lookup + * 3. The DNS stub logic when accepting a TCP-based lookup + */ + struct DnsStream { Manager *manager; + int n_ref; DnsProtocol protocol; @@ -50,12 +58,23 @@ struct DnsStream { int (*on_packet)(DnsStream *s); int (*complete)(DnsStream *s, int error); - DnsTransaction *transaction; + DnsTransaction *transaction; /* when used by the transaction logic */ + DnsQuery *query; /* when used by the DNS stub logic */ LIST_FIELDS(DnsStream, streams); }; int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd); -DnsStream *dns_stream_free(DnsStream *s); +DnsStream *dns_stream_unref(DnsStream *s); +DnsStream *dns_stream_ref(DnsStream *s); int dns_stream_write_packet(DnsStream *s, DnsPacket *p); + +static inline bool DNS_STREAM_QUEUED(DnsStream *s) { + assert(s); + + if (s->fd < 0) /* already stopped? */ + return false; + + return !!s->write_packet; +} diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c new file mode 100644 index 0000000000..d263cedcd9 --- /dev/null +++ b/src/resolve/resolved-dns-stub.c @@ -0,0 +1,572 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "fd-util.h" +#include "resolved-dns-stub.h" +#include "socket-util.h" + +/* The MTU of the loopback device is 64K on Linux, advertise that as maximum datagram size, but subtract the Ethernet, + * IP and UDP header sizes */ +#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U) + +static int dns_stub_make_reply_packet( + uint16_t id, + int rcode, + DnsQuestion *q, + DnsAnswer *answer, + bool add_opt, /* add an OPT RR to this packet */ + bool edns0_do, /* set the EDNS0 DNSSEC OK bit */ + bool ad, /* set the DNSSEC authenticated data bit */ + DnsPacket **ret) { + + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + DnsResourceRecord *rr; + unsigned c = 0; + int r; + + /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence + * roundtrips aren't expensive. */ + + r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); + if (r < 0) + return r; + + /* If the client didn't do EDNS, clamp the rcode to 4 bit */ + if (!add_opt && rcode > 0xF) + rcode = DNS_RCODE_SERVFAIL; + + DNS_PACKET_HEADER(p)->id = id; + DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( + 1 /* qr */, + 0 /* opcode */, + 0 /* aa */, + 0 /* tc */, + 1 /* rd */, + 1 /* ra */, + ad /* ad */, + 0 /* cd */, + rcode)); + + r = dns_packet_append_question(p, q); + if (r < 0) + return r; + DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q)); + + DNS_ANSWER_FOREACH(rr, answer) { + r = dns_question_matches_rr(q, rr, NULL); + if (r < 0) + return r; + if (r > 0) + goto add; + + r = dns_question_matches_cname_or_dname(q, rr, NULL); + if (r < 0) + return r; + if (r > 0) + goto add; + + continue; + add: + r = dns_packet_append_rr(p, rr, NULL, NULL); + if (r < 0) + return r; + + c++; + } + DNS_PACKET_HEADER(p)->ancount = htobe16(c); + + if (add_opt) { + r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL); + if (r < 0) + return r; + } + + *ret = p; + p = NULL; + + return 0; +} + +static void dns_stub_detach_stream(DnsStream *s) { + assert(s); + + s->complete = NULL; + s->on_packet = NULL; + s->query = NULL; +} + +static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *reply) { + int r; + + assert(m); + assert(p); + assert(reply); + + if (s) + r = dns_stream_write_packet(s, reply); + else { + int fd; + + /* Truncate the message to the right size */ + if (reply->size > DNS_PACKET_PAYLOAD_SIZE_MAX(p)) { + dns_packet_truncate(reply, DNS_PACKET_UNICAST_SIZE_MAX); + DNS_PACKET_HEADER(reply)->flags = htobe16(be16toh(DNS_PACKET_HEADER(reply)->flags) | DNS_PACKET_FLAG_TC); + } + + fd = manager_dns_stub_udp_fd(m); + if (fd < 0) + return log_debug_errno(fd, "Failed to get reply socket: %m"); + + /* Note that it is essential here that we explicitly choose the source IP address for this packet. This + * is because otherwise the kernel will choose it automatically based on the routing table and will + * thus pick 127.0.0.1 rather than 127.0.0.53. */ + + r = manager_send(m, fd, LOOPBACK_IFINDEX, p->family, &p->sender, p->sender_port, &p->destination, reply); + } + if (r < 0) + return log_debug_errno(r, "Failed to send reply packet: %m"); + + return 0; +} + +static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + int r; + + assert(m); + assert(p); + + r = dns_stub_make_reply_packet(DNS_PACKET_ID(p), rcode, p->question, NULL, !!p->opt, DNS_PACKET_DO(p), false, &reply); + if (r < 0) + return log_debug_errno(r, "Failed to build failure packet: %m"); + + return dns_stub_send(m, s, p, reply); +} + +static void dns_stub_query_complete(DnsQuery *q) { + int r; + + assert(q); + assert(q->request_dns_packet); + + switch (q->state) { + + case DNS_TRANSACTION_SUCCESS: { + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + + r = dns_stub_make_reply_packet( + DNS_PACKET_ID(q->request_dns_packet), + q->answer_rcode, + q->question_idna, + q->answer, + !!q->request_dns_packet->opt, + DNS_PACKET_DO(q->request_dns_packet), + DNS_PACKET_DO(q->request_dns_packet) && q->answer_authenticated, + &reply); + if (r < 0) { + log_debug_errno(r, "Failed to build reply packet: %m"); + break; + } + + (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, reply); + break; + } + + case DNS_TRANSACTION_RCODE_FAILURE: + (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode); + break; + + case DNS_TRANSACTION_NOT_FOUND: + (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_NXDOMAIN); + break; + + case DNS_TRANSACTION_TIMEOUT: + case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: + /* Propagate a timeout as a no packet, i.e. that the client also gets a timeout */ + break; + + case DNS_TRANSACTION_NO_SERVERS: + case DNS_TRANSACTION_INVALID_REPLY: + case DNS_TRANSACTION_ERRNO: + case DNS_TRANSACTION_ABORTED: + case DNS_TRANSACTION_DNSSEC_FAILED: + case DNS_TRANSACTION_NO_TRUST_ANCHOR: + case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED: + case DNS_TRANSACTION_NETWORK_DOWN: + (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL); + break; + + case DNS_TRANSACTION_NULL: + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: + default: + assert_not_reached("Impossible state"); + } + + /* If there's a packet to write set, let's leave the stream around */ + if (q->request_dns_stream && DNS_STREAM_QUEUED(q->request_dns_stream)) { + + /* Detach the stream from our query (make it an orphan), but do not drop the reference to it. The + * default completion action of the stream will drop the reference. */ + + dns_stub_detach_stream(q->request_dns_stream); + q->request_dns_stream = NULL; + } + + dns_query_free(q); +} + +static int dns_stub_stream_complete(DnsStream *s, int error) { + assert(s); + + log_debug_errno(error, "DNS TCP connection terminated, destroying query: %m"); + + assert(s->query); + dns_query_free(s->query); + + return 0; +} + +static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { + DnsQuery *q = NULL; + int r; + + assert(m); + assert(p); + assert(p->protocol == DNS_PROTOCOL_DNS); + + /* Takes ownership of the *s stream object */ + + if (in_addr_is_localhost(p->family, &p->sender) <= 0 || + in_addr_is_localhost(p->family, &p->destination) <= 0) { + log_error("Got packet on unexpected IP range, refusing."); + dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL); + goto fail; + } + + r = dns_packet_extract(p); + if (r < 0) { + log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m"); + dns_stub_send_failure(m, s, p, DNS_RCODE_FORMERR); + goto fail; + } + + if (!DNS_PACKET_VERSION_SUPPORTED(p)) { + log_debug("Got EDNS OPT field with unsupported version number."); + dns_stub_send_failure(m, s, p, DNS_RCODE_BADVERS); + goto fail; + } + + if (dns_type_is_obsolete(p->question->keys[0]->type)) { + log_debug("Got message with obsolete key type, refusing."); + dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP); + goto fail; + } + + if (dns_type_is_zone_transer(p->question->keys[0]->type)) { + log_debug("Got request for zone transfer, refusing."); + dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP); + goto fail; + } + + if (!DNS_PACKET_RD(p)) { + /* If the "rd" bit is off (i.e. recursion was not requested), then refuse operation */ + log_debug("Got request with recursion disabled, refusing."); + dns_stub_send_failure(m, s, p, DNS_RCODE_REFUSED); + goto fail; + } + + if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) { + log_debug("Got request with DNSSEC CD bit set, refusing."); + dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP); + goto fail; + } + + r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_NO_CNAME); + if (r < 0) { + log_error_errno(r, "Failed to generate query object: %m"); + dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL); + goto fail; + } + + /* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */ + q->clamp_ttl = true; + + q->request_dns_packet = dns_packet_ref(p); + q->request_dns_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */ + q->complete = dns_stub_query_complete; + + if (s) { + s->on_packet = NULL; + s->complete = dns_stub_stream_complete; + s->query = q; + } + + r = dns_query_go(q); + if (r < 0) { + log_error_errno(r, "Failed to start query: %m"); + dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL); + goto fail; + } + + log_info("Processing query..."); + return; + +fail: + if (s && DNS_STREAM_QUEUED(s)) + dns_stub_detach_stream(s); + + dns_query_free(q); +} + +static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + Manager *m = userdata; + int r; + + r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p); + if (r <= 0) + return r; + + if (dns_packet_validate_query(p) > 0) { + log_debug("Got DNS stub UDP query packet for id %u", DNS_PACKET_ID(p)); + + dns_stub_process_query(m, NULL, p); + } else + log_debug("Invalid DNS stub UDP packet, ignoring."); + + return 0; +} + +int manager_dns_stub_udp_fd(Manager *m) { + static const int one = 1; + + union sockaddr_union sa = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(53), + .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB), + }; + + int r; + + if (m->dns_stub_udp_fd >= 0) + return m->dns_stub_udp_fd; + + m->dns_stub_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->dns_stub_udp_fd < 0) + return -errno; + + r = setsockopt(m->dns_stub_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->dns_stub_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->dns_stub_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* Make sure no traffic from outside the local host can leak to onto this socket */ + r = setsockopt(m->dns_stub_udp_fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->dns_stub_udp_fd, &sa.sa, sizeof(sa.in)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, m->dns_stub_udp_fd, EPOLLIN, on_dns_stub_packet, m); + if (r < 0) + goto fail; + + (void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp"); + + return m->dns_stub_udp_fd; + +fail: + m->dns_stub_udp_fd = safe_close(m->dns_stub_udp_fd); + return r; +} + +static int on_dns_stub_stream_packet(DnsStream *s) { + assert(s); + assert(s->read_packet); + + if (dns_packet_validate_query(s->read_packet) > 0) { + log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(s->read_packet)); + + dns_stub_process_query(s->manager, s, s->read_packet); + } else + log_debug("Invalid DNS stub TCP packet, ignoring."); + + /* Drop the reference to the stream. Either a query was created and added its own reference to the stream now, + * or that didn't happen in which case we want to free the stream */ + dns_stream_unref(s); + + return 0; +} + +static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + DnsStream *stream; + Manager *m = userdata; + int cfd, r; + + cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (cfd < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return -errno; + } + + r = dns_stream_new(m, &stream, DNS_PROTOCOL_DNS, cfd); + if (r < 0) { + safe_close(cfd); + return r; + } + + stream->on_packet = on_dns_stub_stream_packet; + + /* We let the reference to the stream dangling here, it will either be dropped by the default "complete" action + * of the stream, or by our packet callback, or when the manager is shut down. */ + + return 0; +} + +int manager_dns_stub_tcp_fd(Manager *m) { + static const int one = 1; + + union sockaddr_union sa = { + .in.sin_family = AF_INET, + .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB), + .in.sin_port = htobe16(53), + }; + + int r; + + if (m->dns_stub_tcp_fd >= 0) + return m->dns_stub_tcp_fd; + + m->dns_stub_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->dns_stub_tcp_fd < 0) + return -errno; + + r = setsockopt(m->dns_stub_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->dns_stub_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->dns_stub_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->dns_stub_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* Make sure no traffic from outside the local host can leak to onto this socket */ + r = setsockopt(m->dns_stub_tcp_fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->dns_stub_tcp_fd, &sa.sa, sizeof(sa.in)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = listen(m->dns_stub_tcp_fd, SOMAXCONN); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, m->dns_stub_tcp_fd, EPOLLIN, on_dns_stub_stream, m); + if (r < 0) + goto fail; + + (void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp"); + + return m->dns_stub_tcp_fd; + +fail: + m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_fd); + return r; +} + +int manager_dns_stub_start(Manager *m) { + int r; + + assert(m); + + r = manager_dns_stub_udp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + r = manager_dns_stub_tcp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + return 0; + +eaddrinuse: + log_warning("Another process is already listening on 127.0.0.53:53. Turning off local DNS stub support."); + manager_dns_stub_stop(m); + + return 0; +} + +void manager_dns_stub_stop(Manager *m) { + assert(m); + + m->dns_stub_udp_event_source = sd_event_source_unref(m->dns_stub_udp_event_source); + m->dns_stub_tcp_event_source = sd_event_source_unref(m->dns_stub_tcp_event_source); + + m->dns_stub_udp_fd = safe_close(m->dns_stub_udp_fd); + m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_fd); +} diff --git a/src/resolve/resolved-dns-stub.h b/src/resolve/resolved-dns-stub.h new file mode 100644 index 0000000000..fce4d25ede --- /dev/null +++ b/src/resolve/resolved-dns-stub.h @@ -0,0 +1,31 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "resolved-manager.h" + +/* 127.0.0.53 in native endian */ +#define INADDR_DNS_STUB ((in_addr_t) 0x7f000035U) + +int manager_dns_stub_udp_fd(Manager *m); +int manager_dns_stub_tcp_fd(Manager *m); + +void manager_dns_stub_stop(Manager *m); +int manager_dns_stub_start(Manager *m); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 2d1767be0a..09f60d3e76 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -60,7 +60,14 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { static void dns_transaction_close_connection(DnsTransaction *t) { assert(t); - t->stream = dns_stream_free(t->stream); + if (t->stream) { + /* Let's detach the stream from our transaction, in case something else keeps a reference to it. */ + t->stream->complete = NULL; + t->stream->on_packet = NULL; + t->stream->transaction = NULL; + t->stream = dns_stream_unref(t->stream); + } + t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source); t->dns_udp_fd = safe_close(t->dns_udp_fd); } @@ -444,7 +451,7 @@ static int on_stream_complete(DnsStream *s, int error) { t = s->transaction; p = dns_packet_ref(s->read_packet); - t->stream = dns_stream_free(t->stream); + dns_transaction_close_connection(t); if (ERRNO_IS_DISCONNECT(error)) { usec_t usec; @@ -556,7 +563,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { r = dns_stream_write_packet(t->stream, t->sent); if (r < 0) { - t->stream = dns_stream_free(t->stream); + t->stream = dns_stream_unref(t->stream); return r; } diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index acce8682de..364812250f 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -230,6 +230,9 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ if (sz != FAMILY_ADDRESS_SIZE(family)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + if (!dns_server_address_valid(family, d)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + r = sd_bus_message_exit_container(message); if (r < 0) return r; diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 8b1d71a3eb..3516af58ee 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -91,18 +91,19 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u DnsScope *scope; int r; + assert(s); + assert(fd >= 0); + assert(m); + r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p); if (r <= 0) return r; scope = manager_find_scope(m, p); - if (!scope) { + if (!scope) log_warning("Got LLMNR UDP packet on unknown scope. Ignoring."); - return 0; - } - - if (dns_packet_validate_reply(p) > 0) { - log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p)); + else if (dns_packet_validate_reply(p) > 0) { + log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p)); dns_scope_check_conflicts(scope, p); @@ -111,7 +112,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u dns_transaction_process_reply(t, p); } else if (dns_packet_validate_query(p) > 0) { - log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p)); + log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p)); dns_scope_process_query(scope, NULL, p); } else @@ -283,25 +284,19 @@ static int on_llmnr_stream_packet(DnsStream *s) { DnsScope *scope; assert(s); + assert(s->read_packet); scope = manager_find_scope(s->manager, s->read_packet); - if (!scope) { + if (!scope) log_warning("Got LLMNR TCP packet on unknown scope. Ignoring."); - return 0; - } - - if (dns_packet_validate_query(s->read_packet) > 0) { - log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet)); + else if (dns_packet_validate_query(s->read_packet) > 0) { + log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s->read_packet)); dns_scope_process_query(scope, s, s->read_packet); - - /* If no reply packet was set, we free the stream */ - if (s->write_packet) - return 0; } else - log_debug("Invalid LLMNR TCP packet."); + log_debug("Invalid LLMNR TCP packet, ignoring."); - dns_stream_free(s); + dns_stream_unref(s); return 0; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index e8811fa1d8..30036049da 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -36,6 +36,7 @@ #include "random-util.h" #include "resolved-bus.h" #include "resolved-conf.h" +#include "resolved-dns-stub.h" #include "resolved-etc-hosts.h" #include "resolved-llmnr.h" #include "resolved-manager.h" @@ -493,6 +494,7 @@ int manager_new(Manager **ret) { m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1; m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1; m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1; + m->dns_stub_udp_fd = m->dns_stub_tcp_fd = -1; m->hostname_fd = -1; m->llmnr_support = RESOLVE_SUPPORT_YES; @@ -555,6 +557,10 @@ int manager_start(Manager *m) { assert(m); + r = manager_dns_stub_start(m); + if (r < 0) + return r; + r = manager_llmnr_start(m); if (r < 0) return r; @@ -584,6 +590,11 @@ Manager *manager_free(Manager *m) { dns_scope_free(m->unicast_scope); + /* At this point only orphaned streams should remain. All others should have been freed already by their + * owners */ + while (m->dns_streams) + dns_stream_unref(m->dns_streams); + hashmap_free(m->links); hashmap_free(m->dns_transactions); @@ -595,6 +606,7 @@ Manager *manager_free(Manager *m) { manager_llmnr_stop(m); manager_mdns_stop(m); + manager_dns_stub_stop(m); sd_bus_slot_unref(m->prepare_for_sleep_slot); sd_event_source_unref(m->bus_retry_event_source); @@ -809,7 +821,14 @@ int manager_write(Manager *m, int fd, DnsPacket *p) { return 0; } -static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) { +static int manager_ipv4_send( + Manager *m, + int fd, + int ifindex, + const struct in_addr *destination, + uint16_t port, + const struct in_addr *source, + DnsPacket *p) { union sockaddr_union sa = { .in.sin_family = AF_INET, }; @@ -822,14 +841,14 @@ static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_ad assert(m); assert(fd >= 0); - assert(addr); + assert(destination); assert(port > 0); assert(p); iov.iov_base = DNS_PACKET_DATA(p); iov.iov_len = p->size; - sa.in.sin_addr = *addr; + sa.in.sin_addr = *destination; sa.in.sin_port = htobe16(port), mh.msg_iov = &iov; @@ -853,12 +872,23 @@ static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_ad pi = (struct in_pktinfo*) CMSG_DATA(cmsg); pi->ipi_ifindex = ifindex; + + if (source) + pi->ipi_spec_dst = *source; } return sendmsg_loop(fd, &mh, 0); } -static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) { +static int manager_ipv6_send( + Manager *m, + int fd, + int ifindex, + const struct in6_addr *destination, + uint16_t port, + const struct in6_addr *source, + DnsPacket *p) { + union sockaddr_union sa = { .in6.sin6_family = AF_INET6, }; @@ -871,14 +901,14 @@ static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_a assert(m); assert(fd >= 0); - assert(addr); + assert(destination); assert(port > 0); assert(p); iov.iov_base = DNS_PACKET_DATA(p); iov.iov_len = p->size; - sa.in6.sin6_addr = *addr; + sa.in6.sin6_addr = *destination; sa.in6.sin6_port = htobe16(port), sa.in6.sin6_scope_id = ifindex; @@ -903,24 +933,36 @@ static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_a pi = (struct in6_pktinfo*) CMSG_DATA(cmsg); pi->ipi6_ifindex = ifindex; + + if (source) + pi->ipi6_addr = *source; } return sendmsg_loop(fd, &mh, 0); } -int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) { +int manager_send( + Manager *m, + int fd, + int ifindex, + int family, + const union in_addr_union *destination, + uint16_t port, + const union in_addr_union *source, + DnsPacket *p) { + assert(m); assert(fd >= 0); - assert(addr); + assert(destination); assert(port > 0); assert(p); log_debug("Sending %s packet with id %" PRIu16 " on interface %i/%s.", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family)); if (family == AF_INET) - return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p); + return manager_ipv4_send(m, fd, ifindex, &destination->in, port, &source->in, p); if (family == AF_INET6) - return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p); + return manager_ipv6_send(m, fd, ifindex, &destination->in6, port, &source->in6, p); return -EAFNOSUPPORT; } diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 0821904e84..114fec7927 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -128,6 +128,13 @@ struct Manager { Set* etc_hosts_by_address; Hashmap* etc_hosts_by_name; usec_t etc_hosts_last, etc_hosts_mtime; + + /* Local DNS stub on 127.0.0.53:53 */ + int dns_stub_udp_fd; + int dns_stub_tcp_fd; + + sd_event_source *dns_stub_udp_event_source; + sd_event_source *dns_stub_tcp_event_source; }; /* Manager */ @@ -140,7 +147,7 @@ int manager_start(Manager *m); uint32_t manager_find_mtu(Manager *m); int manager_write(Manager *m, int fd, DnsPacket *p); -int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p); +int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *destination, uint16_t port, const union in_addr_union *source, DnsPacket *p); int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret); int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 4eb5bba660..31b25ca50f 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -194,10 +194,13 @@ static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *doma Iterator i; fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n" - "# Third party programs must not access this file directly, but\n" - "# only through the symlink at /etc/resolv.conf. To manage\n" - "# resolv.conf(5) in a different way, replace the symlink by a\n" - "# static file or a different symlink.\n\n", f); + "# This is a dynamic resolv.conf file for connecting local clients directly to\n" + "# all known DNS servers.\n#\n" + "# Third party programs must not access this file directly, but only through the\n" + "# symlink at /etc/resolv.conf. To manage resolv.conf(5) in a different way,\n" + "# replace this symlink by a static file or a different symlink.\n#\n" + "# See systemd-resolved.service(8) for details about the supported modes of\n" + "# operation for /etc/resolv.conf.\n\n", f); if (ordered_set_isempty(dns)) fputs("# No DNS servers known.\n", f); diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 3a47b82d8a..deb75f9ae5 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -67,7 +67,11 @@ int main(int argc, char *argv[]) { goto finish; } - r = drop_privileges(uid, gid, 0); + /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */ + r = drop_privileges(uid, gid, + (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */ + (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */ + (UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */); if (r < 0) goto finish; @@ -88,6 +92,13 @@ int main(int argc, char *argv[]) { /* Write finish default resolv.conf to avoid a dangling symlink */ (void) manager_write_resolv_conf(m); + /* Let's drop the remaining caps now */ + r = capability_bounding_set_drop(0, true); + if (r < 0) { + log_error_errno(r, "Failed to drop remaining caps: %m"); + goto finish; + } + sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); diff --git a/tmpfiles.d/etc.conf.m4 b/tmpfiles.d/etc.conf.m4 index ef7b9b9541..064eae94f1 100644 --- a/tmpfiles.d/etc.conf.m4 +++ b/tmpfiles.d/etc.conf.m4 @@ -14,7 +14,7 @@ m4_ifdef(`HAVE_SMACK_RUN_LABEL', t /etc/mtab - - - - security.SMACK64=_ )m4_dnl m4_ifdef(`ENABLE_RESOLVED', -L! /etc/resolv.conf - - - - ../run/systemd/resolve/resolv.conf +L! /etc/resolv.conf - - - - ../usr/lib/systemd/resolv.conf )m4_dnl C /etc/nsswitch.conf - - - - m4_ifdef(`HAVE_PAM', diff --git a/units/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in index a9cc3988ed..15ab56a066 100644 --- a/units/systemd-resolved.service.m4.in +++ b/units/systemd-resolved.service.m4.in @@ -23,7 +23,7 @@ Type=notify Restart=always RestartSec=0 ExecStart=@rootlibexecdir@/systemd-resolved -CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER +CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_NET_RAW CAP_NET_BIND_SERVICE ProtectSystem=full ProtectHome=yes WatchdogSec=3min -- cgit v1.2.3-54-g00ecf From 3f0083a264952dc79f3ae478044b79b66ed03c46 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jun 2016 13:20:02 +0200 Subject: tree-wide: some work-arounds for gcc false positives regarding uninitialized variables --- src/basic/process-util.c | 2 +- src/journal/mmap-cache.c | 4 ++-- src/network/networkd-brvlan.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 20768b715a..3afb5e0a40 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -553,7 +553,7 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) { if (errno == EINTR) continue; - return -errno; + return negative_errno(); } return 0; diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 6bcd9b6ac8..293d27053a 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -481,7 +481,7 @@ static int mmap_try_harder(MMapCache *m, void *addr, int fd, int prot, int flags if (ptr != MAP_FAILED) break; if (errno != ENOMEM) - return -errno; + return negative_errno(); r = make_room(m); if (r < 0) @@ -571,7 +571,7 @@ static int add_mmap( return 1; outofmem: - munmap(d, wsize); + (void) munmap(d, wsize); return -ENOMEM; } diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c index f621b8011b..8bc330ebae 100644 --- a/src/network/networkd-brvlan.c +++ b/src/network/networkd-brvlan.c @@ -58,7 +58,7 @@ static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint struct bridge_vlan_info br_vlan; int i, j, k, r, done, cnt; uint16_t begin, end; - bool untagged; + bool untagged = false; assert(link); assert(req); -- cgit v1.2.3-54-g00ecf From 4e68ec18669db7175a999f95b6b5b0d1908376c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jun 2016 13:20:23 +0200 Subject: tmpfiles: make sure to always initialize "r" correctly. --- src/tmpfiles/tmpfiles.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 79ccf9fad9..bfb6293b3d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2178,7 +2178,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { Iterator iterator; unsigned v = 0; Item *i; - int r; + int r = 0; assert(fn); -- cgit v1.2.3-54-g00ecf From 7351ded5b956b841872a308b8d994b51f3cdd253 Mon Sep 17 00:00:00 2001 From: Ian Lee Date: Tue, 21 Jun 2016 15:10:31 +0100 Subject: Do not ellipsize cgroups when showing slices in --full mode (#3560) Do not ellipsize cgroups when showing slices in --full mode --- src/shared/bus-unit-util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 6fc201b885..04471e2373 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1123,7 +1123,8 @@ static int dump_processes( assert(n == cg->n_children); qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func); - n_columns = MAX(LESS_BY(n_columns, 2U), 20U); + if (n_columns != 0) + n_columns = MAX(LESS_BY(n_columns, 2U), 20U); for (i = 0; i < n; i++) { _cleanup_free_ char *pp = NULL; -- cgit v1.2.3-54-g00ecf From 768c1decf9d5a4776a7c9360ed86d5795f80dce6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jun 2016 21:30:20 +0200 Subject: machinectl: interpret options placed between "shell" verb and machine name Previously, we'd stop processing of the argument list immediately when hitting the "shell" verb. However, we really should continue processing options then, until we hit the machine name. Fixes: #3472 --- src/machine/machinectl.c | 78 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 583d2a21e7..b60e3be362 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2540,35 +2540,65 @@ static int parse_argv(int argc, char *argv[]) { }; bool reorder = false; - int c, r; + int c, r, shell = -1; assert(argc >= 0); assert(argv); for (;;) { - const char * const option_string = "+hp:als:H:M:qn:o:"; + static const char option_string[] = "-hp:als:H:M:qn:o:"; c = getopt_long(argc, argv, option_string + reorder, options, NULL); - if (c < 0) { + if (c < 0) + break; + + switch (c) { + + case 1: /* getopt_long() returns 1 if "-" was the first character of the option string, and a + * non-option argument was discovered. */ + + assert(!reorder); + /* We generally are fine with the fact that getopt_long() reorders the command line, and looks * for switches after the main verb. However, for "shell" we really don't want that, since we - * want that switches passed after that are passed to the program to execute, and not processed - * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled - * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the - * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any - * further options processed. However, if it is anything else, we process the same argument - * again, but this time allow reordering. */ - - if (!reorder && optind < argc && !streq(argv[optind], "shell")) { + * want that switches specified after the machine name are passed to the program to execute, + * and not processed by us. To make this possible, we'll first invoke getopt_long() with + * reordering disabled (i.e. with the "-" prefix in the option string), looking for the first + * non-option parameter. If it's the verb "shell" we remember its position and continue + * processing options. In this case, as soon as we hit the next non-option argument we found + * the machine name, and stop further processing. If the first non-option argument is any other + * verb than "shell" we switch to normal reordering mode and continue processing arguments + * normally. */ + + if (shell >= 0) { + /* If we already found the "shell" verb on the command line, and now found the next + * non-option argument, then this is the machine name and we should stop processing + * further arguments. */ + optind --; /* don't process this argument, go one step back */ + goto done; + } + if (streq(optarg, "shell")) + /* Remember the position of the "shell" verb, and continue processing normally. */ + shell = optind - 1; + else { + int saved_optind; + + /* OK, this is some other verb. In this case, turn on reordering again, and continue + * processing normally. */ reorder = true; - optind--; - continue; + + /* We changed the option string. getopt_long() only looks at it again if we invoke it + * at least once with a reset option index. Hence, let's reset the option index here, + * then invoke getopt_long() again (ignoring what it has to say, after all we most + * likely already processed it), and the bump the option index so that we read the + * intended argument again. */ + saved_optind = optind; + optind = 0; + (void) getopt_long(argc, argv, option_string + reorder, options, NULL); + optind = saved_optind - 1; /* go one step back, process this argument again */ } break; - } - - switch (c) { case 'h': return help(0, NULL, NULL); @@ -2704,6 +2734,22 @@ static int parse_argv(int argc, char *argv[]) { } } +done: + if (shell >= 0) { + char *t; + int i; + + /* We found the "shell" verb while processing the argument list. Since we turned off reordering of the + * argument list initially let's readjust it now, and move the "shell" verb to the back. */ + + optind -= 1; /* place the option index where the "shell" verb will be placed */ + + t = argv[shell]; + for (i = shell; i < optind; i++) + argv[i] = argv[i+1]; + argv[optind] = t; + } + return 1; } -- cgit v1.2.3-54-g00ecf From 32391275c02715f76232128c49b19bb619cd9463 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 20 Jun 2016 18:54:21 +0200 Subject: pid1: initialize TERM environment variable correctly When systemd is started by the kernel, the kernel set the TERM environment variable unconditionnally to "linux" no matter the console device used. This might be an issue for dumb devices with no colors support. This patch uses default_term_for_tty() for getting a more accurate value. But it makes sure to keep the user preferences (if any) which might be passed via the kernel command line. For that purpose /proc should be mounted. --- src/core/main.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 40d7ff9be5..0a09ff514a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1294,6 +1294,35 @@ static int bump_unix_max_dgram_qlen(void) { return 1; } +static int fixup_environment(void) { + _cleanup_free_ char *term = NULL; + int r; + + /* When started as PID1, the kernel uses /dev/console + * for our stdios and uses TERM=linux whatever the + * backend device used by the console. We try to make + * a better guess here since some consoles might not + * have support for color mode for example. + * + * However if TERM was configured through the kernel + * command line then leave it alone. */ + + r = get_proc_cmdline_key("TERM=", &term); + if (r < 0) + return r; + + if (r == 0) { + term = strdup(default_term_for_tty("/dev/console") + 5); + if (!term) + return -errno; + } + + if (setenv("TERM", term, 1) < 0) + return -errno; + + return 0; +} + int main(int argc, char *argv[]) { Manager *m = NULL; int r, retval = EXIT_FAILURE; @@ -1480,6 +1509,14 @@ int main(int argc, char *argv[]) { (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); } + /* We expect the environment to be set correctly if run inside a + * container. */ + if (arg_system && detect_container() <= 0) + if (fixup_environment() < 0) { + error_message = "Failed to fix up PID1 environment"; + goto finish; + } + /* Initialize default unit */ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 3a18b60489504056f9b0b1a139439cbfa60a87e1 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 20 Jun 2016 21:45:28 +0200 Subject: pid1: initialize status color mode after setting up TERM Also we had to connect PID's stdio to null later since colors_enabled() assume that stdout is connected to the console. --- src/core/main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 0a09ff514a..6124a984c3 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1382,7 +1382,6 @@ int main(int argc, char *argv[]) { saved_argv = argv; saved_argc = argc; - log_show_color(colors_enabled()); log_set_upgrade_syslog_to_journal(true); /* Disable the umask logic */ @@ -1393,7 +1392,6 @@ int main(int argc, char *argv[]) { /* Running outside of a container as PID 1 */ arg_system = true; - make_null_stdio(); log_set_target(LOG_TARGET_KMSG); log_open(); @@ -1511,12 +1509,19 @@ int main(int argc, char *argv[]) { /* We expect the environment to be set correctly if run inside a * container. */ - if (arg_system && detect_container() <= 0) + if (arg_system && detect_container() <= 0) { if (fixup_environment() < 0) { error_message = "Failed to fix up PID1 environment"; goto finish; } + /* Try to figure out if we can use colors with the console. No + * need to do that for user instances since they never log + * into the console. */ + log_show_color(colors_enabled()); + make_null_stdio(); + } + /* Initialize default unit */ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 2787d83c28b7565ea6f80737170514e5e6186917 Mon Sep 17 00:00:00 2001 From: Minkyung Date: Wed, 22 Jun 2016 20:26:05 +0900 Subject: watchdog: Support changing watchdog_usec during runtime (#3492) Add sd_notify() parameter to change watchdog_usec during runtime. Application can change watchdog_usec value by sd_notify like this. Example. sd_notify(0, "WATCHDOG_USEC=20000000"). To reset watchdog_usec as configured value in service file, restart service. Notice. sd_event is not currently supported. If application uses sd_event_set_watchdog, or sd_watchdog_enabled, do not use "WATCHDOG_USEC" option through sd_notify. --- man/sd_notify.xml | 9 ++++++++ src/core/service.c | 56 +++++++++++++++++++++++++++++++++++++++++++++---- src/core/service.h | 2 ++ src/systemd/sd-daemon.h | 5 +++++ 4 files changed, 68 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/sd_notify.xml b/man/sd_notify.xml index bd6cfdcd29..025fbec6c1 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -250,6 +250,15 @@ restrictions, it is ignored. + + WATCHDOG_USEC=... + + Reset watchdog_usec value during runtime. + Notice that this is not available when using sd_event_set_watchdog() + or sd_watchdog_enabled(). + Example : WATCHDOG_USEC=20000000 + + It is recommended to prefix variable names that are not diff --git a/src/core/service.c b/src/core/service.c index 78c33b1530..13de671700 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -200,16 +200,27 @@ static void service_stop_watchdog(Service *s) { s->watchdog_timestamp = DUAL_TIMESTAMP_NULL; } +static usec_t service_get_watchdog_usec(Service *s) { + assert(s); + + if (s->watchdog_override_enable) + return s->watchdog_override_usec; + else + return s->watchdog_usec; +} + static void service_start_watchdog(Service *s) { int r; + usec_t watchdog_usec; assert(s); - if (s->watchdog_usec <= 0) + watchdog_usec = service_get_watchdog_usec(s); + if (watchdog_usec == 0 || watchdog_usec == USEC_INFINITY) return; if (s->watchdog_event_source) { - r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec)); + r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, watchdog_usec)); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m"); return; @@ -221,7 +232,7 @@ static void service_start_watchdog(Service *s) { UNIT(s)->manager->event, &s->watchdog_event_source, CLOCK_MONOTONIC, - usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0, + usec_add(s->watchdog_timestamp.monotonic, watchdog_usec), 0, service_dispatch_watchdog, s); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m"); @@ -246,6 +257,17 @@ static void service_reset_watchdog(Service *s) { service_start_watchdog(s); } +static void service_reset_watchdog_timeout(Service *s, usec_t watchdog_override_usec) { + assert(s); + + s->watchdog_override_enable = true; + s->watchdog_override_usec = watchdog_override_usec; + service_reset_watchdog(s); + + log_unit_debug(UNIT(s), "watchdog_usec="USEC_FMT, s->watchdog_usec); + log_unit_debug(UNIT(s), "watchdog_override_usec="USEC_FMT, s->watchdog_override_usec); +} + static void service_fd_store_unlink(ServiceFDStore *fs) { if (!fs) @@ -1992,6 +2014,9 @@ static int service_start(Unit *u) { s->notify_state = NOTIFY_UNKNOWN; + s->watchdog_override_enable = false; + s->watchdog_override_usec = 0; + service_enter_start_pre(s); return 1; } @@ -2123,6 +2148,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + if (s->watchdog_override_enable) + unit_serialize_item_format(u, f, "watchdog-override-usec", USEC_FMT, s->watchdog_override_usec); + return 0; } @@ -2317,6 +2345,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->stderr_fd = fdset_remove(fds, fd); s->exec_context.stdio_as_fds = true; } + } else if (streq(key, "watchdog-override-usec")) { + usec_t watchdog_override_usec; + if (timestamp_deserialize(value, &watchdog_override_usec) < 0) + log_unit_debug(u, "Failed to parse watchdog_override_usec value: %s", value); + else { + s->watchdog_override_enable = true; + s->watchdog_override_usec = watchdog_override_usec; + } } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -2895,12 +2931,15 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) { Service *s = SERVICE(userdata); char t[FORMAT_TIMESPAN_MAX]; + usec_t watchdog_usec; assert(s); assert(source == s->watchdog_event_source); + watchdog_usec = service_get_watchdog_usec(s); + log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!", - format_timespan(t, sizeof(t), s->watchdog_usec, 1)); + format_timespan(t, sizeof(t), watchdog_usec, 1)); service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG); @@ -3037,6 +3076,15 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) service_add_fd_store_set(s, fds, name); } + e = strv_find_startswith(tags, "WATCHDOG_USEC="); + if (e) { + usec_t watchdog_override_usec; + if (safe_atou64(e, &watchdog_override_usec) < 0) + log_unit_warning(u, "Failed to parse WATCHDOG_USEC=%s", e); + else + service_reset_watchdog_timeout(s, watchdog_override_usec); + } + /* Notify clients about changed status or main pid */ if (notify_dbus) unit_add_to_dbus_queue(u); diff --git a/src/core/service.h b/src/core/service.h index 4af3d40439..cfef375b03 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -120,6 +120,8 @@ struct Service { dual_timestamp watchdog_timestamp; usec_t watchdog_usec; + usec_t watchdog_override_usec; + bool watchdog_override_enable; sd_event_source *watchdog_event_source; ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index e6787b0a64..740b176903 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -196,6 +196,11 @@ int sd_is_mq(int fd, const char *path); invocation. This variable is only supported with sd_pid_notify_with_fds(). + WATCHDOG_USEC=... + Reset watchdog_usec value during runtime. + To reset watchdog_usec value, start the service again. + Example: "WATCHDOG_USEC=20000000" + Daemons can choose to send additional variables. However, it is recommended to prefix variable names not listed above with X_. -- cgit v1.2.3-54-g00ecf From 1e9707d495ca52f23dff4d0eb16a1c2346a0f34e Mon Sep 17 00:00:00 2001 From: Elias Probst Date: Wed, 22 Jun 2016 17:10:52 +0200 Subject: machinectl: do not escape the unit name (#3554) Otherwise starting a machine named `foo-bar-baz` will end up in machinectl attempting to start the service unit `systemd-nspawn@foo\x2dbar\x2dbaz` instead of `systemd-nspawn@foo-bar-baz`. --- src/machine/machinectl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 583d2a21e7..5ca557abbf 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1535,11 +1535,7 @@ static int make_service_name(const char *name, char **ret) { return -EINVAL; } - e = unit_name_escape(name); - if (!e) - return log_oom(); - - r = unit_name_build("systemd-nspawn", e, ".service", ret); + r = unit_name_build("systemd-nspawn", name, ".service", ret); if (r < 0) return log_error_errno(r, "Failed to build unit name: %m"); -- cgit v1.2.3-54-g00ecf From 79d4ace11e2813987d611aeae91b4f1237d98928 Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Wed, 22 Jun 2016 15:09:33 -0400 Subject: systemctl: Add missing "/" to files created by 'edit --runtime' --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0dfdae4538..38b5a7e082 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6093,7 +6093,7 @@ static int get_file_to_edit( return log_oom(); if (arg_runtime) { - run = strjoin(paths->runtime_config, name, NULL); + run = strjoin(paths->runtime_config, "/", name, NULL); if (!run) return log_oom(); } -- cgit v1.2.3-54-g00ecf From fc40065bcd098447bf570d3d71950f0435966978 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:29:33 +0200 Subject: core: when writing transient unit files, make sure all lines end with a newline This is a fix-up for 2a9a6f8ac04a69ca36d645f9305a33645f22a22b which covered non-transient units, but missed the case for transient units. --- src/core/unit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index 581962eba6..0a1a5321df 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3364,6 +3364,7 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co /* When this is a transient unit file in creation, then let's not create a new drop-in but instead * write to the transient unit file. */ fputs(data, u->transient_file); + fputc('\n', u->transient_file); return 0; } -- cgit v1.2.3-54-g00ecf From 03857c43ce099e50fbb78dd4b32eb75759b83ae0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:31:24 +0200 Subject: execute: use the return value of setrlimit_closest() properly It's a function defined by us, hence we should look for the error in its return value, not in "errno". --- src/core/execute.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 3c3369373f..ac87e334a4 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1951,12 +1951,14 @@ static int exec_child( int secure_bits = context->secure_bits; for (i = 0; i < _RLIMIT_MAX; i++) { + if (!context->rlimit[i]) continue; - if (setrlimit_closest(i, context->rlimit[i]) < 0) { + r = setrlimit_closest(i, context->rlimit[i]); + if (r < 0) { *exit_status = EXIT_LIMITS; - return -errno; + return r; } } -- cgit v1.2.3-54-g00ecf From 686d9ba614adfef22b1eedc6d1565e18e8778829 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:33:07 +0200 Subject: execute: set PR_SET_NO_NEW_PRIVS also in case the exec memory protection is used This was forgotten when MemoryDenyWriteExecute= was added: we should set NNP in all cases when we set seccomp filters. --- src/core/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index ac87e334a4..135e567222 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2017,7 +2017,7 @@ static int exec_child( } if (context->no_new_privileges || - (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter))) + (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || use_syscall_filter))) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; return -errno; -- cgit v1.2.3-54-g00ecf From abd84d4d8304590a3944eee385edbebc8dc3bda1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:35:04 +0200 Subject: execute: be a little less drastic when MemoryDenyWriteExecute= hits Let's politely refuse with EPERM rather than kill the whole thing right-away. --- src/core/execute.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 135e567222..cf52355fc4 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1237,7 +1237,7 @@ static int apply_memory_deny_write_execute(const ExecContext *c) { r = seccomp_rule_add( seccomp, - SCMP_ACT_KILL, + SCMP_ACT_ERRNO(EPERM), SCMP_SYS(mmap), 1, SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC|PROT_WRITE, PROT_EXEC|PROT_WRITE)); @@ -1246,7 +1246,7 @@ static int apply_memory_deny_write_execute(const ExecContext *c) { r = seccomp_rule_add( seccomp, - SCMP_ACT_KILL, + SCMP_ACT_ERRNO(EPERM), SCMP_SYS(mprotect), 1, SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC)); -- cgit v1.2.3-54-g00ecf From f4170c671b863a211056972a469abd416086f22c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:45:45 +0200 Subject: execute: add a new easy-to-use RestrictRealtime= option to units It takes a boolean value. If true, access to SCHED_RR, SCHED_FIFO and SCHED_DEADLINE is blocked, which my be used to lock up the system. --- man/systemd.exec.xml | 13 +++++ src/core/dbus-execute.c | 5 +- src/core/execute.c | 95 +++++++++++++++++++++++++++++++++-- src/core/execute.h | 4 +- src/core/load-fragment-gperf.gperf.m4 | 2 + 5 files changed, 114 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index dbfc7692f7..ed02666daf 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1413,6 +1413,19 @@ + + RestrictRealtime= + + Takes a boolean argument. If set, any attempts to enable realtime scheduling in a process of + the unit are refused. This restricts access to realtime task scheduling policies such as + SCHED_FIFO, SCHED_RR or SCHED_DEADLINE. See + sched7 for details about + these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods + of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It + is hence recommended to restrict access to realtime scheduling to the few programs that actually require + them. Defaults to off. + + diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4c88c41127..644b9561b5 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -720,6 +720,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -1057,7 +1058,7 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "PrivateTmp", "PrivateDevices", "PrivateNetwork", - "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute")) { + "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -1083,6 +1084,8 @@ int bus_exec_context_set_transient_property( c->syslog_level_prefix = b; else if (streq(name, "MemoryDenyWriteExecute")) c->memory_deny_write_execute = b; + else if (streq(name, "RestrictRealtime")) + c->restrict_realtime = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } diff --git a/src/core/execute.c b/src/core/execute.c index cf52355fc4..8cb18dbd5b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1264,6 +1264,76 @@ finish: return r; } +static int apply_restrict_realtime(const ExecContext *c) { + static const int permitted_policies[] = { + SCHED_OTHER, + SCHED_BATCH, + SCHED_IDLE, + }; + + scmp_filter_ctx *seccomp; + unsigned i; + int r, p, max_policy = 0; + + assert(c); + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + + /* Determine the highest policy constant we want to allow */ + for (i = 0; i < ELEMENTSOF(permitted_policies); i++) + if (permitted_policies[i] > max_policy) + max_policy = permitted_policies[i]; + + /* Go through all policies with lower values than that, and block them -- unless they appear in the + * whitelist. */ + for (p = 0; p < max_policy; p++) { + bool good = false; + + /* Check if this is in the whitelist. */ + for (i = 0; i < ELEMENTSOF(permitted_policies); i++) + if (permitted_policies[i] == p) { + good = true; + break; + } + + if (good) + continue; + + /* Deny this policy */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPERM), + SCMP_SYS(sched_setscheduler), + 1, + SCMP_A1(SCMP_CMP_EQ, p)); + if (r < 0) + goto finish; + } + + /* Blacklist all other policies, i.e. the ones with higher values. Note that all comparisons are unsigned here, + * hence no need no check for < 0 values. */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPERM), + SCMP_SYS(sched_setscheduler), + 1, + SCMP_A1(SCMP_CMP_GT, max_policy)); + if (r < 0) + goto finish; + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; +} + #endif static void do_idle_pipe_dance(int idle_pipe[4]) { @@ -1962,6 +2032,14 @@ static int exec_child( } } + /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */ + if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) { + if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) { + *exit_status = EXIT_LIMITS; + return -errno; + } + } + if (!cap_test_all(context->capability_bounding_set)) { r = capability_bounding_set_drop(context->capability_bounding_set, false); if (r < 0) { @@ -2017,7 +2095,7 @@ static int exec_child( } if (context->no_new_privileges || - (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || use_syscall_filter))) + (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || context->restrict_realtime || use_syscall_filter))) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; return -errno; @@ -2039,6 +2117,15 @@ static int exec_child( return r; } } + + if (context->restrict_realtime) { + r = apply_restrict_realtime(context); + if (r < 0) { + *exit_status = EXIT_SECCOMP; + return r; + } + } + if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { @@ -2474,7 +2561,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sProtectHome: %s\n" "%sProtectSystem: %s\n" "%sIgnoreSIGPIPE: %s\n" - "%sMemoryDenyWriteExecute: %s\n", + "%sMemoryDenyWriteExecute: %s\n" + "%sRestrictRealtime: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", @@ -2485,7 +2573,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, protect_home_to_string(c->protect_home), prefix, protect_system_to_string(c->protect_system), prefix, yes_no(c->ignore_sigpipe), - prefix, yes_no(c->memory_deny_write_execute)); + prefix, yes_no(c->memory_deny_write_execute), + prefix, yes_no(c->restrict_realtime)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); diff --git a/src/core/execute.h b/src/core/execute.h index cd1f7b36f6..210eea0e82 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -193,12 +193,14 @@ struct ExecContext { char **runtime_directory; mode_t runtime_directory_mode; + bool memory_deny_write_execute; + bool restrict_realtime; + bool oom_score_adjust_set:1; bool nice_set:1; bool ioprio_set:1; bool cpu_sched_set:1; bool no_new_privileges_set:1; - bool memory_deny_write_execute; }; #include "cgroup-util.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index eb58586523..fe1006830b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -56,11 +56,13 @@ m4_ifdef(`HAVE_SECCOMP', $1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs) $1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context) $1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute) +$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime) $1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)', `$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 +$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -- cgit v1.2.3-54-g00ecf From 4b7abb5b1186422637089f2863cb8c3705c026e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 04:10:53 +0200 Subject: build-sys: move fdset.[ch] src/basic → src/shared (#3580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes use of the sd_listen_fds() call, and as such should live in src/shared, as the distinction between src/basic and src/shared is that the latter may use libsystemd APIs, the former does not. Note that btrfs-util.[ch] and log.[ch] also include header files from libsystemd, but they only need definitions, they do not invoke any function from it. Hence they may stay in src/basic. --- Makefile.am | 6 +- src/basic/fdset.c | 273 ----------------------------------------------------- src/basic/fdset.h | 58 ------------ src/shared/fdset.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/shared/fdset.h | 58 ++++++++++++ 5 files changed, 334 insertions(+), 334 deletions(-) delete mode 100644 src/basic/fdset.c delete mode 100644 src/basic/fdset.h create mode 100644 src/shared/fdset.c create mode 100644 src/shared/fdset.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 3c13acf28d..02329284f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -836,8 +836,6 @@ libbasic_la_SOURCES = \ src/basic/ordered-set.c \ src/basic/bitmap.c \ src/basic/bitmap.h \ - src/basic/fdset.c \ - src/basic/fdset.h \ src/basic/prioq.c \ src/basic/prioq.h \ src/basic/web-util.c \ @@ -1050,7 +1048,9 @@ libshared_la_SOURCES = \ src/shared/vlan-util.h \ src/shared/vlan-util.c \ src/shared/tests.h \ - src/shared/tests.c + src/shared/tests.c \ + src/shared/fdset.c \ + src/shared/fdset.h if HAVE_UTMP libshared_la_SOURCES += \ diff --git a/src/basic/fdset.c b/src/basic/fdset.c deleted file mode 100644 index 527f27bc67..0000000000 --- a/src/basic/fdset.c +++ /dev/null @@ -1,273 +0,0 @@ -/*** - 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 . -***/ - -#include -#include -#include -#include -#include - -#include "sd-daemon.h" - -#include "fd-util.h" -#include "fdset.h" -#include "log.h" -#include "macro.h" -#include "parse-util.h" -#include "path-util.h" -#include "set.h" - -#define MAKE_SET(s) ((Set*) s) -#define MAKE_FDSET(s) ((FDSet*) s) - -FDSet *fdset_new(void) { - return MAKE_FDSET(set_new(NULL)); -} - -int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) { - unsigned i; - FDSet *s; - int r; - - assert(ret); - - s = fdset_new(); - if (!s) - return -ENOMEM; - - for (i = 0; i < n_fds; i++) { - - r = fdset_put(s, fds[i]); - if (r < 0) { - set_free(MAKE_SET(s)); - return r; - } - } - - *ret = s; - return 0; -} - -FDSet* fdset_free(FDSet *s) { - void *p; - - while ((p = set_steal_first(MAKE_SET(s)))) { - /* Valgrind's fd might have ended up in this set here, - * due to fdset_new_fill(). We'll ignore all failures - * here, so that the EBADFD that valgrind will return - * us on close() doesn't influence us */ - - /* When reloading duplicates of the private bus - * connection fds and suchlike are closed here, which - * has no effect at all, since they are only - * duplicates. So don't be surprised about these log - * messages. */ - - log_debug("Closing left-over fd %i", PTR_TO_FD(p)); - close_nointr(PTR_TO_FD(p)); - } - - set_free(MAKE_SET(s)); - return NULL; -} - -int fdset_put(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return set_put(MAKE_SET(s), FD_TO_PTR(fd)); -} - -int fdset_put_dup(FDSet *s, int fd) { - int copy, r; - - assert(s); - assert(fd >= 0); - - copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (copy < 0) - return -errno; - - r = fdset_put(s, copy); - if (r < 0) { - safe_close(copy); - return r; - } - - return copy; -} - -bool fdset_contains(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); -} - -int fdset_remove(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; -} - -int fdset_new_fill(FDSet **_s) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - FDSet *s; - - assert(_s); - - /* Creates an fdset and fills in all currently open file - * descriptors. */ - - d = opendir("/proc/self/fd"); - if (!d) - return -errno; - - s = fdset_new(); - if (!s) { - r = -ENOMEM; - goto finish; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (hidden_or_backup_file(de->d_name)) - continue; - - r = safe_atoi(de->d_name, &fd); - if (r < 0) - goto finish; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - r = fdset_put(s, fd); - if (r < 0) - goto finish; - } - - r = 0; - *_s = s; - s = NULL; - -finish: - /* We won't close the fds here! */ - if (s) - set_free(MAKE_SET(s)); - - return r; -} - -int fdset_cloexec(FDSet *fds, bool b) { - Iterator i; - void *p; - int r; - - assert(fds); - - SET_FOREACH(p, MAKE_SET(fds), i) { - r = fd_cloexec(PTR_TO_FD(p), b); - if (r < 0) - return r; - } - - return 0; -} - -int fdset_new_listen_fds(FDSet **_s, bool unset) { - int n, fd, r; - FDSet *s; - - assert(_s); - - /* Creates an fdset and fills in all passed file descriptors */ - - s = fdset_new(); - if (!s) { - r = -ENOMEM; - goto fail; - } - - n = sd_listen_fds(unset); - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { - r = fdset_put(s, fd); - if (r < 0) - goto fail; - } - - *_s = s; - return 0; - - -fail: - if (s) - set_free(MAKE_SET(s)); - - return r; -} - -int fdset_close_others(FDSet *fds) { - void *e; - Iterator i; - int *a; - unsigned j, m; - - j = 0, m = fdset_size(fds); - a = alloca(sizeof(int) * m); - SET_FOREACH(e, MAKE_SET(fds), i) - a[j++] = PTR_TO_FD(e); - - assert(j == m); - - return close_all_fds(a, j); -} - -unsigned fdset_size(FDSet *fds) { - return set_size(MAKE_SET(fds)); -} - -bool fdset_isempty(FDSet *fds) { - return set_isempty(MAKE_SET(fds)); -} - -int fdset_iterate(FDSet *s, Iterator *i) { - void *p; - - if (!set_iterate(MAKE_SET(s), i, &p)) - return -ENOENT; - - return PTR_TO_FD(p); -} - -int fdset_steal_first(FDSet *fds) { - void *p; - - p = set_steal_first(MAKE_SET(fds)); - if (!p) - return -ENOENT; - - return PTR_TO_FD(p); -} diff --git a/src/basic/fdset.h b/src/basic/fdset.h deleted file mode 100644 index 16efe5bdf2..0000000000 --- a/src/basic/fdset.h +++ /dev/null @@ -1,58 +0,0 @@ -#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 . -***/ - -#include - -#include "hashmap.h" -#include "macro.h" -#include "set.h" - -typedef struct FDSet FDSet; - -FDSet* fdset_new(void); -FDSet* fdset_free(FDSet *s); - -int fdset_put(FDSet *s, int fd); -int fdset_put_dup(FDSet *s, int fd); - -bool fdset_contains(FDSet *s, int fd); -int fdset_remove(FDSet *s, int fd); - -int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds); -int fdset_new_fill(FDSet **ret); -int fdset_new_listen_fds(FDSet **ret, bool unset); - -int fdset_cloexec(FDSet *fds, bool b); - -int fdset_close_others(FDSet *fds); - -unsigned fdset_size(FDSet *fds); -bool fdset_isempty(FDSet *fds); - -int fdset_iterate(FDSet *s, Iterator *i); - -int fdset_steal_first(FDSet *fds); - -#define FDSET_FOREACH(fd, fds, i) \ - for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i))) - -DEFINE_TRIVIAL_CLEANUP_FUNC(FDSet*, fdset_free); -#define _cleanup_fdset_free_ _cleanup_(fdset_freep) diff --git a/src/shared/fdset.c b/src/shared/fdset.c new file mode 100644 index 0000000000..527f27bc67 --- /dev/null +++ b/src/shared/fdset.c @@ -0,0 +1,273 @@ +/*** + 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 . +***/ + +#include +#include +#include +#include +#include + +#include "sd-daemon.h" + +#include "fd-util.h" +#include "fdset.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" + +#define MAKE_SET(s) ((Set*) s) +#define MAKE_FDSET(s) ((FDSet*) s) + +FDSet *fdset_new(void) { + return MAKE_FDSET(set_new(NULL)); +} + +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) { + unsigned i; + FDSet *s; + int r; + + assert(ret); + + s = fdset_new(); + if (!s) + return -ENOMEM; + + for (i = 0; i < n_fds; i++) { + + r = fdset_put(s, fds[i]); + if (r < 0) { + set_free(MAKE_SET(s)); + return r; + } + } + + *ret = s; + return 0; +} + +FDSet* fdset_free(FDSet *s) { + void *p; + + while ((p = set_steal_first(MAKE_SET(s)))) { + /* Valgrind's fd might have ended up in this set here, + * due to fdset_new_fill(). We'll ignore all failures + * here, so that the EBADFD that valgrind will return + * us on close() doesn't influence us */ + + /* When reloading duplicates of the private bus + * connection fds and suchlike are closed here, which + * has no effect at all, since they are only + * duplicates. So don't be surprised about these log + * messages. */ + + log_debug("Closing left-over fd %i", PTR_TO_FD(p)); + close_nointr(PTR_TO_FD(p)); + } + + set_free(MAKE_SET(s)); + return NULL; +} + +int fdset_put(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return set_put(MAKE_SET(s), FD_TO_PTR(fd)); +} + +int fdset_put_dup(FDSet *s, int fd) { + int copy, r; + + assert(s); + assert(fd >= 0); + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + r = fdset_put(s, copy); + if (r < 0) { + safe_close(copy); + return r; + } + + return copy; +} + +bool fdset_contains(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); +} + +int fdset_remove(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; +} + +int fdset_new_fill(FDSet **_s) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + FDSet *s; + + assert(_s); + + /* Creates an fdset and fills in all currently open file + * descriptors. */ + + d = opendir("/proc/self/fd"); + if (!d) + return -errno; + + s = fdset_new(); + if (!s) { + r = -ENOMEM; + goto finish; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (hidden_or_backup_file(de->d_name)) + continue; + + r = safe_atoi(de->d_name, &fd); + if (r < 0) + goto finish; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + r = fdset_put(s, fd); + if (r < 0) + goto finish; + } + + r = 0; + *_s = s; + s = NULL; + +finish: + /* We won't close the fds here! */ + if (s) + set_free(MAKE_SET(s)); + + return r; +} + +int fdset_cloexec(FDSet *fds, bool b) { + Iterator i; + void *p; + int r; + + assert(fds); + + SET_FOREACH(p, MAKE_SET(fds), i) { + r = fd_cloexec(PTR_TO_FD(p), b); + if (r < 0) + return r; + } + + return 0; +} + +int fdset_new_listen_fds(FDSet **_s, bool unset) { + int n, fd, r; + FDSet *s; + + assert(_s); + + /* Creates an fdset and fills in all passed file descriptors */ + + s = fdset_new(); + if (!s) { + r = -ENOMEM; + goto fail; + } + + n = sd_listen_fds(unset); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { + r = fdset_put(s, fd); + if (r < 0) + goto fail; + } + + *_s = s; + return 0; + + +fail: + if (s) + set_free(MAKE_SET(s)); + + return r; +} + +int fdset_close_others(FDSet *fds) { + void *e; + Iterator i; + int *a; + unsigned j, m; + + j = 0, m = fdset_size(fds); + a = alloca(sizeof(int) * m); + SET_FOREACH(e, MAKE_SET(fds), i) + a[j++] = PTR_TO_FD(e); + + assert(j == m); + + return close_all_fds(a, j); +} + +unsigned fdset_size(FDSet *fds) { + return set_size(MAKE_SET(fds)); +} + +bool fdset_isempty(FDSet *fds) { + return set_isempty(MAKE_SET(fds)); +} + +int fdset_iterate(FDSet *s, Iterator *i) { + void *p; + + if (!set_iterate(MAKE_SET(s), i, &p)) + return -ENOENT; + + return PTR_TO_FD(p); +} + +int fdset_steal_first(FDSet *fds) { + void *p; + + p = set_steal_first(MAKE_SET(fds)); + if (!p) + return -ENOENT; + + return PTR_TO_FD(p); +} diff --git a/src/shared/fdset.h b/src/shared/fdset.h new file mode 100644 index 0000000000..16efe5bdf2 --- /dev/null +++ b/src/shared/fdset.h @@ -0,0 +1,58 @@ +#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 . +***/ + +#include + +#include "hashmap.h" +#include "macro.h" +#include "set.h" + +typedef struct FDSet FDSet; + +FDSet* fdset_new(void); +FDSet* fdset_free(FDSet *s); + +int fdset_put(FDSet *s, int fd); +int fdset_put_dup(FDSet *s, int fd); + +bool fdset_contains(FDSet *s, int fd); +int fdset_remove(FDSet *s, int fd); + +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds); +int fdset_new_fill(FDSet **ret); +int fdset_new_listen_fds(FDSet **ret, bool unset); + +int fdset_cloexec(FDSet *fds, bool b); + +int fdset_close_others(FDSet *fds); + +unsigned fdset_size(FDSet *fds); +bool fdset_isempty(FDSet *fds); + +int fdset_iterate(FDSet *s, Iterator *i); + +int fdset_steal_first(FDSet *fds); + +#define FDSET_FOREACH(fd, fds, i) \ + for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i))) + +DEFINE_TRIVIAL_CLEANUP_FUNC(FDSet*, fdset_free); +#define _cleanup_fdset_free_ _cleanup_(fdset_freep) -- cgit v1.2.3-54-g00ecf From 3ade16c9c842bb18a5c0edb56ed8153c250ddeaf Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 23 Jun 2016 17:47:03 +0100 Subject: fstab-generator: ignore root=/dev/nfs (#3591) root=/dev/nfs is a legacy option for the kernel to handle root on NFS. Documentation for this kernel command line option can be found in the kernel source tree: Documentation/filesystems/nfs/nfsroot.txt --- src/fstab-generator/fstab-generator.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index fc7cf39847..880dc1bd2a 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -502,6 +502,12 @@ static int add_sysroot_mount(void) { return 0; } + if (streq(arg_root_what, "/dev/nfs")) { + /* This is handled by the kernel or the initrd */ + log_debug("Skipping root directory handling, as /dev/nfs was requested."); + return 0; + } + what = fstab_node_to_udev_node(arg_root_what); if (!what) return log_oom(); -- cgit v1.2.3-54-g00ecf From d001e0a3afb4c31486870e36e0c3a4bfcde20f0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 23:24:38 +0200 Subject: resolved: rework SERVFAIL handling There might be two reasons why we get a SERVFAIL response from our selected DNS server: because this DNS server itself is bad, or because the DNS server actually serving the zone upstream is bad. So far we immediately downgraded our server feature level when getting SERVFAIL, under the assumption that the first case is the only possible case. However, this meant we'd downgrade immediately even if we encountered the second case described above. With this commit handling of SERVFAIL is reworked. As soon as we get a SERVFAIL on a transaction we retry the transaction with a lower feature level, without changing the feature level tracked for the DNS server itself. If that fails too, we downgrade further, and so on. If during this downgrading the SERVFAIL goes away we assume that the DNS server we are talking to is bad, but the zone is fine and propagate the detected feature level to the information we track about the DNS server. Should the SERVFAIL not go away this way we let the transaction fail and accept the SERVFAIL. --- src/resolve/resolved-dns-server.c | 80 ++++++++++++++++------------------ src/resolve/resolved-dns-server.h | 3 +- src/resolve/resolved-dns-transaction.c | 66 ++++++++++++++++++++++------ src/resolve/resolved-dns-transaction.h | 3 ++ 4 files changed, 95 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 5acfcb4239..a9decf1158 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -244,6 +244,26 @@ static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) { assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0); } +static void dns_server_reset_counters(DnsServer *s) { + assert(s); + + s->n_failed_udp = 0; + s->n_failed_tcp = 0; + s->packet_truncated = false; + s->verified_usec = 0; + + /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the + * grace period ends, but not when lowering the possible feature level, as a lower level feature level should + * not make RRSIGs appear or OPT appear, but rather make them disappear. If the reappear anyway, then that's + * indication for a differently broken OPT/RRSIG implementation, and we really don't want to support that + * either. + * + * This is particularly important to deal with certain Belkin routers which break OPT for certain lookups (A), + * but pass traffic through for others (AAAA). If we detect the broken behaviour on one lookup we should not + * reenable it for another, because we cannot validate things anyway, given that the RRSIG/OPT data will be + * incomplete. */ +} + void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size) { assert(s); @@ -304,17 +324,6 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); } -void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level) { - assert(s); - - /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */ - - if (s->possible_feature_level != level) - return; - - s->packet_failed = true; -} - void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level) { assert(s); @@ -352,6 +361,24 @@ void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level) { s->packet_bad_opt = true; } +void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + /* Invoked whenever we got a FORMERR, SERVFAIL or NOTIMP rcode from a server and downgrading the feature level + * for the transaction made it go away. In this case we immediately downgrade to the feature level that made + * things work. */ + + if (s->verified_feature_level > level) + s->verified_feature_level = level; + + if (s->possible_feature_level > level) { + s->possible_feature_level = level; + dns_server_reset_counters(s); + } + + log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", dns_server_string(s)); +} + static bool dns_server_grace_period_expired(DnsServer *s) { usec_t ts; @@ -371,27 +398,6 @@ static bool dns_server_grace_period_expired(DnsServer *s) { return true; } -static void dns_server_reset_counters(DnsServer *s) { - assert(s); - - s->n_failed_udp = 0; - s->n_failed_tcp = 0; - s->packet_failed = false; - s->packet_truncated = false; - s->verified_usec = 0; - - /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the - * grace period ends, but not when lowering the possible feature level, as a lower level feature level should - * not make RRSIGs appear or OPT appear, but rather make them disappear. If the reappear anyway, then that's - * indication for a differently broken OPT/RRSIG implementation, and we really don't want to support that - * either. - * - * This is particularly important to deal with certain Belkin routers which break OPT for certain lookups (A), - * but pass traffic through for others (AAAA). If we detect the broken behaviour on one lookup we should not - * reenable it for another, because we cannot validate things anyway, given that the RRSIG/OPT data will be - * incomplete. */ -} - DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { assert(s); @@ -454,16 +460,6 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { log_debug("Lost too many UDP packets, downgrading feature level..."); s->possible_feature_level--; - } else if (s->packet_failed && - s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { - - /* We got a failure packet, and are at a feature level above UDP. Note that in this case we - * downgrade no further than UDP, under the assumption that a failure packet indicates an - * incompatible packet contents, but not a problem with the transport. */ - - log_debug("Got server failure, downgrading feature level..."); - s->possible_feature_level--; - } else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && s->packet_truncated && s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 463c5724a7..03ed85b3b9 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -77,7 +77,6 @@ struct DnsServer { unsigned n_failed_udp; unsigned n_failed_tcp; - bool packet_failed:1; bool packet_truncated:1; bool packet_bad_opt:1; bool packet_rrsig_missing:1; @@ -113,10 +112,10 @@ void dns_server_move_back_and_unmark(DnsServer *s); void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size); void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t usec); -void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level); DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index bcb1b6d8a7..ded2abce47 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -207,6 +207,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) t->answer_nsec_ttl = (uint32_t) -1; t->key = dns_resource_key_ref(key); t->current_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; + t->clamp_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; t->id = pick_new_id(s->manager); @@ -371,22 +372,38 @@ static int dns_transaction_pick_server(DnsTransaction *t) { assert(t); assert(t->scope->protocol == DNS_PROTOCOL_DNS); + /* Pick a DNS server and a feature level for it. */ + server = dns_scope_get_dns_server(t->scope); if (!server) return -ESRCH; + /* If we changed the server invalidate the feature level clamping, as the new server might have completely + * different properties. */ + if (server != t->server) + t->clamp_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; + t->current_feature_level = dns_server_possible_feature_level(server); + /* Clamp the feature level if that is requested. */ + if (t->clamp_feature_level != _DNS_SERVER_FEATURE_LEVEL_INVALID && + t->current_feature_level > t->clamp_feature_level) + t->current_feature_level = t->clamp_feature_level; + + log_debug("Using feature level %s for transaction %u.", dns_server_feature_level_to_string(t->current_feature_level), t->id); + if (server == t->server) return 0; dns_server_unref(t->server); t->server = dns_server_ref(server); + log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id); + return 1; } -static void dns_transaction_retry(DnsTransaction *t) { +static void dns_transaction_retry(DnsTransaction *t, bool next_server) { int r; assert(t); @@ -394,7 +411,8 @@ static void dns_transaction_retry(DnsTransaction *t) { log_debug("Retrying transaction %" PRIu16 ".", t->id); /* Before we try again, switch to a new server. */ - dns_scope_next_dns_server(t->scope); + if (next_server) + dns_scope_next_dns_server(t->scope); r = dns_transaction_go(t); if (r < 0) { @@ -460,7 +478,7 @@ static int on_stream_complete(DnsStream *s, int error) { assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level, usec - t->start_usec); - dns_transaction_retry(t); + dns_transaction_retry(t, true); return 0; } if (error != 0) { @@ -878,10 +896,22 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { /* Request failed, immediately try again with reduced features */ - log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); - dns_server_packet_failed(t->server, t->current_feature_level); - dns_transaction_retry(t); + if (t->current_feature_level <= DNS_SERVER_FEATURE_LEVEL_WORST) { + /* This was already at the lowest possible feature level? If so, we can't downgrade + * this transaction anymore, hence let's process the response, and accept the rcode. */ + log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); + break; + } + + /* Reduce this feature level by one and try again. */ + t->clamp_feature_level = t->current_feature_level - 1; + + log_debug("Server returned error %s, retrying transaction with reduced feature level %s.", + dns_rcode_to_string(DNS_PACKET_RCODE(p)), + dns_server_feature_level_to_string(t->clamp_feature_level)); + + dns_transaction_retry(t, false /* use the same server */); return; } else if (DNS_PACKET_TC(p)) dns_server_packet_truncated(t->server, t->current_feature_level); @@ -926,7 +956,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { goto fail; /* On DNS, couldn't send? Try immediately again, with a new server */ - dns_transaction_retry(t); + dns_transaction_retry(t, true); } return; @@ -939,11 +969,19 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { return; } - /* Report that the OPT RR was missing */ if (t->server) { + /* Report that we successfully received a valid packet with a good rcode after we initially got a bad + * rcode and subsequently downgraded the protocol */ + + if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN) && + t->clamp_feature_level != _DNS_SERVER_FEATURE_LEVEL_INVALID) + dns_server_packet_rcode_downgrade(t->server, t->clamp_feature_level); + + /* Report that the OPT RR was missing */ if (!p->opt) dns_server_packet_bad_opt(t->server, t->current_feature_level); + /* Report that we successfully received a packet */ dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, ts - t->start_usec, p->size); } @@ -1030,7 +1068,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_feature_level, usec - t->start_usec); - dns_transaction_retry(t); + dns_transaction_retry(t, true); return 0; } if (r < 0) { @@ -1139,7 +1177,7 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat log_debug("Timeout reached on transaction %" PRIu16 ".", t->id); - dns_transaction_retry(t); + dns_transaction_retry(t, true); return 0; } @@ -1770,8 +1808,10 @@ static bool dns_transaction_dnssec_supported(DnsTransaction *t) { if (!t->server) return true; - if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_DO) - return false; + /* Note that we do not check the feature level actually used for the transaction but instead the feature level + * the server is known to support currently, as the transaction feature level might be lower than what the + * server actually supports, since we might have downgraded this transaction's feature level because we got a + * SERVFAIL earlier and wanted to check whether downgrading fixes it. */ return dns_server_dnssec_supported(t->server); } @@ -2863,7 +2903,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { if (!dns_transaction_dnssec_supported_full(t)) { /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */ t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; - log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id); + log_debug("Not validating response for %" PRIu16 ", used server feature level does not support DNSSEC.", t->id); return 0; } diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index eaece91533..bc1529d621 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -115,6 +115,9 @@ struct DnsTransaction { /* The features of the DNS server at time of transaction start */ DnsServerFeatureLevel current_feature_level; + /* If we got SERVFAIL back, we retry the lookup, using a lower feature level than we used before. */ + DnsServerFeatureLevel clamp_feature_level; + /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction * completing. */ -- cgit v1.2.3-54-g00ecf From 6ff01a0d645e21e44fb0d6222d9d098019bcbefd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 23:36:10 +0200 Subject: resolved: when caching replies, check rcode earlier This way we don't log complaints about packets without SOA in case we are not caching it anyway because the rcode is not SUCCESS or NXDOMAIN... --- src/resolve/resolved-dns-cache.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 77c42d7aad..ba937107b6 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -624,6 +624,12 @@ int dns_cache_put( dns_cache_remove_previous(c, key, answer); + /* We only care for positive replies and NXDOMAINs, on all + * other replies we will simply flush the respective entries, + * and that's it */ + if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) + return 0; + if (dns_answer_size(answer) <= 0) { char key_str[DNS_RESOURCE_KEY_STRING_MAX]; @@ -632,12 +638,6 @@ int dns_cache_put( return 0; } - /* We only care for positive replies and NXDOMAINs, on all - * other replies we will simply flush the respective entries, - * and that's it */ - if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) - return 0; - cache_keys = dns_answer_size(answer); if (key) cache_keys++; -- cgit v1.2.3-54-g00ecf From b3c6b00a93cca0e9108cef0b63e11787c1e10fc3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 23:46:56 +0200 Subject: resolved: when processing auxiliary DNSSEC transactions, accept those with SERVFAIL Some upstream DNS servers return SERVFAIL if we ask them for DNSSEC RRs, which some forwarding DNS servers pass on to us as SERVFAIL (other though as NOERROR...). This is should not be considered a problem, as long as the domain in question didn't have DNSSEC enabled. Hence: when making use of auxiliary transactions accept those that return SERVFAIL. --- src/resolve/resolved-dns-transaction.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index ded2abce47..2b1a32b8fb 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -652,14 +652,15 @@ static int dns_transaction_dnssec_ready(DnsTransaction *t) { return 0; case DNS_TRANSACTION_RCODE_FAILURE: - if (dt->answer_rcode != DNS_RCODE_NXDOMAIN) { + if (!IN_SET(dt->answer_rcode, DNS_RCODE_NXDOMAIN, DNS_RCODE_SERVFAIL)) { log_debug("Auxiliary DNSSEC RR query failed with rcode=%s.", dns_rcode_to_string(dt->answer_rcode)); goto fail; } - /* Fall-through: NXDOMAIN is good enough for us. This is because some DNS servers erronously - * return NXDOMAIN for empty non-terminals (Akamai...), and we need to handle that nicely, when - * asking for parent SOA or similar RRs to make unsigned proofs. */ + /* Fall-through: NXDOMAIN/SERVFAIL is good enough for us. This is because some DNS servers + * erronously return NXDOMAIN/SERVFAIL for empty non-terminals (Akamai...) or missing DS + * records (Facebook), and we need to handle that nicely, when asking for parent SOA or similar + * RRs to make unsigned proofs. */ case DNS_TRANSACTION_SUCCESS: /* All good. */ -- cgit v1.2.3-54-g00ecf From ceeddf79b8464469a5307a1030862c7c4fe289e9 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 24 Jun 2016 07:54:28 +0200 Subject: resolved: add option to disable caching (#3592) In some cases, caching DNS results locally is not desirable, a it makes DNS cache poisoning attacks a tad easier and also allows users on the system to determine whether or not a particular domain got visited by another user. Thus provide a new "Cache" resolved.conf option to disable it. --- NEWS | 8 ++++++++ man/resolved.conf.xml | 17 +++++++++++++++++ src/resolve/resolved-dns-transaction.c | 4 ++++ src/resolve/resolved-gperf.gperf | 1 + src/resolve/resolved-manager.c | 1 + src/resolve/resolved-manager.h | 1 + src/resolve/resolved.conf.in | 1 + 7 files changed, 33 insertions(+) (limited to 'src') diff --git a/NEWS b/NEWS index 7ecb10e216..e4efb476c6 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,14 @@ CHANGES WITH 231: "Options=" with a drop-in, or mount /tmp from /etc/fstab with your desired options. + * systemd-resolved gained a new "Cache=" option in resolved.conf. + Local caching makes DNS poisoning attacks slightly easier and allows + a local user to detect whether any other user on the same machine has + recently visited a given DNS name (privacy). If that is a concern, + you can disable local caching with this option at the cost of slower + DNS resolution (which is particularly expensive with DNSSEC). The + default continues to be "yes" (i. e. caching is enabled). + Contributions from: ... — Somewhere, 2016-XX-XX diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 920ce9e89b..024ad6a9c1 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -202,6 +202,23 @@ + + Cache= + Takes a boolean argument. If "yes" (the default), + resolving a domain name which already got queried earlier will re-use + the previous result as long as that is still valid, and thus does not + need to do an actual network request. + + However, local caching slightly increases the chance of a + successful DNS poisoning attack, and might also be a privacy problem in + some environments: By measuring the time it takes to resolve a + particular network name, a user can determine whether any other user on + the same machine recently visited that name. If either of these is a + concern, you may disable the local caching. Be aware that this comes at + a performance cost, which is very high with DNSSEC. + + + diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 09f60d3e76..06e7145422 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -590,6 +590,10 @@ static void dns_transaction_cache_answer(DnsTransaction *t) { if (!IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) return; + /* Caching disabled? */ + if (!t->scope->manager->enable_cache) + return; + /* We never cache if this packet is from the local host, under * the assumption that a locally running DNS server would * cache this anyway, and probably knows better when to flush diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 82f26215df..2fd56bce26 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -19,3 +19,4 @@ Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0 Resolve.Domains, config_parse_search_domains, 0, 0 Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support) Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode) +Resolve.Cache, config_parse_bool, 0, offsetof(Manager, enable_cache) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 30036049da..add463b6a9 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -500,6 +500,7 @@ int manager_new(Manager **ret) { m->llmnr_support = RESOLVE_SUPPORT_YES; m->mdns_support = RESOLVE_SUPPORT_NO; m->dnssec_mode = DEFAULT_DNSSEC_MODE; + m->enable_cache = true; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 114fec7927..deebd8e484 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -46,6 +46,7 @@ struct Manager { ResolveSupport llmnr_support; ResolveSupport mdns_support; DnssecMode dnssec_mode; + bool enable_cache; /* Network */ Hashmap *links; diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index a288588924..3bd8389c88 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -17,3 +17,4 @@ #Domains= #LLMNR=yes #DNSSEC=@DEFAULT_DNSSEC_MODE@ +#Cache=yes -- cgit v1.2.3-54-g00ecf From 39c38ce17c3a15f7b709536a6d7f1f7e093ac450 Mon Sep 17 00:00:00 2001 From: Doug Christman Date: Fri, 24 Jun 2016 02:00:35 -0400 Subject: systemctl: Create new unit files with "edit --force" (#3584) --- TODO | 4 +--- man/systemctl.xml | 6 ++++++ src/systemctl/systemctl.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/TODO b/TODO index 8de1029b9b..0d18e0734b 100644 --- a/TODO +++ b/TODO @@ -197,9 +197,7 @@ Features: * systemctl: if some operation fails, show log output? -* systemctl edit: -- allow creation of units from scratch -- use equvalent of cat() to insert existing config as a comment, prepended with #. +* systemctl edit: use equvalent of cat() to insert existing config as a comment, prepended with #. Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc. * exponential backoff in timesyncd when we cannot reach a server diff --git a/man/systemctl.xml b/man/systemctl.xml index 914af929c8..742da81cfe 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -481,6 +481,9 @@ When used with enable, overwrite any existing conflicting symlinks. + When used with edit, create all of the + specified units which do not already exist. + When used with halt, poweroff, reboot or kexec, execute the selected operation without shutting down all units. However, all processes will be killed forcibly and all file systems are unmounted or remounted read-only. This is hence a @@ -1303,6 +1306,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service If is specified, this will copy the original units instead of creating drop-in files. + If is specified and any units do + not already exist, new unit files will be opened for editing. + If is specified, the changes will be made temporarily in /run and they will be lost on the next reboot. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 38b5a7e082..0a8e60c195 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2499,7 +2499,7 @@ static int unit_find_paths( r = 1; } - if (r == 0) + if (r == 0 && !arg_force) log_error("No files found for %s.", unit_name); return r; @@ -6070,7 +6070,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t); } else if (r < 0) - return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t); + return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path); *ret_tmp_fn = t; t = NULL; @@ -6114,9 +6114,10 @@ static int get_file_to_edit( return 0; } -static int unit_file_create_dropin( +static int unit_file_create_new( const LookupPaths *paths, const char *unit_name, + const char *suffix, char **ret_new_path, char **ret_tmp_path) { @@ -6127,7 +6128,7 @@ static int unit_file_create_dropin( assert(ret_new_path); assert(ret_tmp_path); - ending = strjoina(unit_name, ".d/override.conf"); + ending = strjoina(unit_name, suffix); r = get_file_to_edit(paths, ending, &tmp_new_path); if (r < 0) return r; @@ -6180,7 +6181,6 @@ static int unit_file_create_copy( r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path); if (r < 0) { - log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path); free(tmp_new_path); return r; } @@ -6291,18 +6291,26 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { r = unit_find_paths(bus, *name, &lp, &path, NULL); if (r < 0) return r; - else if (r == 0) - return -ENOENT; - else if (!path) { - // FIXME: support units with path==NULL (no FragmentPath) - log_error("No fragment exists for %s.", *name); - return -ENOENT; + else if (!arg_force) { + if (r == 0) { + log_error("Run 'systemctl edit --force %s' to create a new unit.", *name); + return -ENOENT; + } else if (!path) { + // FIXME: support units with path==NULL (no FragmentPath) + log_error("No fragment exists for %s.", *name); + return -ENOENT; + } + } + + if (path) { + if (arg_full) + r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); + else + r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path); + } else { + r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path); } - if (arg_full) - r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); - else - r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 2b40998d3c02ff4097373150cb47776ced0be315 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 15:59:24 +0200 Subject: cgroup: minor coding style fix --- src/core/cgroup.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 799296ad28..932160d276 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -36,8 +36,7 @@ #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC) -static void cgroup_compat_warn(void) -{ +static void cgroup_compat_warn(void) { static bool cgroup_compat_warned = false; if (cgroup_compat_warned) @@ -50,7 +49,7 @@ static void cgroup_compat_warn(void) #define log_cgroup_compat(unit, fmt, ...) do { \ cgroup_compat_warn(); \ log_unit_debug(unit, "cgroup-compat: " fmt, ##__VA_ARGS__); \ - } while (0) + } while (false) void cgroup_context_init(CGroupContext *c) { assert(c); -- cgit v1.2.3-54-g00ecf From 5816a84352e19492df61036d26eff0eb00f2d8c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 15:59:42 +0200 Subject: machined: don't bother explicitly closing the errno pipe There's no point in explicitly closing the errno pipe, if we exit right after anyway. It doesn't hurt doing this either, but let's do this the same way for all cases where we use the "Operation" object right now, and in all other cases we do not close the pipe explicitly, hence don't do so here either. --- src/machine/machine-dbus.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index de5d98f23e..f50f363ba3 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1200,8 +1200,6 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro child_fail: (void) write(errno_pipe_fd[1], &r, sizeof(r)); - errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - _exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 03c2b2889fa2d090d7953e28124ec5d00898289d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 16:01:14 +0200 Subject: machined: "machinectl clean" can take a while, do it asynchronously from a background process This is a follow-up to 5d2036b5f3506bd0ff07042aee8d69c26db32298, and also makes the "machinectl clean" verb asynchronous, after all it's little more than a series of image removals. The changes required to make this happen are a bit more comprehensive as we need to pass information about deleted images back to the client, as well as information about the image we failed on if we failed on one. Hence, create a temporary file in /tmp, serialize that data into, and read it from the parent after the operation is complete. --- src/basic/fileio.c | 41 +++++++++ src/basic/fileio.h | 2 + src/machine/image-dbus.c | 4 +- src/machine/machine-dbus.c | 2 +- src/machine/machinectl.c | 19 ++-- src/machine/machined-dbus.c | 214 ++++++++++++++++++++++++++++++++++++-------- src/machine/operation.c | 41 ++++++--- src/machine/operation.h | 4 +- 8 files changed, 272 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 29f5374222..0360a8eab3 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1354,3 +1354,44 @@ int link_tmpfile(int fd, const char *path, const char *target) { return 0; } + +int read_nul_string(FILE *f, char **ret) { + _cleanup_free_ char *x = NULL; + size_t allocated = 0, n = 0; + + assert(f); + assert(ret); + + /* Reads a NUL-terminated string from the specified file. */ + + for (;;) { + int c; + + if (!GREEDY_REALLOC(x, allocated, n+2)) + return -ENOMEM; + + c = fgetc(f); + if (c == 0) /* Terminate at NUL byte */ + break; + if (c == EOF) { + if (ferror(f)) + return -errno; + break; /* Terminate at EOF */ + } + + x[n++] = (char) c; + } + + if (x) + x[n] = 0; + else { + x = new0(char, 1); + if (!x) + return -ENOMEM; + } + + *ret = x; + x = NULL; + + return 0; +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 58dbc80c24..9ac497d9eb 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -86,3 +86,5 @@ int open_tmpfile_unlinkable(const char *directory, int flags); int open_tmpfile_linkable(const char *target, int flags, char **ret_path); int link_tmpfile(int fd, const char *path, const char *target); + +int read_nul_string(FILE *f, char **ret); diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 0eed9b81bb..867bbc467b 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -81,7 +81,7 @@ int bus_image_method_remove( errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - r = operation_new(m, NULL, child, message, errno_pipe_fd[0]); + r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL); if (r < 0) { (void) sigkill_wait(child); return r; @@ -193,7 +193,7 @@ int bus_image_method_clone( errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - r = operation_new(m, NULL, child, message, errno_pipe_fd[0]); + r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL); if (r < 0) { (void) sigkill_wait(child); return r; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index f50f363ba3..ba7ac04b56 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1207,7 +1207,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro /* Copying might take a while, hence install a watch on the child, and return */ - r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]); + r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL); if (r < 0) { (void) sigkill_wait(child); return r; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 5ca557abbf..d68c50b203 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2375,7 +2375,7 @@ static int set_limit(int argc, char *argv[], void *userdata) { } static int clean_images(int argc, char *argv[], void *userdata) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; uint64_t usage, total = 0; char fb[FORMAT_BYTES_MAX]; @@ -2384,15 +2384,22 @@ static int clean_images(int argc, char *argv[], void *userdata) { unsigned c = 0; int r; - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", - "CleanPool", - &error, - &reply, - "s", arg_all ? "all" : "hidden"); + "CleanPool"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", arg_all ? "all" : "hidden"); + if (r < 0) + return bus_log_create_error(r); + + /* This is a slow operation, hence permit a longer time for completion. */ + r = sd_bus_call(bus, m, USEC_INFINITY, &error, &reply); if (r < 0) return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r)); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 31efa3695b..52ce83a185 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -29,6 +29,7 @@ #include "bus-util.h" #include "cgroup-util.h" #include "fd-util.h" +#include "fileio.h" #include "formats-util.h" #include "hostname-util.h" #include "image-dbus.h" @@ -822,22 +823,106 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata, return bus_image_method_mark_read_only(message, i, error); } +static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_fclose_ FILE *f = NULL; + bool success; + size_t n; + int r; + + assert(operation); + assert(operation->extra_fd >= 0); + + if (lseek(operation->extra_fd, 0, SEEK_SET) == (off_t) -1) + return -errno; + + f = fdopen(operation->extra_fd, "re"); + if (!f) + return -errno; + + operation->extra_fd = -1; + + /* The resulting temporary file starts with a boolean value that indicates success or not. */ + errno = 0; + n = fread(&success, 1, sizeof(success), f); + if (n != sizeof(success)) + return ret < 0 ? ret : (errno != 0 ? -errno : -EIO); + + if (ret < 0) { + _cleanup_free_ char *name = NULL; + + /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean + * set to false followed by the name of the failed image. Let's try to read this and use it for the + * error message. If we can't read it, don't mind, and return the naked error. */ + + if (success) /* The resulting temporary file could not be updated, ignore it. */ + return ret; + + r = read_nul_string(f, &name); + if (r < 0 || isempty(name)) /* Same here... */ + return ret; + + return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name); + } + + assert(success); + + r = sd_bus_message_new_method_return(operation->message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + /* On success the resulting temporary file will contain a list of image names that were removed followed by + * their size on disk. Let's read that and turn it into a bus message. */ + for (;;) { + _cleanup_free_ char *name = NULL; + uint64_t size; + + r = read_nul_string(f, &name); + if (r < 0) + return r; + if (isempty(name)) /* reached the end */ + break; + + errno = 0; + n = fread(&size, 1, sizeof(size), f); + if (n != sizeof(size)) + return errno != 0 ? -errno : -EIO; + + r = sd_bus_message_append(reply, "(st)", name, size); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) { enum { REMOVE_ALL, REMOVE_HIDDEN, } mode; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(image_hashmap_freep) Hashmap *images = NULL; + _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; + _cleanup_close_ int result_fd = -1; Manager *m = userdata; - Image *image; + Operation *operation; const char *mm; - Iterator i; + pid_t child; int r; assert(message); + if (m->n_operations >= OPERATIONS_MAX) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations."); + r = sd_bus_message_read(message, "s", &mm); if (r < 0) return r; @@ -863,50 +948,109 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err if (r == 0) return 1; /* Will call us back */ - images = hashmap_new(&string_hash_ops); - if (!images) - return -ENOMEM; + if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m"); - r = image_discover(images); - if (r < 0) - return r; + /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this + * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this + * continously */ + result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC); + if (result_fd < 0) + return -errno; - r = sd_bus_message_new_method_return(message, &reply); - if (r < 0) - return r; + /* This might be a slow operation, run it asynchronously in a background process */ + child = fork(); + if (child < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); - r = sd_bus_message_open_container(reply, 'a', "(st)"); - if (r < 0) - return r; + if (child == 0) { + _cleanup_(image_hashmap_freep) Hashmap *images = NULL; + bool success = true; + Image *image; + Iterator i; + ssize_t l; - HASHMAP_FOREACH(image, images, i) { + errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - /* We can't remove vendor images (i.e. those in /usr) */ - if (IMAGE_IS_VENDOR(image)) - continue; + images = hashmap_new(&string_hash_ops); + if (!images) { + r = -ENOMEM; + goto child_fail; + } - if (IMAGE_IS_HOST(image)) - continue; + r = image_discover(images); + if (r < 0) + goto child_fail; - if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image)) - continue; + l = write(result_fd, &success, sizeof(success)); + if (l < 0) { + r = -errno; + goto child_fail; + } - r = image_remove(image); - if (r == -EBUSY) /* keep images that are currently being used. */ - continue; - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name); + HASHMAP_FOREACH(image, images, i) { - r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive); - if (r < 0) - return r; + /* We can't remove vendor images (i.e. those in /usr) */ + if (IMAGE_IS_VENDOR(image)) + continue; + + if (IMAGE_IS_HOST(image)) + continue; + + if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image)) + continue; + + r = image_remove(image); + if (r == -EBUSY) /* keep images that are currently being used. */ + continue; + if (r < 0) { + /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */ + success = false; + (void) ftruncate(result_fd, 0); + (void) lseek(result_fd, 0, SEEK_SET); + (void) write(result_fd, &success, sizeof(success)); + (void) write(result_fd, image->name, strlen(image->name)+1); + goto child_fail; + } + + l = write(result_fd, image->name, strlen(image->name)+1); + if (l < 0) { + r = -errno; + goto child_fail; + } + + l = write(result_fd, &image->usage_exclusive, sizeof(image->usage_exclusive)); + if (l < 0) { + r = -errno; + goto child_fail; + } + } + + result_fd = safe_close(result_fd); + _exit(EXIT_SUCCESS); + + child_fail: + (void) write(errno_pipe_fd[1], &r, sizeof(r)); + _exit(EXIT_FAILURE); } - r = sd_bus_message_close_container(reply); - if (r < 0) + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + /* The clean-up might take a while, hence install a watch on the child and return */ + + r = operation_new(m, NULL, child, message, errno_pipe_fd[0], &operation); + if (r < 0) { + (void) sigkill_wait(child); return r; + } - return sd_bus_send(NULL, reply, NULL); + operation->extra_fd = result_fd; + operation->done = clean_pool_done; + + result_fd = -1; + errno_pipe_fd[0] = -1; + + return 1; } static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) { diff --git a/src/machine/operation.c b/src/machine/operation.c index e6ddc41a55..8f8321a8b3 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -41,18 +41,33 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat goto fail; } - if (si->si_status != EXIT_SUCCESS) { - if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r)) - r = sd_bus_error_set_errnof(&error, r, "%m"); - else - r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed."); - + if (si->si_status == EXIT_SUCCESS) + r = 0; + else if (read(o->errno_fd, &r, sizeof(r)) != sizeof(r)) { /* Try to acquire error code for failed operation */ + r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed."); goto fail; } - r = sd_bus_reply_method_return(o->message, NULL); - if (r < 0) - log_error_errno(r, "Failed to reply to message: %m"); + if (o->done) { + /* A completion routine is set for this operation, call it. */ + r = o->done(o, r, &error); + if (r < 0) { + if (!sd_bus_error_is_set(&error)) + sd_bus_error_set_errno(&error, r); + + goto fail; + } + + } else { + /* The default default operaton when done is to simply return an error on failure or an empty success + * message on success. */ + if (r < 0) + goto fail; + + r = sd_bus_reply_method_return(o->message, NULL); + if (r < 0) + log_error_errno(r, "Failed to reply to message: %m"); + } operation_free(o); return 0; @@ -66,7 +81,7 @@ fail: return 0; } -int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) { +int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) { Operation *o; int r; @@ -79,6 +94,8 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag if (!o) return -ENOMEM; + o->extra_fd = -1; + r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o); if (r < 0) { free(o); @@ -102,6 +119,9 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag /* At this point we took ownership of both the child and the errno file descriptor! */ + if (ret) + *ret = o; + return 0; } @@ -112,6 +132,7 @@ Operation *operation_free(Operation *o) { sd_event_source_unref(o->event_source); safe_close(o->errno_fd); + safe_close(o->extra_fd); if (o->pid > 1) (void) sigkill_wait(o->pid); diff --git a/src/machine/operation.h b/src/machine/operation.h index 7ca47bc3af..9831b123d7 100644 --- a/src/machine/operation.h +++ b/src/machine/operation.h @@ -38,10 +38,12 @@ struct Operation { pid_t pid; sd_bus_message *message; int errno_fd; + int extra_fd; sd_event_source *event_source; + int (*done)(Operation *o, int ret, sd_bus_error *error); LIST_FIELDS(Operation, operations); LIST_FIELDS(Operation, operations_by_machine); }; -int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd); +int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret); Operation *operation_free(Operation *o); -- cgit v1.2.3-54-g00ecf From 1c6c037cece7add31e4017ea7775ddb32d4fe7ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 16:03:49 +0200 Subject: machined: make sure CleanPool() method is opened up in the dbus policy The method is already hooked up to PolicyKit, hence let's open this up via the bus policy language too. Fixes: #3585 --- src/machine/org.freedesktop.machine1.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf index 9d40b90151..562b9d3cc0 100644 --- a/src/machine/org.freedesktop.machine1.conf +++ b/src/machine/org.freedesktop.machine1.conf @@ -116,6 +116,10 @@ send_interface="org.freedesktop.machine1.Manager" send_member="SetImageLimit"/> + + -- cgit v1.2.3-54-g00ecf From 6edefe0b064e57af108f56172b3dafa0be61e234 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Fri, 24 Jun 2016 16:08:43 +0200 Subject: pid1: restore console color support for containers (#3595) Commit 3a18b60489504056f9b0b1a139439cbfa60a87e1 introduced a regression that disabled the color mode for container. This patch fixes this. --- src/core/main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 237c9c9ebe..3d74ef1adf 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1507,13 +1507,14 @@ int main(int argc, char *argv[]) { (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); } - /* We expect the environment to be set correctly if run inside a - * container. */ - if (arg_system && detect_container() <= 0) { - if (fixup_environment() < 0) { - error_message = "Failed to fix up PID1 environment"; - goto finish; - } + if (arg_system) { + /* We expect the environment to be set correctly + * if run inside a container. */ + if (detect_container() <= 0) + if (fixup_environment() < 0) { + error_message = "Failed to fix up PID1 environment"; + goto finish; + } /* Try to figure out if we can use colors with the console. No * need to do that for user instances since they never log -- cgit v1.2.3-54-g00ecf From e34e72fb18b6a14c43c71db34dc4fd983383a71a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 20:59:51 +0200 Subject: fstab-generator: let's use path_equal() for comparing paths --- src/fstab-generator/fstab-generator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 880dc1bd2a..daf50706c7 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -502,7 +502,7 @@ static int add_sysroot_mount(void) { return 0; } - if (streq(arg_root_what, "/dev/nfs")) { + if (path_equal(arg_root_what, "/dev/nfs")) { /* This is handled by the kernel or the initrd */ log_debug("Skipping root directory handling, as /dev/nfs was requested."); return 0; -- cgit v1.2.3-54-g00ecf From 40472036cf467b80409d17d18bb28dd1314d93e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:00:11 +0200 Subject: fstab-generator: document why we copy the root device into the usr device if unset Let's a comment about this, to avoid questions popping up like in #2344. --- src/fstab-generator/fstab-generator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index daf50706c7..62e67e088b 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -548,22 +548,20 @@ static int add_sysroot_usr_mount(void) { return 0; if (arg_root_what && !arg_usr_what) { + /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */ arg_usr_what = strdup(arg_root_what); - if (!arg_usr_what) return log_oom(); } if (arg_root_fstype && !arg_usr_fstype) { arg_usr_fstype = strdup(arg_root_fstype); - if (!arg_usr_fstype) return log_oom(); } if (arg_root_options && !arg_usr_options) { arg_usr_options = strdup(arg_root_options); - if (!arg_usr_options) return log_oom(); } -- cgit v1.2.3-54-g00ecf From 47be5f0742caf56d38b41ae97dff21303d3ed264 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:01:22 +0200 Subject: fstab-generator: fix checking of fstab_node_to_udev_node() result We have to check for OOM here, let's add that. There's really no point in checking for path_is_absolute() on the result however, as there's no particular reason why that should be refused. Also, we don't have similar checks for the other mount devices the generator deals with, hence don't bother with it here either. Let's remove that check. (And it shouldn't return made-up errors like "-1" in this case anyway.) --- src/fstab-generator/fstab-generator.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 62e67e088b..26fccbe360 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -570,10 +570,8 @@ static int add_sysroot_usr_mount(void) { return 0; what = fstab_node_to_udev_node(arg_usr_what); - if (!path_is_absolute(what)) { - log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); - return -1; - } + if (!what) + return log_oom(); if (!arg_usr_options) opts = arg_root_rw > 0 ? "rw" : "ro"; -- cgit v1.2.3-54-g00ecf From dbf43a1b3a10b8e50eca3866687989ca5b21dabd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:03:47 +0200 Subject: systemctl: fix an error condition from "-1" to something meaningful We really shouldn't make up errors like "-1", but use proper errno definitions. --- src/systemctl/systemctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0a8e60c195..c0b285b58f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6175,7 +6175,7 @@ static int unit_file_create_copy( if (response != 'y') { log_warning("%s ignored", unit_name); free(tmp_new_path); - return -1; + return -EKEYREJECTED; } } @@ -6307,10 +6307,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); else r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path); - } else { + } else r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path); - } - if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 003cba39467a87bc2b530d311090b698fb08a993 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:04:48 +0200 Subject: fstab-generator: don't skip /usr handling if root handling didn't work correctly Let's follow the same logic for all mounts here: log errors, and exit the process uncleanly ultimately, but do not skip further mounts if we encounter a problem with an earlier one. Fixes: #2344 --- src/fstab-generator/fstab-generator.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 26fccbe360..8688ae51c9 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -683,10 +683,15 @@ int main(int argc, char *argv[]) { /* Always honour root= and usr= in the kernel command line if we are in an initrd */ if (in_initrd()) { + int k; + r = add_sysroot_mount(); - if (r == 0) - r = add_sysroot_usr_mount(); - } + + k = add_sysroot_usr_mount(); + if (k < 0) + r = k; + } else + r = 0; /* Honour /etc/fstab only when that's enabled */ if (arg_fstab_enabled) { -- cgit v1.2.3-54-g00ecf From f113f8e382b8b53d586a507ef4c125009a4be33e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:07:18 +0200 Subject: fstab-generator: skip fsck for /usr on non-device file systems We do the same already for the root device, hence follow the scheme for /usr too. (Also add some explanatory comments.) --- src/fstab-generator/fstab-generator.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 8688ae51c9..f941643c70 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -532,10 +532,10 @@ static int add_sysroot_mount(void) { "/sysroot", arg_root_fstype, opts, - is_device_path(what) ? 1 : 0, - false, - false, - false, + is_device_path(what) ? 1 : 0, /* passno */ + false, /* noauto off */ + false, /* nofail off */ + false, /* automount off */ SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline"); } @@ -585,10 +585,10 @@ static int add_sysroot_usr_mount(void) { "/sysroot/usr", arg_usr_fstype, opts, - 1, - false, - false, - false, + is_device_path(what) ? 1 : 0, /* passno */ + false, /* noauto off */ + false, /* nofail off */ + false, /* automount off */ SPECIAL_INITRD_FS_TARGET, "/proc/cmdline"); } -- cgit v1.2.3-54-g00ecf From 592288a2a78a3bd5b61b094f0512ce4806537b21 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2016 21:22:05 +0200 Subject: fstab-generator: minor simplification --- src/fstab-generator/fstab-generator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index f941643c70..5aeca7e2d5 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -417,8 +417,7 @@ static int parse_fstab(bool initrd) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open %s: %m", fstab_path); - return -errno; + return log_error_errno(errno, "Failed to open %s: %m", fstab_path); } while ((me = getmntent(f))) { -- cgit v1.2.3-54-g00ecf From cc8b113e0ba9e8dfbc4159799133a7d32f633109 Mon Sep 17 00:00:00 2001 From: Felipe Sateler Date: Fri, 24 Jun 2016 22:14:25 -0400 Subject: build-sys: Add new libsystemd-shared private library Link as many binaries as possible with it, to save storage space. Preserve the static libshared and libbasic for use in libraries, nss modules and udev. Libraries need to be static in order to avoid polluting the symbol namespace. Udev needs to be static so downstream can avoid strict version dependencies with the systemd package, and this can complicate upgrade scenarios. --- Makefile.am | 538 ++++++++++++++++++++++++++++------------------ src/test/test-path-util.c | 2 +- 2 files changed, 328 insertions(+), 212 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c25a7c9d8d..86d5620a79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -108,6 +108,7 @@ CLEAN_LOCAL_HOOKS = pkginclude_HEADERS = noinst_LTLIBRARIES = lib_LTLIBRARIES = +rootlibexec_LTLIBRARIES = include_HEADERS = noinst_DATA = pkgconfigdata_DATA = @@ -1078,12 +1079,51 @@ libshared_la_CFLAGS = \ libshared_la_LIBADD = \ libsystemd-internal.la \ + libbasic.la \ libsystemd-journal-internal.la \ libudev-internal.la \ $(ACL_LIBS) \ $(LIBIDN_LIBS) \ $(SECCOMP_LIBS) +rootlibexec_LTLIBRARIES += \ + libsystemd-shared.la + +libsystemd_shared_la_SOURCES = \ + $(libbasic_la_SOURCES) \ + $(libshared_la_SOURCES) \ + $(libsystemd_internal_la_SOURCES) \ + $(libsystemd_journal_internal_la_SOURCES) \ + $(libudev_internal_la_SOURCES) + +libsystemd_shared_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(libbasic_la_CFLAGS) \ + $(libshared_la_CFLAGS) \ + $(libsystemd_internal_la_CFLAGS) \ + $(libsystemd_journal_internal_la_CFLAGS) \ + $(libudev_internal_la_CFLAGS) \ + $(ACL_CFLAGS) \ + $(LIBIDN_CFLAGS) \ + $(SECCOMP_CFLAGS) \ + -fvisibility=default + +# We can't use libshared_la_LIBADD here because it would +# pull in libsystemd*-internal.la +libsystemd_shared_la_LIBADD = \ + $(libbasic_la_LIBADD) \ + $(libsystemd_internal_la_LIBADD) \ + $(libsystemd_journal_internal_la_LIBADD) \ + $(libudev_internal_la_LIBADD) \ + $(ACL_LIBS) \ + $(LIBIDN_LIBS) \ + $(SECCOMP_LIBS) + +libsystemd_shared_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -release $(PACKAGE_VERSION) + + # ----------------------------------------------------------------------------- if HAVE_LIBIPTC noinst_LTLIBRARIES += \ @@ -1244,7 +1284,7 @@ libcore_la_CFLAGS = \ $(SECCOMP_CFLAGS) libcore_la_LIBADD = \ - libshared.la \ + libsystemd-shared.la \ $(PAM_LIBS) \ $(AUDIT_LIBS) \ $(KMOD_LIBS) \ @@ -1637,7 +1677,7 @@ test_device_nodes_SOURCES = \ src/test/test-device-nodes.c test_device_nodes_LDADD = \ - libshared.la + libsystemd-shared.la test_engine_SOURCES = \ src/test/test-engine.c @@ -1688,7 +1728,7 @@ test_dns_domain_SOURCES = \ test_dns_domain_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la if ENABLE_EFI @@ -1699,7 +1739,7 @@ test_boot_timestamps_SOURCES = \ src/test/test-boot-timestamps.c test_boot_timestamps_LDADD = \ - libshared.la + libsystemd-shared.la endif test_unit_name_SOURCES = \ @@ -1728,29 +1768,35 @@ test_utf8_SOURCES = \ src/test/test-utf8.c test_utf8_LDADD = \ - libshared.la + libsystemd-shared.la test_capability_SOURCES = \ src/test/test-capability.c +test_capability_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + test_capability_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(CAP_LIBS) test_async_SOURCES = \ src/test/test-async.c test_async_LDADD = \ - libshared.la + libsystemd-shared.la test_locale_util_SOURCES = \ src/test/test-locale-util.c test_locale_util_LDADD = \ - libshared.la + libsystemd-shared.la test_copy_SOURCES = \ src/test/test-copy.c +# Link statically to ensure file is large test_copy_LDADD = \ libshared.la @@ -1758,187 +1804,192 @@ test_sigbus_SOURCES = \ src/test/test-sigbus.c test_sigbus_LDADD = \ - libshared.la + libsystemd-shared.la test_condition_SOURCES = \ src/test/test-condition.c test_condition_LDADD = \ - libshared.la + libsystemd-shared.la test_fdset_SOURCES = \ src/test/test-fdset.c test_fdset_LDADD = \ - libshared.la + libsystemd-shared.la test_fstab_util_SOURCES = \ src/test/test-fstab-util.c test_fstab_util_LDADD = \ - libshared.la + libsystemd-shared.la test_ratelimit_SOURCES = \ src/test/test-ratelimit.c test_ratelimit_LDADD = \ - libshared.la + libsystemd-shared.la test_util_SOURCES = \ src/test/test-util.c test_util_LDADD = \ - libshared.la + libsystemd-shared.la test_hexdecoct_SOURCES = \ src/test/test-hexdecoct.c test_hexdecoct_LDADD = \ - libbasic.la + libsystemd-shared.la test_alloc_util_SOURCES = \ src/test/test-alloc-util.c test_alloc_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_xattr_util_SOURCES = \ src/test/test-xattr-util.c test_xattr_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_io_util_SOURCES = \ src/test/test-io-util.c test_io_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_glob_util_SOURCES = \ src/test/test-glob-util.c test_glob_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_fs_util_SOURCES = \ src/test/test-fs-util.c test_fs_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_proc_cmdline_SOURCES = \ src/test/test-proc-cmdline.c test_proc_cmdline_LDADD = \ - libbasic.la + libsystemd-shared.la test_fd_util_SOURCES = \ src/test/test-fd-util.c test_fd_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_web_util_SOURCES = \ src/test/test-web-util.c test_web_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_cpu_set_util_SOURCES = \ src/test/test-cpu-set-util.c test_cpu_set_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_stat_util_SOURCES = \ src/test/test-stat-util.c test_stat_util_LDADD = \ - libbasic.la + libsystemd-shared.la test_escape_SOURCES = \ src/test/test-escape.c test_escape_LDADD = \ - libbasic.la + libsystemd-shared.la test_string_util_SOURCES = \ src/test/test-string-util.c test_string_util_LDADD = \ - libshared.la + libsystemd-shared.la test_extract_word_SOURCES = \ src/test/test-extract-word.c test_extract_word_LDADD = \ - libshared.la + libsystemd-shared.la test_parse_util_SOURCES = \ src/test/test-parse-util.c test_parse_util_LDADD = \ - libshared.la + libsystemd-shared.la test_user_util_SOURCES = \ src/test/test-user-util.c test_user_util_LDADD = \ - libshared.la + libsystemd-shared.la test_hostname_util_SOURCES = \ src/test/test-hostname-util.c test_hostname_util_LDADD = \ - libshared.la + libsystemd-shared.la test_process_util_SOURCES = \ src/test/test-process-util.c test_process_util_LDADD = \ - libshared.la + libsystemd-shared.la test_terminal_util_SOURCES = \ src/test/test-terminal-util.c test_terminal_util_LDADD = \ - libshared.la + libsystemd-shared.la test_path_lookup_SOURCES = \ src/test/test-path-lookup.c test_path_lookup_LDADD = \ - libshared.la + libsystemd-shared.la test_uid_range_SOURCES = \ src/test/test-uid-range.c test_uid_range_LDADD = \ - libshared.la + libsystemd-shared.la test_cap_list_SOURCES = \ src/test/test-cap-list.c +test_cap_list_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + test_cap_list_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(CAP_LIBS) test_socket_util_SOURCES = \ src/test/test-socket-util.c test_socket_util_LDADD = \ - libshared.la + libsystemd-shared.la test_barrier_SOURCES = \ src/test/test-barrier.c test_barrier_LDADD = \ - libshared.la + libsystemd-shared.la test_tmpfiles_SOURCES = \ src/test/test-tmpfiles.c test_tmpfiles_LDADD = \ - libshared.la + libsystemd-shared.la test_namespace_SOURCES = \ src/test/test-namespace.c @@ -1947,19 +1998,19 @@ test_verbs_SOURCES = \ src/test/test-verbs.c test_verbs_LDADD = \ - libshared.la + libsystemd-shared.la test_install_root_SOURCES = \ src/test/test-install-root.c test_install_root_LDADD = \ - libshared.la + libsystemd-shared.la test_acl_util_SOURCES = \ src/test/test-acl-util.c test_acl_util_LDADD = \ - libshared.la + libsystemd-shared.la test_namespace_LDADD = \ libcore.la @@ -1968,31 +2019,31 @@ test_rlimit_util_SOURCES = \ src/test/test-rlimit-util.c test_rlimit_util_LDADD = \ - libshared.la + libsystemd-shared.la test_ask_password_api_SOURCES = \ src/test/test-ask-password-api.c test_ask_password_api_LDADD = \ - libshared.la + libsystemd-shared.la test_signal_util_SOURCES = \ src/test/test-signal-util.c test_signal_util_LDADD = \ - libshared.la + libsystemd-shared.la test_selinux_SOURCES = \ src/test/test-selinux.c test_selinux_LDADD = \ - libshared.la + libsystemd-shared.la test_sizeof_SOURCES = \ src/test/test-sizeof.c test_sizeof_LDADD = \ - libshared.la + libsystemd-shared.la BUILT_SOURCES += \ src/test/test-hashmap-ordered.c @@ -2014,34 +2065,34 @@ test_hashmap_SOURCES = \ src/test/test-hashmap-plain.c test_hashmap_LDADD = \ - libshared.la + libsystemd-shared.la test_set_SOURCES = \ src/test/test-set.c test_set_LDADD = \ - libshared.la + libsystemd-shared.la test_bitmap_SOURCES = \ src/test/test-bitmap.c test_bitmap_LDADD = \ - libshared.la + libsystemd-shared.la test_xml_SOURCES = \ src/test/test-xml.c test_xml_LDADD = \ - libshared.la + libsystemd-shared.la test_list_SOURCES = \ src/test/test-list.c test_list_LDADD = \ - libshared.la + libsystemd-shared.la test_unaligned_LDADD = \ - libshared.la + libsystemd-shared.la test_unaligned_SOURCES = \ src/test/test-unaligned.c @@ -2069,49 +2120,49 @@ test_prioq_SOURCES = \ src/test/test-prioq.c test_prioq_LDADD = \ - libshared.la + libsystemd-shared.la test_fileio_SOURCES = \ src/test/test-fileio.c test_fileio_LDADD = \ - libshared.la + libsystemd-shared.la test_time_SOURCES = \ src/test/test-time.c test_time_LDADD = \ - libshared.la + libsystemd-shared.la test_clock_SOURCES = \ src/test/test-clock.c test_clock_LDADD = \ - libshared.la + libsystemd-shared.la test_architecture_SOURCES = \ src/test/test-architecture.c test_architecture_LDADD = \ - libshared.la + libsystemd-shared.la test_log_SOURCES = \ src/test/test-log.c test_log_LDADD = \ - libshared.la + libsystemd-shared.la test_ipcrm_SOURCES = \ src/test/test-ipcrm.c test_ipcrm_LDADD = \ - libshared.la + libsystemd-shared.la test_btrfs_SOURCES = \ src/test/test-btrfs.c test_btrfs_LDADD = \ - libshared.la + libsystemd-shared.la if HAVE_LIBIPTC test_firewall_util_SOURCES = \ @@ -2123,7 +2174,7 @@ test_firewall_util_CFLAGS = \ test_firewall_util_LDADD = \ libfirewall.la \ - libshared.la \ + libsystemd-shared.la \ $(LIBIPTC_LIBS) endif @@ -2135,20 +2186,20 @@ test_netlink_manual_CFLAGS = \ $(KMOD_CFLAGS) test_netlink_manual_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(KMOD_LIBS) test_ellipsize_SOURCES = \ src/test/test-ellipsize.c test_ellipsize_LDADD = \ - libshared.la + libsystemd-shared.la test_date_SOURCES = \ src/test/test-date.c test_date_LDADD = \ - libshared.la + libsystemd-shared.la test_sleep_SOURCES = \ src/test/test-sleep.c @@ -2160,31 +2211,31 @@ test_replace_var_SOURCES = \ src/test/test-replace-var.c test_replace_var_LDADD = \ - libshared.la + libsystemd-shared.la test_calendarspec_SOURCES = \ src/test/test-calendarspec.c test_calendarspec_LDADD = \ - libshared.la + libsystemd-shared.la test_strip_tab_ansi_SOURCES = \ src/test/test-strip-tab-ansi.c test_strip_tab_ansi_LDADD = \ - libshared.la + libsystemd-shared.la test_daemon_SOURCES = \ src/test/test-daemon.c test_daemon_LDADD = \ - libshared.la + libsystemd-shared.la test_cgroup_SOURCES = \ src/test/test-cgroup.c test_cgroup_LDADD = \ - libshared.la + libsystemd-shared.la test_cgroup_mask_SOURCES = \ src/test/test-cgroup-mask.c @@ -2204,31 +2255,31 @@ test_cgroup_util_SOURCES = \ src/test/test-cgroup-util.c test_cgroup_util_LDADD = \ - libshared.la + libsystemd-shared.la test_env_util_SOURCES = \ src/test/test-env-util.c test_env_util_LDADD = \ - libshared.la + libsystemd-shared.la test_strbuf_SOURCES = \ src/test/test-strbuf.c test_strbuf_LDADD = \ - libshared.la + libsystemd-shared.la test_strv_SOURCES = \ src/test/test-strv.c test_strv_LDADD = \ - libshared.la + libsystemd-shared.la test_path_util_SOURCES = \ src/test/test-path-util.c test_path_util_LDADD = \ - libshared.la + libsystemd-shared.la test_path_SOURCES = \ src/test/test-path.c @@ -2254,25 +2305,25 @@ test_siphash24_SOURCES = \ src/test/test-siphash24.c test_siphash24_LDADD = \ - libshared.la + libsystemd-shared.la test_strxcpyx_SOURCES = \ src/test/test-strxcpyx.c test_strxcpyx_LDADD = \ - libshared.la + libsystemd-shared.la test_install_SOURCES = \ src/test/test-install.c test_install_LDADD = \ - libshared.la + libsystemd-shared.la test_watchdog_SOURCES = \ src/test/test-watchdog.c test_watchdog_LDADD = \ - libshared.la + libsystemd-shared.la test_sched_prio_SOURCES = \ src/test/test-sched-prio.c @@ -2292,25 +2343,25 @@ test_conf_files_SOURCES = \ src/test/test-conf-files.c test_conf_files_LDADD = \ - libshared.la + libsystemd-shared.la test_conf_parser_SOURCES = \ src/test/test-conf-parser.c test_conf_parser_LDADD = \ - libshared.la + libsystemd-shared.la test_af_list_SOURCES = \ src/test/test-af-list.c test_af_list_LDADD = \ - libbasic.la + libsystemd-shared.la test_arphrd_list_SOURCES = \ src/test/test-arphrd-list.c test_arphrd_list_LDADD = \ - libbasic.la + libsystemd-shared.la # ------------------------------------------------------------------------------ ## .PHONY so it always rebuilds it @@ -2370,7 +2421,7 @@ systemd_initctl_SOURCES = \ src/initctl/initctl.c systemd_initctl_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_update_utmp_SOURCES = \ @@ -2381,7 +2432,7 @@ systemd_update_utmp_CFLAGS = \ $(AUDIT_CFLAGS) systemd_update_utmp_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(AUDIT_LIBS) # ------------------------------------------------------------------------------ @@ -2389,7 +2440,7 @@ systemd_update_done_SOURCES = \ src/update-done/update-done.c systemd_update_done_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_shutdown_SOURCES = \ @@ -2402,7 +2453,7 @@ systemd_shutdown_SOURCES = \ src/core/killall.c systemd_shutdown_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ if HAVE_KMOD @@ -2414,7 +2465,7 @@ systemd_modules_load_CFLAGS = \ $(KMOD_CFLAGS) systemd_modules_load_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(KMOD_LIBS) rootlibexec_PROGRAMS += \ @@ -2444,8 +2495,13 @@ if ENABLE_TMPFILES systemd_tmpfiles_SOURCES = \ src/tmpfiles/tmpfiles.c +systemd_tmpfiles_CFLAGS = \ + $(AM_CFLAGS) \ + $(ACL_CFLAGS) + systemd_tmpfiles_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(ACL_LIBS) rootbin_PROGRAMS += \ systemd-tmpfiles @@ -2504,7 +2560,7 @@ systemd_sysusers_SOURCES = \ src/sysusers/sysusers.c systemd_sysusers_LDADD = \ - libshared.la + libsystemd-shared.la rootbin_PROGRAMS += \ systemd-sysusers @@ -2550,7 +2606,7 @@ systemd_firstboot_SOURCES = \ src/firstboot/firstboot.c systemd_firstboot_LDADD = \ - libshared.la \ + libsystemd-shared.la \ -lcrypt rootbin_PROGRAMS += \ @@ -2573,7 +2629,7 @@ systemd_machine_id_setup_SOURCES = \ src/core/machine-id-setup.h systemd_machine_id_setup_LDADD = \ - libshared.la + libsystemd-shared.la SYSINIT_TARGET_WANTS += \ systemd-machine-id-commit.service @@ -2583,35 +2639,35 @@ systemd_sysctl_SOURCES = \ src/sysctl/sysctl.c systemd_sysctl_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_sleep_SOURCES = \ src/sleep/sleep.c systemd_sleep_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_fsck_SOURCES = \ src/fsck/fsck.c systemd_fsck_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_ac_power_SOURCES = \ src/ac-power/ac-power.c systemd_ac_power_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_detect_virt_SOURCES = \ src/detect-virt/detect-virt.c systemd_detect_virt_LDADD = \ - libshared.la + libsystemd-shared.la INSTALL_EXEC_HOOKS += \ systemd-detect-virt-install-hook @@ -2621,21 +2677,21 @@ systemd_delta_SOURCES = \ src/delta/delta.c systemd_delta_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_getty_generator_SOURCES = \ src/getty-generator/getty-generator.c systemd_getty_generator_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_debug_generator_SOURCES = \ src/debug-generator/debug-generator.c systemd_debug_generator_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_fstab_generator_SOURCES = \ @@ -2643,14 +2699,14 @@ systemd_fstab_generator_SOURCES = \ src/core/mount-setup.c systemd_fstab_generator_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_system_update_generator_SOURCES = \ src/system-update-generator/system-update-generator.c systemd_system_update_generator_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ if ENABLE_HIBERNATE @@ -2664,13 +2720,13 @@ systemd_hibernate_resume_SOURCES = \ src/hibernate-resume/hibernate-resume.c systemd_hibernate_resume_LDADD = \ - libshared.la + libsystemd-shared.la systemd_hibernate_resume_generator_SOURCES = \ src/hibernate-resume/hibernate-resume-generator.c systemd_hibernate_resume_generator_LDADD = \ - libshared.la + libsystemd-shared.la dist_systemunit_DATA += \ units/hibernate.target \ @@ -2703,7 +2759,7 @@ bootctl_CFLAGS = \ $(BLKID_CFLAGS) bootctl_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(BLKID_LIBS) bin_PROGRAMS += \ @@ -2894,7 +2950,7 @@ systemd_gpt_auto_generator_SOURCES = \ src/basic/blkid-util.h systemd_gpt_auto_generator_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(BLKID_LIBS) systemd_gpt_auto_generator_CFLAGS = \ @@ -2918,7 +2974,7 @@ systemd_rc_local_generator_SOURCES = \ src/rc-local-generator/rc-local-generator.c systemd_rc_local_generator_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_remount_fs_SOURCES = \ @@ -2927,70 +2983,70 @@ systemd_remount_fs_SOURCES = \ src/core/mount-setup.h systemd_remount_fs_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_cgroups_agent_SOURCES = \ src/cgroups-agent/cgroups-agent.c systemd_cgroups_agent_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_escape_SOURCES = \ src/escape/escape.c systemd_escape_LDADD = \ - libshared.la + libsystemd-shared.la # ----------------------------------------------------------------------------- systemctl_SOURCES = \ src/systemctl/systemctl.c systemctl_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_notify_SOURCES = \ src/notify/notify.c systemd_notify_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_path_SOURCES = \ src/path/path.c systemd_path_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_ask_password_SOURCES = \ src/ask-password/ask-password.c systemd_ask_password_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_reply_password_SOURCES = \ src/reply-password/reply-password.c systemd_reply_password_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_cgls_SOURCES = \ src/cgls/cgls.c systemd_cgls_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_cgtop_SOURCES = \ src/cgtop/cgtop.c systemd_cgtop_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_nspawn_SOURCES = \ @@ -3030,12 +3086,17 @@ gperf_gperf_sources += \ systemd_nspawn_CFLAGS = \ $(AM_CFLAGS) \ + $(ACL_CFLAGS) \ $(BLKID_CFLAGS) \ - $(SECCOMP_CFLAGS) + $(SECCOMP_CFLAGS) \ + $(SELINUX_CFLAGS) systemd_nspawn_LDADD = \ - libshared.la \ - $(BLKID_LIBS) + libsystemd-shared.la \ + $(ACL_LIBS) \ + $(BLKID_LIBS) \ + $(SECCOMP_LIBS) \ + $(SELINUX_LIBS) if HAVE_LIBIPTC systemd_nspawn_LDADD += \ @@ -3047,8 +3108,13 @@ test_patch_uid_SOURCES = \ src/nspawn/nspawn-patch-uid.h \ src/nspawn/test-patch-uid.c +test_patch_uid_CFLAGS = \ + $(AM_CFLAGS) \ + $(ACL_CFLAGS) + test_patch_uid_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(ACL_LIBS) manual_tests += \ test-patch-uid @@ -3058,21 +3124,21 @@ systemd_run_SOURCES = \ src/run/run.c systemd_run_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_stdio_bridge_SOURCES = \ src/stdio-bridge/stdio-bridge.c systemd_stdio_bridge_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_tty_ask_password_agent_SOURCES = \ src/tty-ask-password-agent/tty-ask-password-agent.c systemd_tty_ask_password_agent_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ libsystemd_internal_la_SOURCES = \ @@ -3166,7 +3232,6 @@ libsystemd_internal_la_SOURCES = \ src/libsystemd/sd-resolve/sd-resolve.c libsystemd_internal_la_LIBADD = \ - libbasic.la \ -lresolv noinst_LTLIBRARIES += \ @@ -3241,7 +3306,7 @@ test_bus_marshal_SOURCES = \ src/libsystemd/sd-bus/test-bus-marshal.c test_bus_marshal_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(GLIB_LIBS) \ $(DBUS_LIBS) @@ -3254,13 +3319,13 @@ test_bus_signature_SOURCES = \ src/libsystemd/sd-bus/test-bus-signature.c test_bus_signature_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_chat_SOURCES = \ src/libsystemd/sd-bus/test-bus-chat.c test_bus_chat_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_cleanup_SOURCES = \ src/libsystemd/sd-bus/test-bus-cleanup.c @@ -3270,23 +3335,24 @@ test_bus_cleanup_CFLAGS = \ $(SECCOMP_CFLAGS) test_bus_cleanup_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_server_SOURCES = \ src/libsystemd/sd-bus/test-bus-server.c test_bus_server_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_objects_SOURCES = \ src/libsystemd/sd-bus/test-bus-objects.c test_bus_objects_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_error_SOURCES = \ src/libsystemd/sd-bus/test-bus-error.c +# Link statically because this test uses BUS_ERROR_MAP_ELF_REGISTER test_bus_error_LDADD = \ libshared.la @@ -3294,7 +3360,7 @@ test_bus_gvariant_SOURCES = \ src/libsystemd/sd-bus/test-bus-gvariant.c test_bus_gvariant_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(GLIB_LIBS) test_bus_gvariant_CFLAGS = \ @@ -3305,67 +3371,67 @@ test_bus_creds_SOURCES = \ src/libsystemd/sd-bus/test-bus-creds.c test_bus_creds_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_match_SOURCES = \ src/libsystemd/sd-bus/test-bus-match.c test_bus_match_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_kernel_SOURCES = \ src/libsystemd/sd-bus/test-bus-kernel.c test_bus_kernel_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_kernel_bloom_SOURCES = \ src/libsystemd/sd-bus/test-bus-kernel-bloom.c test_bus_kernel_bloom_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_benchmark_SOURCES = \ src/libsystemd/sd-bus/test-bus-benchmark.c test_bus_benchmark_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_zero_copy_SOURCES = \ src/libsystemd/sd-bus/test-bus-zero-copy.c test_bus_zero_copy_LDADD = \ - libshared.la + libsystemd-shared.la test_bus_introspect_SOURCES = \ src/libsystemd/sd-bus/test-bus-introspect.c test_bus_introspect_LDADD = \ - libshared.la + libsystemd-shared.la test_event_SOURCES = \ src/libsystemd/sd-event/test-event.c test_event_LDADD = \ - libshared.la + libsystemd-shared.la test_netlink_SOURCES = \ src/libsystemd/sd-netlink/test-netlink.c test_netlink_LDADD = \ - libshared.la + libsystemd-shared.la test_local_addresses_SOURCES = \ src/libsystemd/sd-netlink/test-local-addresses.c test_local_addresses_LDADD = \ - libshared.la + libsystemd-shared.la test_resolve_SOURCES = \ src/libsystemd/sd-resolve/test-resolve.c test_resolve_LDADD = \ - libshared.la + libsystemd-shared.la busctl_SOURCES = \ src/libsystemd/sd-bus/busctl.c \ @@ -3373,7 +3439,7 @@ busctl_SOURCES = \ src/libsystemd/sd-bus/busctl-introspect.h busctl_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ @@ -3441,7 +3507,7 @@ test_dhcp_option_SOURCES = \ test_dhcp_option_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_dhcp_client_SOURCES = \ src/systemd/sd-dhcp-client.h \ @@ -3451,14 +3517,14 @@ test_dhcp_client_SOURCES = \ test_dhcp_client_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_dhcp_server_SOURCES = \ src/libsystemd-network/test-dhcp-server.c test_dhcp_server_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_ipv4ll_SOURCES = \ src/systemd/sd-ipv4ll.h \ @@ -3467,7 +3533,7 @@ test_ipv4ll_SOURCES = \ test_ipv4ll_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_ipv4ll_manual_SOURCES = \ src/systemd/sd-ipv4ll.h \ @@ -3475,7 +3541,7 @@ test_ipv4ll_manual_SOURCES = \ test_ipv4ll_manual_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_acd_SOURCES = \ src/systemd/sd-ipv4acd.h \ @@ -3483,7 +3549,7 @@ test_acd_SOURCES = \ test_acd_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la test_ndisc_rs_SOURCES = \ src/systemd/sd-dhcp6-client.h \ @@ -3496,7 +3562,7 @@ test_ndisc_rs_SOURCES = \ test_ndisc_rs_LDADD = \ libsystemd-network.la \ libudev.la \ - libshared.la + libsystemd-shared.la test_dhcp6_client_SOURCES = \ src/systemd/sd-dhcp6-client.h \ @@ -3508,14 +3574,14 @@ test_dhcp6_client_SOURCES = \ test_dhcp6_client_LDADD = \ libsystemd-network.la \ libudev.la \ - libshared.la + libsystemd-shared.la test_lldp_SOURCES = \ src/libsystemd-network/test-lldp.c test_lldp_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la tests += \ test-dhcp-option \ @@ -3553,7 +3619,8 @@ libudev_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/libudev/libudev.sym libudev_la_LIBADD = \ - libsystemd-internal.la + libsystemd-internal.la \ + libbasic.la pkgconfiglib_DATA += \ src/libudev/libudev.pc @@ -3717,7 +3784,8 @@ systemd_udevd_SOURCES = \ src/udev/udevd.c systemd_udevd_LDADD = \ - libudev-core.la + libudev-core.la \ + libbasic.la udevadm_SOURCES = \ src/udev/udevadm.c \ @@ -3733,7 +3801,8 @@ udevadm_SOURCES = \ src/udev/udevadm-util.h udevadm_LDADD = \ - libudev-core.la + libudev-core.la \ + libbasic.la # ------------------------------------------------------------------------------ if ENABLE_HWDB @@ -3812,15 +3881,17 @@ test_libudev_SOURCES = \ src/test/test-libudev.c test_libudev_LDADD = \ - libshared.la + libsystemd-shared.la test_udev_SOURCES = \ src/test/test-udev.c test_udev_LDADD = \ libudev-core.la \ + libsystemd-shared.la \ $(BLKID_LIBS) \ - $(KMOD_LIBS) + $(KMOD_LIBS) \ + -lrt if ENABLE_TESTS check_DATA += \ @@ -3924,7 +3995,7 @@ test_id128_SOURCES = \ src/test/test-id128.c test_id128_LDADD = \ - libshared.la + libsystemd-shared.la tests += \ test-id128 @@ -3938,7 +4009,7 @@ systemd_socket_activate_SOURCES = \ src/activate/activate.c systemd_socket_activate_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ systemd_journald_SOURCES = \ @@ -3947,7 +4018,7 @@ systemd_journald_SOURCES = \ systemd_journald_LDADD = \ libjournal-core.la \ - libshared.la + libsystemd-shared.la systemd_cat_SOURCES = \ src/journal/cat.c @@ -3969,7 +4040,7 @@ systemd_journal_upload_CFLAGS = \ $(LIBCURL_CFLAGS) systemd_journal_upload_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(LIBCURL_LIBS) nodist_systemunit_DATA += \ @@ -4050,7 +4121,7 @@ journalctl_SOURCES = \ src/journal/journalctl.c journalctl_LDADD = \ - libshared.la \ + libsystemd-shared.la \ libudev-core.la if HAVE_QRENCODE @@ -4145,13 +4216,18 @@ test_compress_SOURCES = \ src/journal/test-compress.c test_compress_LDADD = \ - libshared.la + libsystemd-shared.la + +if HAVE_LZ4 +test_compress_LDADD += \ + -llz4 +endif test_compress_benchmark_SOURCES = \ src/journal/test-compress-benchmark.c test_compress_benchmark_LDADD = \ - libshared.la + libsystemd-shared.la test_audit_type_SOURCES = \ src/journal/test-audit-type.c @@ -4184,7 +4260,7 @@ nodist_libjournal_core_la_SOURCES = \ src/journal/journald-gperf.c libjournal_core_la_LIBADD = \ - libshared.la + libsystemd-shared.la noinst_LTLIBRARIES += \ libjournal-core.la @@ -4379,7 +4455,7 @@ systemd_journal_gatewayd_SOURCES = \ src/journal-remote/microhttpd-util.c systemd_journal_gatewayd_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(MICROHTTPD_LIBS) if HAVE_GNUTLS @@ -4415,7 +4491,7 @@ systemd_socket_proxyd_SOURCES = \ src/socket-proxy/socket-proxyd.c systemd_socket_proxyd_LDADD = \ - libshared.la + libsystemd-shared.la # ------------------------------------------------------------------------------ if ENABLE_COREDUMP @@ -4424,8 +4500,13 @@ systemd_coredump_SOURCES = \ src/coredump/coredump-vacuum.c \ src/coredump/coredump-vacuum.h +systemd_coredump_CFLAGS = \ + $(AM_CFLAGS) \ + $(ACL_CFLAGS) + systemd_coredump_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(ACL_LIBS) if HAVE_ELFUTILS systemd_coredump_SOURCES += \ @@ -4455,7 +4536,7 @@ coredumpctl_SOURCES = \ src/coredump/coredumpctl.c coredumpctl_LDADD = \ - libshared.la + libsystemd-shared.la bin_PROGRAMS += \ coredumpctl @@ -4469,7 +4550,7 @@ test_coredump_vacuum_SOURCES = \ src/coredump/coredump-vacuum.h test_coredump_vacuum_LDADD = \ - libshared.la + libsystemd-shared.la dist_bashcompletion_data += \ shell-completion/bash/coredumpctl @@ -4494,7 +4575,7 @@ systemd_binfmt_SOURCES = \ src/binfmt/binfmt.c systemd_binfmt_LDADD = \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-binfmt @@ -4525,7 +4606,7 @@ systemd_vconsole_setup_SOURCES = \ src/vconsole/vconsole-setup.c systemd_vconsole_setup_LDADD = \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-vconsole-setup @@ -4556,7 +4637,7 @@ systemd_quotacheck_SOURCES = \ src/quotacheck/quotacheck.c systemd_quotacheck_LDADD = \ - libshared.la + libsystemd-shared.la endif EXTRA_DIST += \ @@ -4577,7 +4658,7 @@ systemd_random_seed_SOURCES = \ src/random-seed/random-seed.c systemd_random_seed_LDADD = \ - libshared.la + libsystemd-shared.la SYSINIT_TARGET_WANTS += \ systemd-random-seed.service @@ -4599,7 +4680,7 @@ systemd_backlight_SOURCES = \ src/backlight/backlight.c systemd_backlight_LDADD = \ - libshared.la + libsystemd-shared.la endif EXTRA_DIST += \ @@ -4620,7 +4701,7 @@ systemd_rfkill_SOURCES = \ src/rfkill/rfkill.c systemd_rfkill_LDADD = \ - libshared.la + libsystemd-shared.la endif EXTRA_DIST += \ @@ -4646,14 +4727,14 @@ systemd_cryptsetup_CFLAGS = \ $(LIBCRYPTSETUP_CFLAGS) systemd_cryptsetup_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(LIBCRYPTSETUP_LIBS) systemd_cryptsetup_generator_SOURCES = \ src/cryptsetup/cryptsetup-generator.c systemd_cryptsetup_generator_LDADD = \ - libshared.la + libsystemd-shared.la SYSINIT_TARGET_WANTS += \ cryptsetup.target @@ -4666,7 +4747,7 @@ systemd_hostnamed_SOURCES = \ src/hostname/hostnamed.c systemd_hostnamed_LDADD = \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-hostnamed @@ -4696,7 +4777,7 @@ hostnamectl_SOURCES = \ src/hostname/hostnamectl.c hostnamectl_LDADD = \ - libshared.la + libsystemd-shared.la bin_PROGRAMS += \ hostnamectl @@ -4729,7 +4810,7 @@ systemd_localed_SOURCES = \ src/locale/keymap-util.h systemd_localed_LDADD = \ - libshared.la \ + libsystemd-shared.la \ -ldl systemd_localed_CFLAGS = \ @@ -4780,7 +4861,7 @@ localectl_SOURCES = \ src/locale/localectl.c localectl_LDADD = \ - libshared.la + libsystemd-shared.la bin_PROGRAMS += \ localectl @@ -4806,7 +4887,7 @@ systemd_timedated_SOURCES = \ src/timedate/timedated.c systemd_timedated_LDADD = \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-timedated @@ -4836,7 +4917,7 @@ timedatectl_SOURCES = \ src/timedate/timedatectl.c timedatectl_LDADD = \ - libshared.la + libsystemd-shared.la bin_PROGRAMS += \ timedatectl @@ -4870,7 +4951,8 @@ nodist_systemd_timesyncd_SOURCES = \ systemd_timesyncd_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la \ + -lm rootlibexec_PROGRAMS += \ systemd-timesyncd @@ -4899,6 +4981,7 @@ test_nss_SOURCES = \ test_nss_LDADD = \ libsystemd-internal.la \ + libbasic.la \ -ldl manual_tests += \ @@ -4920,7 +5003,8 @@ libnss_myhostname_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-myhostname/nss-myhostname.sym libnss_myhostname_la_LIBADD = \ - libsystemd-internal.la + libsystemd-internal.la \ + libbasic.la lib_LTLIBRARIES += \ libnss_myhostname.la @@ -4950,7 +5034,7 @@ libmachine_core_la_SOURCES = \ src/machine/operation.h libmachine_core_la_LIBADD = \ - libshared.la + libsystemd-shared.la noinst_LTLIBRARIES += \ libmachine-core.la @@ -4959,7 +5043,7 @@ machinectl_SOURCES = \ src/machine/machinectl.c machinectl_LDADD = \ - libshared.la + libsystemd-shared.la rootbin_PROGRAMS += \ machinectl @@ -5018,7 +5102,8 @@ libnss_mymachines_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-mymachines/nss-mymachines.sym libnss_mymachines_la_LIBADD = \ - libsystemd-internal.la + libsystemd-internal.la \ + libbasic.la lib_LTLIBRARIES += \ libnss_mymachines.la @@ -5056,7 +5141,7 @@ systemd_importd_CFLAGS = \ -D SYSTEMD_EXPORT_PATH=\"$(rootlibexecdir)/systemd-export\" systemd_importd_LDADD = \ - libshared.la + libsystemd-shared.la systemd_pull_SOURCES = \ src/import/pull.c \ @@ -5087,7 +5172,7 @@ systemd_pull_CFLAGS = \ -D USER_KEYRING_PATH=\"$(pkgsysconfdir)/import-pubring.gpg\" systemd_pull_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(LIBCURL_LIBS) \ $(XZ_LIBS) \ $(ZLIB_LIBS) \ @@ -5113,7 +5198,7 @@ systemd_import_CFLAGS = \ $(ZLIB_CFLAGS) systemd_import_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(XZ_LIBS) \ $(ZLIB_LIBS) \ -lbz2 @@ -5135,7 +5220,7 @@ systemd_export_CFLAGS = \ $(ZLIB_CFLAGS) systemd_export_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(XZ_LIBS) \ $(ZLIB_LIBS) \ -lbz2 @@ -5177,7 +5262,7 @@ test_qcow2_CFLAGS = \ $(ZLIB_CFLAGS) test_qcow2_LDADD = \ - libshared.la \ + libsystemd-shared.la \ $(ZLIB_LIBS) endif @@ -5264,9 +5349,15 @@ nodist_systemd_resolved_SOURCES = \ src/resolve/dns_type-to-name.h \ src/resolve/resolved-gperf.c +systemd_resolved_CFLAGS = \ + $(AM_CFLAGS) \ + $(GCRYPT_CFLAGS) + systemd_resolved_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la \ + $(GCRYPT_LIBS) \ + -lm rootlibexec_PROGRAMS += \ systemd-resolved @@ -5310,6 +5401,7 @@ libnss_resolve_la_LDFLAGS = \ libnss_resolve_la_LIBADD = \ libsystemd-internal.la \ + libbasic.la \ -ldl lib_LTLIBRARIES += \ @@ -5325,8 +5417,14 @@ nodist_systemd_resolve_SOURCES = \ src/resolve/dns_type-from-name.h \ src/resolve/dns_type-to-name.h +systemd_resolve_CFLAGS = \ + $(AM_CFLAGS) \ + $(GCRYPT_CFLAGS) + systemd_resolve_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(GCRYPT_LIBS) \ + -lm bin_PROGRAMS += \ systemd-resolve @@ -5352,8 +5450,14 @@ test_resolve_tables_SOURCES = \ $(basic_dns_sources) \ src/shared/test-tables.h +test_resolve_tables_CFLAGS = \ + $(AM_CFLAGS) \ + $(GCRYPT_CFLAGS) + test_resolve_tables_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(GCRYPT_LIBS) \ + -lm test_dns_packet_SOURCES = \ src/resolve/test-dns-packet.c \ @@ -5363,8 +5467,14 @@ test_dns_packet_CPPFLAGS = \ $(AM_CPPFLAGS) \ -DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\" +test_dns_packet_CFLAGS = \ + $(AM_CFLAGS) \ + $(GCRYPT_CFLAGS) + test_dns_packet_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(GCRYPT_LIBS) \ + -lm EXTRA_DIST += \ src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts \ @@ -5383,8 +5493,14 @@ test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ $(basic_dns_sources) +test_dnssec_CFLAGS = \ + $(AM_CFLAGS) \ + $(GCRYPT_CFLAGS) + test_dnssec_LDADD = \ - libshared.la + libsystemd-shared.la \ + $(GCRYPT_LIBS) \ + -lm test_dnssec_complex_SOURCES = \ src/resolve/test-dnssec-complex.c \ @@ -5392,7 +5508,7 @@ test_dnssec_complex_SOURCES = \ src/resolve/dns-type.h test_dnssec_complex_LDADD = \ - libshared.la + libsystemd-shared.la endif @@ -5495,7 +5611,7 @@ nodist_libnetworkd_core_la_SOURCES = \ libnetworkd_core_la_LIBADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-networkd-wait-online @@ -5513,7 +5629,7 @@ systemd_networkd_wait_online_SOURCES = \ systemd_networkd_wait_online_LDADD = \ libsystemd-network.la \ - libshared.la + libsystemd-shared.la rootbin_PROGRAMS += \ networkctl @@ -5522,7 +5638,7 @@ networkctl_SOURCES = \ src/network/networkctl.c networkctl_LDADD = \ - libshared.la \ + libsystemd-shared.la \ libsystemd-network.la dist_bashcompletion_data += \ @@ -5640,7 +5756,7 @@ liblogind_core_la_SOURCES = \ src/login/logind-acl.h liblogind_core_la_LIBADD = \ - libshared.la + libsystemd-shared.la if HAVE_ACL liblogind_core_la_SOURCES += \ @@ -5659,7 +5775,7 @@ loginctl_SOURCES = \ src/login/sysfs-show.c loginctl_LDADD = \ - libshared.la + libsystemd-shared.la rootbin_PROGRAMS += \ loginctl @@ -5675,7 +5791,7 @@ systemd_inhibit_SOURCES = \ src/login/inhibit.c systemd_inhibit_LDADD = \ - libshared.la + libsystemd-shared.la rootbin_PROGRAMS += \ systemd-inhibit @@ -5684,19 +5800,19 @@ test_login_SOURCES = \ src/libsystemd/sd-login/test-login.c test_login_LDADD = \ - libshared.la + libsystemd-shared.la test_login_shared_SOURCES = \ src/login/test-login-shared.c test_login_shared_LDADD = \ - libshared.la + libsystemd-shared.la test_inhibit_SOURCES = \ src/login/test-inhibit.c test_inhibit_LDADD = \ - libshared.la + libsystemd-shared.la test_login_tables_SOURCES = \ src/login/test-login-tables.c @@ -5805,7 +5921,7 @@ systemd_user_sessions_SOURCES = \ src/user-sessions/user-sessions.c systemd_user_sessions_LDADD = \ - libshared.la + libsystemd-shared.la rootlibexec_PROGRAMS += \ systemd-user-sessions diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index b53324b5e6..6094d4c3e5 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -114,7 +114,7 @@ static void test_find_binary(const char *self) { assert_se(find_binary(self, &p) == 0); puts(p); - assert_se(endswith(p, "/test-path-util")); + assert_se(endswith(p, "/lt-test-path-util")); assert_se(path_is_absolute(p)); free(p); -- cgit v1.2.3-54-g00ecf From 0c6aeb4609f619328b9dcf8d8d815bd06e412ac5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 25 Jun 2016 06:04:43 +0200 Subject: nspawn: fix uid patching logic (#3599) An incorrectly set if/else chain caused aus to apply the access mode of a symlink to the directory it is located in. Yuck. Fixes: #3547 --- src/nspawn/nspawn-patch-uid.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c index cc79597c95..ded5866d05 100644 --- a/src/nspawn/nspawn-patch-uid.c +++ b/src/nspawn/nspawn-patch-uid.c @@ -263,9 +263,12 @@ static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift return -errno; /* The Linux kernel alters the mode in some cases of chown(). Let's undo this. */ - if (name && !S_ISLNK(st->st_mode)) - r = fchmodat(fd, name, st->st_mode, 0); - else + if (name) { + if (!S_ISLNK(st->st_mode)) + r = fchmodat(fd, name, st->st_mode, 0); + else /* AT_SYMLINK_NOFOLLOW is not available for fchmodat() */ + r = 0; + } else r = fchmod(fd, st->st_mode); if (r < 0) return -errno; -- cgit v1.2.3-54-g00ecf From 8a3134b2b78b4ec310cd3f7b38fd0c9e09254aa8 Mon Sep 17 00:00:00 2001 From: 0xAX <0xAX@users.noreply.github.com> Date: Sun, 26 Jun 2016 13:37:00 +0300 Subject: basic/strv: use SWAP_TWO() macro (#3602) --- src/basic/strv.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index 97a96e5762..578a9c1005 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -804,11 +804,7 @@ char **strv_reverse(char **l) { 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; + SWAP_TWO(l[i], l[n-1-i]); } return l; -- cgit v1.2.3-54-g00ecf From 03fb3334589fb65e7e158e35ed5e68fa8824280c Mon Sep 17 00:00:00 2001 From: 0xAX <0xAX@users.noreply.github.com> Date: Sun, 26 Jun 2016 18:37:24 +0300 Subject: networkd: use strv_fnmatch() (#3605) --- src/network/networkd-wait-online-manager.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c index 2ff7ddb044..725b3310dd 100644 --- a/src/network/networkd-wait-online-manager.c +++ b/src/network/networkd-wait-online-manager.c @@ -30,8 +30,6 @@ #include "util.h" bool manager_ignore_link(Manager *m, Link *link) { - char **ignore; - assert(m); assert(link); @@ -44,11 +42,7 @@ bool manager_ignore_link(Manager *m, Link *link) { return true; /* ignore interfaces we explicitly are asked to ignore */ - STRV_FOREACH(ignore, m->ignore) - if (fnmatch(*ignore, link->ifname, 0) == 0) - return true; - - return false; + return strv_fnmatch(m->ignore, link->ifname, 0); } bool manager_all_configured(Manager *m) { -- cgit v1.2.3-54-g00ecf From 68ce459f2fadd3f8aa6e083b4823b37116394956 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Jun 2016 17:41:33 +0200 Subject: machinectl: verify image existance on "start" and "enable" (#3579) Let's make sure we catch early when a machine doesn't exist that is attempted to be started or enabled as system service. --- src/machine/machinectl.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 5ca557abbf..b47d2a832a 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -32,6 +32,7 @@ #include "sd-bus.h" #include "alloc-util.h" +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-unit-util.h" #include "bus-util.h" @@ -1523,6 +1524,32 @@ static int read_only_image(int argc, char *argv[], void *userdata) { return 0; } +static int image_exists(sd_bus *bus, const char *name) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(name); + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetImage", + &error, + NULL, + "s", name); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE)) + return 0; + + return log_error_errno(r, "Failed to check whether image %s exists: %s", name, bus_error_message(&error, -r)); + } + + return 1; +} + static int make_service_name(const char *name, char **ret) { _cleanup_free_ char *e = NULL; int r; @@ -1565,6 +1592,14 @@ static int start_machine(int argc, char *argv[], void *userdata) { if (r < 0) return r; + r = image_exists(bus, argv[i]); + if (r < 0) + return r; + if (r == 0) { + log_error("Machine image '%s' does not exist.", argv[1]); + return -ENXIO; + } + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -1632,6 +1667,14 @@ static int enable_machine(int argc, char *argv[], void *userdata) { if (r < 0) return r; + r = image_exists(bus, argv[i]); + if (r < 0) + return r; + if (r == 0) { + log_error("Machine image '%s' does not exist.", argv[1]); + return -ENXIO; + } + r = sd_bus_message_append(m, "s", unit); if (r < 0) return bus_log_create_error(r); -- cgit v1.2.3-54-g00ecf From 3172836b2f9841994ed7d0daf054d4570b8dac6f Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 26 Jun 2016 22:36:46 +0200 Subject: sd-device: enumerator - do not abort enumeration if a device fails Collect the errors and return to the caller, but continue enumerating all devices. --- src/libsystemd/sd-device/device-enumerator.c | 34 +++++++++++++++------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 4a7a8b1f9e..62d03ae00d 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -696,17 +696,19 @@ static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const c static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) { const char *tag; Iterator i; - int r; + int r = 0; assert(enumerator); SET_FOREACH(tag, enumerator->match_tag, i) { - r = enumerator_scan_devices_tag(enumerator, tag); - if (r < 0) - return r; + int k; + + k = enumerator_scan_devices_tag(enumerator, tag); + if (k < 0) + r = k; } - return 0; + return r; } static int parent_add_child(sd_device_enumerator *enumerator, const char *path) { @@ -838,7 +840,7 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { sd_device *device; - int r; + int r = 0, k; assert(enumerator); @@ -850,22 +852,22 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { sd_device_unref(device); if (!set_isempty(enumerator->match_tag)) { - r = enumerator_scan_devices_tags(enumerator); - if (r < 0) - return r; + k = enumerator_scan_devices_tags(enumerator); + if (k < 0) + r = k; } else if (enumerator->match_parent) { - r = enumerator_scan_devices_children(enumerator); - if (r < 0) - return r; + k = enumerator_scan_devices_children(enumerator); + if (k < 0) + r = k; } else { - r = enumerator_scan_devices_all(enumerator); - if (r < 0) - return r; + k = enumerator_scan_devices_all(enumerator); + if (k < 0) + r = k; } enumerator->scan_uptodate = true; - return 0; + return r; } _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) { -- cgit v1.2.3-54-g00ecf From de7e983ea13f1cb76339db9037fc5115199396d0 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 26 Jun 2016 23:05:27 +0200 Subject: sd-device: device_id - set correctly for 'drivers' The 'drivers' pseudo-subsystem needs special treatment. These pseudo-devices are found under /sys/bus/drivers/, so needs the real subsystem encoded in the device_id in order to be resolved. The reader side already assumed this to be the case. --- src/libsystemd/sd-device/device-internal.h | 2 + src/libsystemd/sd-device/sd-device.c | 84 +++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index ab222e27de..9fad388953 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -76,6 +76,8 @@ struct sd_device { char *subsystem; bool subsystem_set; /* don't reread subsystem */ + char *driver_subsystem; /* only set for the 'drivers' subsystem */ + bool driver_subsystem_set; /* don't reread subsystem */ char *driver; bool driver_set; /* don't reread driver */ diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 5c9e00ed80..c13f6fca28 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -75,6 +75,7 @@ _public_ sd_device *sd_device_unref(sd_device *device) { free(device->devtype); free(device->devname); free(device->subsystem); + free(device->driver_subsystem); free(device->driver); free(device->id_filename); free(device->properties_strv); @@ -766,21 +767,45 @@ int device_set_subsystem(sd_device *device, const char *_subsystem) { return 0; } +static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) { + _cleanup_free_ char *subsystem = NULL; + int r; + + assert(device); + assert(_subsystem); + assert(*_subsystem); + + subsystem = strdup(_subsystem); + if (!subsystem) + return -ENOMEM; + + r = device_set_subsystem(device, "drivers"); + if (r < 0) + return r; + + free(device->driver_subsystem); + device->driver_subsystem = subsystem; + subsystem = NULL; + + return 0; +} + _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { + const char *syspath, *drivers = NULL; + int r; + assert_return(ret, -EINVAL); assert_return(device, -EINVAL); + r = sd_device_get_syspath(device, &syspath); + if (r < 0) + return r; + if (!device->subsystem_set) { _cleanup_free_ char *subsystem = NULL; - const char *syspath; char *path; - int r; /* read 'subsystem' link */ - r = sd_device_get_syspath(device, &syspath); - if (r < 0) - return r; - path = strjoina(syspath, "/subsystem"); r = readlink_value(path, &subsystem); if (r >= 0) @@ -788,16 +813,39 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { /* use implicit names */ else if (path_startswith(device->devpath, "/module/")) r = device_set_subsystem(device, "module"); - else if (strstr(device->devpath, "/drivers/")) - r = device_set_subsystem(device, "drivers"); - else if (path_startswith(device->devpath, "/subsystem/") || - path_startswith(device->devpath, "/class/") || - path_startswith(device->devpath, "/bus/")) + else if (!(drivers = strstr(syspath, "/drivers/")) && + (path_startswith(device->devpath, "/subsystem/") || + path_startswith(device->devpath, "/class/") || + path_startswith(device->devpath, "/bus/"))) r = device_set_subsystem(device, "subsystem"); if (r < 0 && r != -ENOENT) return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath); device->subsystem_set = true; + } else if (!device->driver_subsystem_set) + drivers = strstr(syspath, "/drivers/"); + + if (!device->driver_subsystem_set) { + if (drivers) { + _cleanup_free_ char *subpath = NULL; + + subpath = strndup(syspath, drivers - syspath); + if (!subpath) + r = -ENOMEM; + else { + const char *subsys; + + subsys = strrchr(subpath, '/'); + if (!subsys) + r = -EINVAL; + else + r = device_set_drivers_subsystem(device, subsys + 1); + } + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath); + } + + device->driver_subsystem_set = true; } if (!device->subsystem) @@ -1234,9 +1282,17 @@ int device_get_id_filename(sd_device *device, const char **ret) { if (!subsystem) return -EINVAL; - r = asprintf(&id, "+%s:%s", subsystem, sysname); - if (r < 0) - return -ENOMEM; + if (streq(subsystem, "drivers")) { + /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem + * encoded as well */ + r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname); + if (r < 0) + return -ENOMEM; + } else { + r = asprintf(&id, "+%s:%s", subsystem, sysname); + if (r < 0) + return -ENOMEM; + } } device->id_filename = id; -- cgit v1.2.3-54-g00ecf From 21d6220fe0bf24fda7df9833961e022cafa439bc Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 27 Jun 2016 09:58:59 +0200 Subject: sd-device: new_from_subsystem_sysnam - support a real subsystem called 'drivers' We support writing out tags and db files in case a real subsystem called 'drivers' exists, so there is no reason to refuse parsing it. --- src/libsystemd/sd-device/sd-device.c | 43 +++++++++++++++++------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index c13f6fca28..d503232505 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -259,7 +259,8 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) } _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) { - char *syspath; + char *name, *syspath; + size_t len = 0; assert_return(ret, -EINVAL); assert_return(subsystem, -EINVAL); @@ -298,33 +299,29 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver); if (access(syspath, F_OK) >= 0) return sd_device_new_from_syspath(ret, syspath); - } else - return -EINVAL; - } else { - char *name; - size_t len = 0; + } + } - /* translate sysname back to sysfs filename */ - name = strdupa(sysname); - while (name[len] != '\0') { - if (name[len] == '/') - name[len] = '!'; + /* translate sysname back to sysfs filename */ + name = strdupa(sysname); + while (name[len] != '\0') { + if (name[len] == '/') + name[len] = '!'; - len++; - } + len++; + } - syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name); - if (access(syspath, F_OK) >= 0) - return sd_device_new_from_syspath(ret, syspath); + syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name); + if (access(syspath, F_OK) >= 0) + return sd_device_new_from_syspath(ret, syspath); - syspath = strjoina("/sys/bus/", subsystem, "/devices/", name); - if (access(syspath, F_OK) >= 0) - return sd_device_new_from_syspath(ret, syspath); + syspath = strjoina("/sys/bus/", subsystem, "/devices/", name); + if (access(syspath, F_OK) >= 0) + return sd_device_new_from_syspath(ret, syspath); - syspath = strjoina("/sys/class/", subsystem, "/", name); - if (access(syspath, F_OK) >= 0) - return sd_device_new_from_syspath(ret, syspath); - } + syspath = strjoina("/sys/class/", subsystem, "/", name); + if (access(syspath, F_OK) >= 0) + return sd_device_new_from_syspath(ret, syspath); return -ENODEV; } -- cgit v1.2.3-54-g00ecf From 2027927b1002a74d24300704a655614f8ea48e45 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 27 Jun 2016 15:47:37 +0300 Subject: basic: pass flags to the fnmatch (#3606) Fixes: ``` $ systemctl list-unit-files 'hey\*' 0 unit files listed. $ systemctl list-unit-files | grep hey hey\x7eho.service static ``` --- src/basic/strv.c | 2 +- src/test/test-strv.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index 578a9c1005..4e8153421a 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -834,7 +834,7 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; STRV_FOREACH(p, patterns) - if (fnmatch(*p, s, 0) == 0) + if (fnmatch(*p, s, flags) == 0) return true; return false; diff --git a/src/test/test-strv.c b/src/test/test-strv.c index fc01dcfaf1..cf5887d258 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -685,6 +685,16 @@ static void test_foreach_string(void) { assert_se(streq(x, "zzz")); } +static void test_strv_fnmatch(void) { + _cleanup_free_ char **v = NULL; + + assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); + + v = strv_new("*\\*", NULL); + assert_se(!strv_fnmatch(v, "\\", 0)); + assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE)); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -750,6 +760,7 @@ int main(int argc, char *argv[]) { test_strv_make_nulstr(); test_foreach_string(); + test_strv_fnmatch(); return 0; } -- cgit v1.2.3-54-g00ecf From f9d14060ae09c7597a80c01188a6b15f33f9bcd3 Mon Sep 17 00:00:00 2001 From: 0xAX <0xAX@users.noreply.github.com> Date: Tue, 28 Jun 2016 00:26:07 +0300 Subject: basic/strv: introduce STRV_IGNORE macro (#3601) to hide casting of '-1' strings and make code cleaner. --- src/basic/strv.c | 10 +++++----- src/basic/strv.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index 4e8153421a..53298268f4 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -139,16 +139,16 @@ char **strv_new_ap(const char *x, va_list ap) { va_list aq; /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the + * STRV_IGNORE. This is supposed to be used with the * STRV_IFNOTNULL() macro to include possibly NULL strings in * the string list. */ if (x) { - n = x == (const char*) -1 ? 0 : 1; + n = x == STRV_IGNORE ? 0 : 1; va_copy(aq, ap); while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) + if (s == STRV_IGNORE) continue; n++; @@ -162,7 +162,7 @@ char **strv_new_ap(const char *x, va_list ap) { return NULL; if (x) { - if (x != (const char*) -1) { + if (x != STRV_IGNORE) { a[i] = strdup(x); if (!a[i]) goto fail; @@ -171,7 +171,7 @@ char **strv_new_ap(const char *x, va_list ap) { while ((s = va_arg(ap, const char*))) { - if (s == (const char*) -1) + if (s == STRV_IGNORE) continue; a[i] = strdup(s); diff --git a/src/basic/strv.h b/src/basic/strv.h index f61bbb5386..683ce83a2a 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -69,8 +69,10 @@ bool strv_equal(char **a, char **b); char **strv_new(const char *x, ...) _sentinel_; char **strv_new_ap(const char *x, va_list ap); +#define STRV_IGNORE ((const char *) -1) + static inline const char* STRV_IFNOTNULL(const char *x) { - return x ? x : (const char *) -1; + return x ? x : STRV_IGNORE; } static inline bool strv_isempty(char * const *l) { -- cgit v1.2.3-54-g00ecf From 94363cbbf38023bac4fc90595d2d839d25acfe38 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 28 Jun 2016 18:18:27 +0200 Subject: resolved: add test for route-only domain filtering (#3609) With commit 6f7da49d00 route-only domains do not get put into resolv.conf's "search" list any more. Add a comment about the tri-state, to clarify its semantics and why we are passing a bool parameter into an int type. Also add a test case for it. --- src/resolve/resolved-manager.c | 5 +++++ test/networkd-test.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index add463b6a9..92ade820ac 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1200,6 +1200,11 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { return 0; } +/* filter_route is a tri-state: + * < 0: no filtering + * = 0 or false: return only domains which should be used for searching + * > 0 or true: return only domains which are for routing only + */ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) { DnsSearchDomain *d; Iterator i; diff --git a/test/networkd-test.py b/test/networkd-test.py index 78da0a213a..8f5d43bc88 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -227,6 +227,37 @@ DHCP=%s def test_hotplug_dhcp_ip6(self): self.do_test(coldplug=False, ipv6=True) + def test_route_only_dns(self): + with open('/run/systemd/network/myvpn.netdev', 'w') as f: + f.write('''[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + with open('/run/systemd/network/myvpn.network', 'w') as f: + f.write('''[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains= ~company''') + self.addCleanup(os.remove, '/run/systemd/network/myvpn.netdev') + self.addCleanup(os.remove, '/run/systemd/network/myvpn.network') + + self.do_test(coldplug=True, ipv6=False, + extra_opts='IPv6AcceptRouterAdvertisements=False') + + if os.path.islink('/etc/resolv.conf'): + with open('/etc/resolv.conf') as f: + contents = f.read() + + # ~company is not a search domain, only a routing domain + self.assertNotRegex(contents, 'search.*company') + + # our global server should appear, unless we already have three + # (different) servers + if contents.count('nameserver ') < 3: + self.assertIn('nameserver 192.168.5.1\n', contents) + @unittest.skipUnless(have_dnsmasq, 'dnsmasq not installed') class DnsmasqClientTest(ClientTestBase, unittest.TestCase): -- cgit v1.2.3-54-g00ecf From a1abf5ea7fa1c3c3ef80937c8d349390ce3da39d Mon Sep 17 00:00:00 2001 From: Lénaïc Huard Date: Tue, 28 Jun 2016 20:15:33 +0200 Subject: Remove blank line in the output of “systemctl show” (#3614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “systemctl show” added an extra blank line after the dump of the EnvironmentFile property of the unit. --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c0b285b58f..e56b9b8957 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4367,7 +4367,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0) - print_prop("EnvironmentFile", "%s (ignore_errors=%s)\n", path, yes_no(ignore)); + print_prop("EnvironmentFile", "%s (ignore_errors=%s)", path, yes_no(ignore)); if (r < 0) return bus_log_parse_error(r); -- cgit v1.2.3-54-g00ecf From f3bd7561c54dea82b128d06f6b269a4951ae2855 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 15:27:07 -0400 Subject: journalctl: allow --file/--directory with --boot or --list-boots It works mostly fine, and can be quite useful to examine data from another system. OTOH, a single boot id doesn't make sense with --merge, so mixing with --merge is still not allowed. --- src/journal/journalctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 8e4897831b..ac55e68b90 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -868,8 +868,8 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && (arg_file || arg_directory || arg_merge)) { - log_error("Using --boot or --list-boots with --file, --directory or --merge is not supported."); + if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) { + log_error("Using --boot or --list-boots with --merge is not supported."); return -EINVAL; } -- cgit v1.2.3-54-g00ecf From 8453f06257f984a8dbeba92dfe02b52204c9abf8 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 15:39:56 -0400 Subject: journalct: do no allow --this-boot to take arguments Before --this-boot was deprecated in a331b5e6d47243, it did not take any arguments. --- src/journal/journalctl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index ac55e68b90..043c6d9630 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -348,6 +348,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_FULL, ARG_NO_TAIL, ARG_NEW_ID128, + ARG_THIS_BOOT, ARG_LIST_BOOTS, ARG_USER, ARG_SYSTEM, @@ -392,9 +393,9 @@ static int parse_argv(int argc, char *argv[]) { { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, { "quiet", no_argument, NULL, 'q' }, { "merge", no_argument, NULL, 'm' }, + { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */ { "boot", optional_argument, NULL, 'b' }, { "list-boots", no_argument, NULL, ARG_LIST_BOOTS }, - { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */ { "dmesg", no_argument, NULL, 'k' }, { "system", no_argument, NULL, ARG_SYSTEM }, { "user", no_argument, NULL, ARG_USER }, @@ -544,6 +545,10 @@ static int parse_argv(int argc, char *argv[]) { arg_merge = true; break; + case ARG_THIS_BOOT: + arg_boot = true; + break; + case 'b': arg_boot = true; -- cgit v1.2.3-54-g00ecf From 07ff6b0823adc82bead4e73a9c3659ed1bab9801 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 15:49:03 -0400 Subject: journalctl: use simpler variable names in get_boots() Those are just local variables and ref_boot_offset is especially obnoxious. --- src/journal/journalctl.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 043c6d9630..8c59bacc0b 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1107,13 +1107,13 @@ static int discover_next_boot(sd_journal *j, static int get_boots( sd_journal *j, BootId **boots, - sd_id128_t *query_ref_boot, - int ref_boot_offset) { + sd_id128_t *boot_id, + int offset) { bool skip_once; int r, count = 0; BootId *head = NULL, *tail = NULL; - const bool advance_older = query_ref_boot && ref_boot_offset <= 0; + const bool advance_older = boot_id && offset <= 0; sd_id128_t previous_boot_id; assert(j); @@ -1121,19 +1121,19 @@ static int get_boots( /* Adjust for the asymmetry that offset 0 is * the last (and current) boot, while 1 is considered the * (chronological) first boot in the journal. */ - skip_once = query_ref_boot && sd_id128_is_null(*query_ref_boot) && ref_boot_offset < 0; + skip_once = boot_id && sd_id128_is_null(*boot_id) && offset < 0; /* Advance to the earliest/latest occurrence of our reference * boot ID (taking our lookup direction into account), so that * discover_next_boot() can do its job. * If no reference is given, the journal head/tail will do, * they're "virtual" boots after all. */ - if (query_ref_boot && !sd_id128_is_null(*query_ref_boot)) { + if (boot_id && !sd_id128_is_null(*boot_id)) { char match[9+32+1] = "_BOOT_ID="; sd_journal_flush_matches(j); - sd_id128_to_string(*query_ref_boot, match + 9); + sd_id128_to_string(*boot_id, match + 9); r = sd_journal_add_match(j, match, sizeof(match) - 1); if (r < 0) return r; @@ -1153,7 +1153,7 @@ static int get_boots( return r; else if (r == 0) goto finish; - else if (ref_boot_offset == 0) { + else if (offset == 0) { count = 1; goto finish; } @@ -1192,14 +1192,14 @@ static int get_boots( previous_boot_id = current->id; - if (query_ref_boot) { + if (boot_id) { if (!skip_once) - ref_boot_offset += advance_older ? 1 : -1; + offset += advance_older ? 1 : -1; skip_once = false; - if (ref_boot_offset == 0) { + if (offset == 0) { count = 1; - *query_ref_boot = current->id; + *boot_id = current->id; break; } } else { @@ -1255,7 +1255,7 @@ static int list_boots(sd_journal *j) { static int add_boot(sd_journal *j) { char match[9+32+1] = "_BOOT_ID="; - sd_id128_t ref_boot_id; + sd_id128_t boot_id; int r; assert(j); @@ -1266,8 +1266,8 @@ static int add_boot(sd_journal *j) { if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL)) return add_match_this_boot(j, arg_machine); - ref_boot_id = arg_boot_id; - r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset); + boot_id = arg_boot_id; + r = get_boots(j, NULL, &boot_id, arg_boot_offset); assert(r <= 1); if (r <= 0) { const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); @@ -1282,7 +1282,7 @@ static int add_boot(sd_journal *j) { return r == 0 ? -ENODATA : r; } - sd_id128_to_string(ref_boot_id, match + 9); + sd_id128_to_string(boot_id, match + 9); r = sd_journal_add_match(j, match, sizeof(match) - 1); if (r < 0) -- cgit v1.2.3-54-g00ecf From 592855c3189549fed93b1060b72299910c6ab1d0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 16:12:47 -0400 Subject: journalct: allow --boot=0 to DTRT with --file/--directory --boot=0 magically meant "this boot", but when used with --file/--directory it should simply refer to the last boot found in the specified journal. This way, --boot and --list-boots are consistent. Fixes #3603. --- src/journal/journalctl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 8c59bacc0b..4cc0c2b6c2 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1121,7 +1121,7 @@ static int get_boots( /* Adjust for the asymmetry that offset 0 is * the last (and current) boot, while 1 is considered the * (chronological) first boot in the journal. */ - skip_once = boot_id && sd_id128_is_null(*boot_id) && offset < 0; + skip_once = boot_id && sd_id128_is_null(*boot_id) && offset <= 0; /* Advance to the earliest/latest occurrence of our reference * boot ID (taking our lookup direction into account), so that @@ -1263,7 +1263,12 @@ static int add_boot(sd_journal *j) { if (!arg_boot) return 0; - if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL)) + /* Take a shortcut and use the current boot_id, which we can do very quickly. + * We can do this only when we logs are coming from the current machine, + * so take the slow path if log location is specified. */ + if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL) && + !arg_directory && !arg_file) + return add_match_this_boot(j, arg_machine); boot_id = arg_boot_id; -- cgit v1.2.3-54-g00ecf From d6568222d74bdfbeb75e37e96b64248ec0145dea Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 29 Jun 2016 01:57:07 +0530 Subject: systemctl mask of an non-existent unit should print a warning (#3521) fixes https://bugzilla.redhat.com/show_bug.cgi?id=842060 --- src/systemctl/systemctl.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e56b9b8957..b575437bcb 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5605,6 +5605,46 @@ static int mangle_names(char **original_names, char ***mangled_names) { return 0; } +static int unit_exists(const char *unit) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL; + static const struct bus_properties_map property_map[] = { + { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, + { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state)}, + {}, + }; + UnitStatusInfo info = {}; + sd_bus *bus; + int r; + + path = unit_dbus_path_from_name(unit); + if (!path) + return log_oom(); + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", ""); + if (r < 0) + return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); + + r = bus_message_map_all_properties(reply, property_map, &info); + if (r < 0) + return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); + + return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive"); +} + static int enable_unit(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; const char *verb = argv[0]; @@ -5666,6 +5706,14 @@ static int enable_unit(int argc, char *argv[], void *userdata) { const char *method; sd_bus *bus; + if (STR_IN_SET(verb, "mask", "unmask")) { + r = unit_exists(*names); + if (r < 0) + return r; + if (r == 0) + log_notice("Unit %s does not exist, proceeding anyway.", *names); + } + r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From f0d5c5be5923f3342d0de1241e30650b1d57d551 Mon Sep 17 00:00:00 2001 From: Weng Xuetian Date: Wed, 29 Jun 2016 13:22:12 -0700 Subject: sd-bus: Fix a read after free error in bus-match. (#3624) (#3625) The loop on bus_match_run should break and return immediately if bus->match_callbacks_modified is true. Otherwise the loop may access free'd data. --- src/libsystemd/sd-bus/bus-match.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 397baf6f33..db01f21135 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -429,6 +429,9 @@ int bus_match_run( r = bus_match_run(bus, c, m); if (r != 0) return r; + + if (bus && bus->match_callbacks_modified) + return 0; } } -- cgit v1.2.3-54-g00ecf From 7486322b99da5b4d2d00d35b310b035f936f7964 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Jun 2016 19:03:26 -0700 Subject: sd-event: expose the event loop iteration counter via sd_event_get_iteration() This extends the existing event loop iteration counter to 64bit, and exposes it via a new function sd_event_get_iteration(). This is helpful for cases like issue #3612. After all, since we maintain the counter anyway, we might as well expose it. (This also fixes an unrelated issue in the man page for sd_event_wait() where micro and milliseconds got mixed up) --- Makefile-man.am | 5 +++++ man/sd_event_wait.xml | 22 ++++++++++++++++------ src/libsystemd/libsystemd.sym | 5 +++++ src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- src/systemd/sd-event.h | 1 + 5 files changed, 38 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Makefile-man.am b/Makefile-man.am index cd7583bed7..8ab733360d 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -338,6 +338,7 @@ MANPAGES_ALIAS += \ man/sd_event_default.3 \ man/sd_event_dispatch.3 \ man/sd_event_get_exit_code.3 \ + man/sd_event_get_iteration.3 \ man/sd_event_get_state.3 \ man/sd_event_get_tid.3 \ man/sd_event_get_watchdog.3 \ @@ -669,6 +670,7 @@ man/sd_event_child_handler_t.3: man/sd_event_add_child.3 man/sd_event_default.3: man/sd_event_new.3 man/sd_event_dispatch.3: man/sd_event_wait.3 man/sd_event_get_exit_code.3: man/sd_event_exit.3 +man/sd_event_get_iteration.3: man/sd_event_wait.3 man/sd_event_get_state.3: man/sd_event_wait.3 man/sd_event_get_tid.3: man/sd_event_new.3 man/sd_event_get_watchdog.3: man/sd_event_set_watchdog.3 @@ -1318,6 +1320,9 @@ man/sd_event_dispatch.html: man/sd_event_wait.html man/sd_event_get_exit_code.html: man/sd_event_exit.html $(html-alias) +man/sd_event_get_iteration.html: man/sd_event_wait.html + $(html-alias) + man/sd_event_get_state.html: man/sd_event_wait.html $(html-alias) diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index f2aea00e98..26327dc688 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -47,6 +47,7 @@ sd_event_prepare sd_event_dispatch sd_event_get_state + sd_event_get_iteration SD_EVENT_INITIAL SD_EVENT_PREPARING SD_EVENT_ARMED @@ -93,6 +94,12 @@ sd_event *event + + int sd_event_get_iteration + sd_event *event + uint64_t *ret + + @@ -140,12 +147,15 @@ determine the state the event loop is currently in. It returns one of the states described below. - All four functions take, as the first argument, the event - loop object event that has been created - with sd_event_new(). The timeout for - sd_event_wait() is specified in - usec in milliseconds. (uint64_t) - -1 may be used to specify an infinite timeout. + sd_event_get_iteration() may be used to determine the current iteration of the event + loop. It returns an unsigned 64bit integer containing a counter that increases monotonically with each iteration of + the event loop, starting with 0. The counter is increased at the time of the + sd_event_prepare() invocation. + + All five functions take, as the first argument, the event loop object event that has + been created with sd_event_new(). The timeout for sd_event_wait() is + specified in usec in microseconds. (uint64_t) -1 may be used to + specify an infinite timeout. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 0b3a1708dc..542254295c 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -495,3 +495,8 @@ global: sd_journal_open_directory_fd; sd_journal_open_files_fd; } LIBSYSTEMD_229; + +LIBSYSTEMD_231 { +global: + sd_event_get_iteration; +} LIBSYSTEMD_230; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f364b54b50..9857f8b1fc 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -109,8 +109,8 @@ struct sd_event_source { int64_t priority; unsigned pending_index; unsigned prepare_index; - unsigned pending_iteration; - unsigned prepare_iteration; + uint64_t pending_iteration; + uint64_t prepare_iteration; LIST_FIELDS(sd_event_source, sources); @@ -215,7 +215,7 @@ struct sd_event { pid_t original_pid; - unsigned iteration; + uint64_t iteration; triple_timestamp timestamp; int state; @@ -2874,3 +2874,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } + +_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + *ret = e->iteration; + return 0; +} diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 531ace1c34..cc26b7df55 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -104,6 +104,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); int sd_event_get_exit_code(sd_event *e, int *code); int sd_event_set_watchdog(sd_event *e, int b); int sd_event_get_watchdog(sd_event *e); +int sd_event_get_iteration(sd_event *e, uint64_t *ret); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); -- cgit v1.2.3-54-g00ecf From 34a8f0811c972aedd812468ae13bf9c18010c267 Mon Sep 17 00:00:00 2001 From: ottopotto Date: Thu, 30 Jun 2016 17:59:06 +0300 Subject: journalctl: Make temporary files directory configurable (#3574) journalctl: Use env variable TMPDIR to save temporary files --- src/basic/fs-util.c | 29 ++++++++++++++++++++++++++++ src/basic/fs-util.h | 2 ++ src/journal/journal-verify.c | 15 ++++++++++++--- src/test/test-fs-util.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index e24e7036f7..f0c6f3265e 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -38,6 +38,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -495,6 +496,34 @@ int get_files_in_directory(const char *path, char ***list) { return n; } +int var_tmp(char **ret) { + const char *tmp_dir = NULL; + const char *env_tmp_dir = NULL; + char *c = NULL; + int r; + + assert(ret); + + env_tmp_dir = getenv("TMPDIR"); + if (env_tmp_dir != NULL) { + r = is_dir(env_tmp_dir, true); + if (r < 0 && r != -ENOENT) + return r; + if (r > 0) + tmp_dir = env_tmp_dir; + } + + if (!tmp_dir) + tmp_dir = "/var/tmp"; + + c = strdup(tmp_dir); + if (!c) + return -ENOMEM; + *ret = c; + + return 0; +} + int inotify_add_watch_fd(int fd, int what, uint32_t mask) { char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; int r; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 517b599d6f..075e5942b1 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -61,6 +61,8 @@ int mkfifo_atomic(const char *path, mode_t mode); int get_files_in_directory(const char *path, char ***list); +int var_tmp(char **ret); + #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) #define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index a37316b8f9..f61f158e8a 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -26,6 +26,7 @@ #include "compress.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" @@ -825,6 +826,8 @@ int journal_file_verify( int data_fd = -1, entry_fd = -1, entry_array_fd = -1; unsigned i; bool found_last = false; + _cleanup_free_ char *tmp_dir = NULL; + #ifdef HAVE_GCRYPT uint64_t last_tag = 0; #endif @@ -843,19 +846,25 @@ int journal_file_verify( } else if (f->seal) return -ENOKEY; - data_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); + r = var_tmp(&tmp_dir); + if (r < 0) { + log_error_errno(r, "Failed to determine temporary directory: %m"); + goto fail; + } + + data_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC); if (data_fd < 0) { r = log_error_errno(data_fd, "Failed to create data file: %m"); goto fail; } - entry_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); + entry_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC); if (entry_fd < 0) { r = log_error_errno(entry_fd, "Failed to create entry file: %m"); goto fail; } - entry_array_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); + entry_array_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC); if (entry_array_fd < 0) { r = log_error_errno(entry_array_fd, "Failed to create entry array file: %m"); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 6db2c2b6f1..e0c040f39b 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -82,10 +82,56 @@ static void test_get_files_in_directory(void) { assert_se(get_files_in_directory(".", NULL) >= 0); } +static void test_var_tmp(void) { + char *tmp_dir = NULL; + char *tmpdir_backup = NULL; + const char *default_var_tmp = NULL; + const char *var_name; + bool do_overwrite = true; + + default_var_tmp = "/var/tmp"; + var_name = "TMPDIR"; + + if (getenv(var_name) != NULL) { + tmpdir_backup = strdup(getenv(var_name)); + assert_se(tmpdir_backup != NULL); + } + + unsetenv(var_name); + + var_tmp(&tmp_dir); + assert_se(!strcmp(tmp_dir, default_var_tmp)); + + free(tmp_dir); + + setenv(var_name, "/tmp", do_overwrite); + assert_se(!strcmp(getenv(var_name), "/tmp")); + + var_tmp(&tmp_dir); + assert_se(!strcmp(tmp_dir, "/tmp")); + + free(tmp_dir); + + setenv(var_name, "/88_does_not_exist_88", do_overwrite); + assert_se(!strcmp(getenv(var_name), "/88_does_not_exist_88")); + + var_tmp(&tmp_dir); + assert_se(!strcmp(tmp_dir, default_var_tmp)); + + free(tmp_dir); + + if (tmpdir_backup != NULL) { + setenv(var_name, tmpdir_backup, do_overwrite); + assert_se(!strcmp(getenv(var_name), tmpdir_backup)); + free(tmpdir_backup); + } +} + int main(int argc, char *argv[]) { test_unlink_noerrno(); test_readlink_and_make_absolute(); test_get_files_in_directory(); + test_var_tmp(); return 0; } -- cgit v1.2.3-54-g00ecf From 36f20ae3b2975e44b6ef17e453ae06a289e9a122 Mon Sep 17 00:00:00 2001 From: Kyle Walker Date: Thu, 30 Jun 2016 15:12:18 -0400 Subject: manager: Only invoke a single sigchld per unit within a cleanup cycle By default, each iteration of manager_dispatch_sigchld() results in a unit level sigchld event being invoked. For scope units, this results in a scope_sigchld_event() which can seemingly stall for workloads that have a large number of PIDs within the scope. The stall exhibits itself as a SIG_0 being initiated for each u->pids entry as a result of pid_is_unwaited(). v2: This patch resolves this condition by only paying to cost of a sigchld in the underlying scope unit once per sigchld iteration. A new "sigchldgen" member resides within the Unit struct. The Manager is incremented via the sd event loop, accessed via sd_event_get_iteration, and the Unit member is set to the same value as the manager each time that a sigchld event is invoked. If the Manager iteration value and Unit member match, the sigchld event is not invoked for that iteration. --- src/core/manager.c | 13 +++++++++++-- src/core/unit.c | 1 + src/core/unit.h | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 012aa6cd53..1323df7d88 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1716,16 +1716,25 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t } static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { + uint64_t iteration; + assert(m); assert(u); assert(si); + sd_event_get_iteration(m->event, &iteration); + log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); unit_unwatch_pid(u, si->si_pid); - if (UNIT_VTABLE(u)->sigchld_event) - UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + if (UNIT_VTABLE(u)->sigchld_event) { + if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + u->sigchldgen = iteration; + } else + log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); + } } static int manager_dispatch_sigchld(Manager *m) { diff --git a/src/core/unit.c b/src/core/unit.c index 0a1a5321df..8e5395361d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -100,6 +100,7 @@ Unit *unit_new(Manager *m, size_t size) { u->on_failure_job_mode = JOB_REPLACE; u->cgroup_inotify_wd = -1; u->job_timeout = USEC_INFINITY; + u->sigchldgen = 0; RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst); RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16); diff --git a/src/core/unit.h b/src/core/unit.h index 08a927962d..c41011ed9d 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -162,6 +162,9 @@ struct Unit { * process SIGCHLD for */ Set *pids; + /* Used in sigchld event invocation to avoid repeat events being invoked */ + uint64_t sigchldgen; + /* Used during GC sweeps */ unsigned gc_marker; -- cgit v1.2.3-54-g00ecf From 60a3b1e11ab0cef0f1e690a7c7117866113cf540 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jun 2016 12:25:07 -0700 Subject: sd-event: expose the event loop iteration counter via sd_event_get_iteration() (#3631) This extends the existing event loop iteration counter to 64bit, and exposes it via a new function sd_event_get_iteration(). This is helpful for cases like issue #3612. After all, since we maintain the counter anyway, we might as well expose it. (This also fixes an unrelated issue in the man page for sd_event_wait() where micro and milliseconds got mixed up) --- Makefile-man.am | 5 +++++ man/sd_event_wait.xml | 22 ++++++++++++++++------ src/libsystemd/libsystemd.sym | 5 +++++ src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- src/systemd/sd-event.h | 1 + 5 files changed, 38 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Makefile-man.am b/Makefile-man.am index cd7583bed7..8ab733360d 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -338,6 +338,7 @@ MANPAGES_ALIAS += \ man/sd_event_default.3 \ man/sd_event_dispatch.3 \ man/sd_event_get_exit_code.3 \ + man/sd_event_get_iteration.3 \ man/sd_event_get_state.3 \ man/sd_event_get_tid.3 \ man/sd_event_get_watchdog.3 \ @@ -669,6 +670,7 @@ man/sd_event_child_handler_t.3: man/sd_event_add_child.3 man/sd_event_default.3: man/sd_event_new.3 man/sd_event_dispatch.3: man/sd_event_wait.3 man/sd_event_get_exit_code.3: man/sd_event_exit.3 +man/sd_event_get_iteration.3: man/sd_event_wait.3 man/sd_event_get_state.3: man/sd_event_wait.3 man/sd_event_get_tid.3: man/sd_event_new.3 man/sd_event_get_watchdog.3: man/sd_event_set_watchdog.3 @@ -1318,6 +1320,9 @@ man/sd_event_dispatch.html: man/sd_event_wait.html man/sd_event_get_exit_code.html: man/sd_event_exit.html $(html-alias) +man/sd_event_get_iteration.html: man/sd_event_wait.html + $(html-alias) + man/sd_event_get_state.html: man/sd_event_wait.html $(html-alias) diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index f2aea00e98..26327dc688 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -47,6 +47,7 @@ sd_event_prepare sd_event_dispatch sd_event_get_state + sd_event_get_iteration SD_EVENT_INITIAL SD_EVENT_PREPARING SD_EVENT_ARMED @@ -93,6 +94,12 @@ sd_event *event + + int sd_event_get_iteration + sd_event *event + uint64_t *ret + + @@ -140,12 +147,15 @@ determine the state the event loop is currently in. It returns one of the states described below. - All four functions take, as the first argument, the event - loop object event that has been created - with sd_event_new(). The timeout for - sd_event_wait() is specified in - usec in milliseconds. (uint64_t) - -1 may be used to specify an infinite timeout. + sd_event_get_iteration() may be used to determine the current iteration of the event + loop. It returns an unsigned 64bit integer containing a counter that increases monotonically with each iteration of + the event loop, starting with 0. The counter is increased at the time of the + sd_event_prepare() invocation. + + All five functions take, as the first argument, the event loop object event that has + been created with sd_event_new(). The timeout for sd_event_wait() is + specified in usec in microseconds. (uint64_t) -1 may be used to + specify an infinite timeout. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 0b3a1708dc..542254295c 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -495,3 +495,8 @@ global: sd_journal_open_directory_fd; sd_journal_open_files_fd; } LIBSYSTEMD_229; + +LIBSYSTEMD_231 { +global: + sd_event_get_iteration; +} LIBSYSTEMD_230; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f364b54b50..9857f8b1fc 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -109,8 +109,8 @@ struct sd_event_source { int64_t priority; unsigned pending_index; unsigned prepare_index; - unsigned pending_iteration; - unsigned prepare_iteration; + uint64_t pending_iteration; + uint64_t prepare_iteration; LIST_FIELDS(sd_event_source, sources); @@ -215,7 +215,7 @@ struct sd_event { pid_t original_pid; - unsigned iteration; + uint64_t iteration; triple_timestamp timestamp; int state; @@ -2874,3 +2874,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } + +_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + *ret = e->iteration; + return 0; +} diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 531ace1c34..cc26b7df55 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -104,6 +104,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); int sd_event_get_exit_code(sd_event *e, int *code); int sd_event_set_watchdog(sd_event *e, int b); int sd_event_get_watchdog(sd_event *e); +int sd_event_get_iteration(sd_event *e, uint64_t *ret); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); -- cgit v1.2.3-54-g00ecf From 2cb623954f9df6bef85bca32933c75737ddc9a88 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jun 2016 15:56:23 -0700 Subject: Fix #3236 (#3633) * networkd: condition_test() can return a negative error, handle that If a condition check fails with an error we should not consider the check successful. Fix that. We should probably also improve logging in this case, but for now, let's just unbreak this breakage. Fixes: #3236 * condition: handle unrecognized architectures nicer When we encounter a check for an architecture we don't know we should not let the condition check fail with an error code, but instead simply return false. After all the architecture might just be newer than the ones we know, in which case it's certainly not our local one. Fixes: #3236 --- src/libsystemd-network/network-internal.c | 8 ++++---- src/shared/condition.c | 7 ++++--- src/test/test-condition.c | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index ce30b7fc25..9d78b953fc 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -102,16 +102,16 @@ bool net_match_config(const struct ether_addr *match_mac, const char *dev_type, const char *dev_name) { - if (match_host && !condition_test(match_host)) + if (match_host && condition_test(match_host) <= 0) return false; - if (match_virt && !condition_test(match_virt)) + if (match_virt && condition_test(match_virt) <= 0) return false; - if (match_kernel && !condition_test(match_kernel)) + if (match_kernel && condition_test(match_kernel) <= 0) return false; - if (match_arch && !condition_test(match_arch)) + if (match_arch && condition_test(match_arch) <= 0) return false; if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) diff --git a/src/shared/condition.c b/src/shared/condition.c index 3a45ed265c..6bb42c0692 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -182,10 +182,11 @@ static int condition_test_architecture(Condition *c) { if (streq(c->parameter, "native")) b = native_architecture(); - else + else { b = architecture_from_string(c->parameter); - if (b < 0) - return b; + if (b < 0) /* unknown architecture? Then it's definitely not ours */ + return false; + } return a == b; } diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 8903d10db7..987862f1c6 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -159,15 +159,15 @@ static void test_condition_test_architecture(void) { assert_se(sa); condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false); - assert_se(condition_test(condition) < 0); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } -- cgit v1.2.3-54-g00ecf From 1e706c8dff18dc8a9ccc0e1d0bf2b1a0fd79c501 Mon Sep 17 00:00:00 2001 From: Kyle Walker Date: Fri, 1 Jul 2016 13:03:35 -0400 Subject: manager: Fixing a debug printf formatting mistake (#3640) A 'llu' formatting statement was used in a debugging printf statement instead of a 'PRIu64'. Correcting that mistake here. --- src/core/manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 1323df7d88..902c2a0a27 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1733,7 +1733,7 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); u->sigchldgen = iteration; } else - log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); + log_debug("%s already issued a sigchld this iteration %" PRIu64 ", skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); } } -- cgit v1.2.3-54-g00ecf From 32b5236916296044a89532025e9fb5ef7e68ca8a Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Thu, 30 Jun 2016 20:16:05 -0400 Subject: calendarspec: allow ranges in date and time specifications Resolves #3042 --- TODO | 1 - man/systemd.time.xml | 5 +++- src/basic/calendarspec.c | 64 +++++++++++++++++++++++++++++++------------- src/test/test-calendarspec.c | 5 ++++ 4 files changed, 54 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/TODO b/TODO index 3af3126453..5208bdb818 100644 --- a/TODO +++ b/TODO @@ -565,7 +565,6 @@ Features: o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET) o DST changes - Support 2012-02~4 as syntax for specifying the fourth to last day of the month. - - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1 - Modulate timer frequency based on battery state * add libsystemd-password or so to query passwords during boot using the password agent logic diff --git a/man/systemd.time.xml b/man/systemd.time.xml index ffcac82263..6f9e88406d 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -227,7 +227,8 @@ values separated by commas. Values may also be suffixed with / and a repetition value, which indicates that the value and all values plus multiples of the repetition value - are matched. + are matched. Each component may also contain a range of values + separated by ... The seconds component may contain decimal fractions both in the value and the repetition. All fractions are rounded to 6 @@ -273,6 +274,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 monday *-12-* 17:00 → Mon *-12-* 17:00:00 Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45 12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00 + 12..14:10,20,30 → *-*-* 12,13,14:10,20,30:00 mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45 03-05 08:05:40 → *-03-05 08:05:40 08:05:40 → *-*-* 08:05:40 @@ -281,6 +283,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 2003-03-05 05:40 → 2003-03-05 05:40:00 05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001 + 2003-02..04-05 → 2003-02,03,04-05 00:00:00 2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC 2003-03-05 → 2003-03-05 00:00:00 03-05 → *-03-05 00:00:00 diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 6e0bab9b94..54ab909ddf 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -32,6 +32,8 @@ #include "parse-util.h" #include "string-util.h" +/* Longest valid date/time range is 1970..2199 */ +#define MAX_RANGE_LEN 230 #define BITS_WEEKDAYS 127 static void free_chain(CalendarComponent *c) { @@ -448,8 +450,26 @@ static int parse_component_decimal(const char **p, bool usec, unsigned long *res return 0; } +static int const_chain(int value, CalendarComponent **c) { + CalendarComponent *cc = NULL; + + assert(c); + + cc = new0(CalendarComponent, 1); + if (!cc) + return -ENOMEM; + + cc->value = value; + cc->repeat = 0; + cc->next = *c; + + *c = cc; + + return 0; +} + static int prepend_component(const char **p, bool usec, CalendarComponent **c) { - unsigned long value, repeat = 0; + unsigned long i, value, range_end, range_inc, repeat = 0; CalendarComponent *cc; int r; const char *e; @@ -471,6 +491,30 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) { if (repeat == 0) return -ERANGE; + } else if (e[0] == '.' && e[1] == '.') { + e += 2; + r = parse_component_decimal(&e, usec, &range_end); + if (r < 0) + return r; + + if (value >= range_end) + return -EINVAL; + + range_inc = usec ? USEC_PER_SEC : 1; + + /* Don't allow impossibly large ranges... */ + if (range_end - value >= MAX_RANGE_LEN * range_inc) + return -EINVAL; + + /* ...or ranges with only a single element */ + if (range_end - value < range_inc) + return -EINVAL; + + for (i = value; i <= range_end; i += range_inc) { + r = const_chain(i, c); + if (r < 0) + return r; + } } if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':') @@ -495,24 +539,6 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) { return 0; } -static int const_chain(int value, CalendarComponent **c) { - CalendarComponent *cc = NULL; - - assert(c); - - cc = new0(CalendarComponent, 1); - if (!cc) - return -ENOMEM; - - cc->value = value; - cc->repeat = 0; - cc->next = *c; - - *c = cc; - - return 0; -} - static int parse_chain(const char **p, bool usec, CalendarComponent **c) { const char *t; CalendarComponent *cc = NULL; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 5a8c6cbfb6..cb2538ed7f 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -124,6 +124,10 @@ int main(int argc, char* argv[]) { test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001"); test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); + test_one("9..11,13:00,30", "*-*-* 09,10,11,13:00,30:00"); + test_one("1..3-1..3 1..3:1..3", "*-01,02,03-01,02,03 01,02,03:01,02,03:00"); + test_one("00:00:1.125..2.125", "*-*-* 00:00:01.125000,02.125000"); + test_one("00:00:1.0..3.8", "*-*-* 00:00:01,02,03"); test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); @@ -146,6 +150,7 @@ int main(int argc, char* argv[]) { assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0); assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0); assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0); + assert_se(calendar_spec_from_string("00:00:00.0..00.9", &c) < 0); return 0; } -- cgit v1.2.3-54-g00ecf From e638d0504fa4861896f47c19e22b48c7f8ca3478 Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Thu, 30 Jun 2016 22:26:07 -0400 Subject: calendarspec: use ".." notation for ranges of weekdays For backwards compatibility, both the new format (Mon..Wed) and the old format (Mon-Wed) are supported. --- man/systemd.time.xml | 10 +++++----- src/basic/calendarspec.c | 24 ++++++++++++++++++------ src/test/test-calendarspec.c | 7 +++++-- 3 files changed, 28 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 6f9e88406d..9f0b2e1120 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -217,8 +217,8 @@ should consist of one or more English language weekday names, either in the abbreviated (Wed) or non-abbreviated (Wednesday) form (case does not matter), separated by commas. Specifying two - weekdays separated by - refers to a range of - continuous weekdays. , and - + weekdays separated by .. refers to a range of + continuous weekdays. , and .. may be combined freely. In the date and time specifications, any component may be @@ -263,12 +263,12 @@ Examples for valid timestamps and their normalized form: - Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00 + Sat,Thu,Mon..Wed,Sat..Sun → Mon..Thu,Sat,Sun *-*-* 00:00:00 Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00 Wed *-1 → Wed *-*-01 00:00:00 - Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00 + Wed..Wed,Wed *-1 → Wed *-*-01 00:00:00 Wed, 17:48 → Wed *-*-* 17:48:00 -Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 +Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03 *-*-7 0:0:0 → *-*-07 00:00:00 10-15 → *-10-15 00:00:00 monday *-12-* 17:00 → Mon *-12-* 17:00:00 diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 54ab909ddf..e4cfab364e 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -202,7 +202,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { }; int l, x; - bool need_colon = false; + bool need_comma = false; assert(f); assert(c); @@ -213,10 +213,10 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { if (c->weekdays_bits & (1 << x)) { if (l < 0) { - if (need_colon) + if (need_comma) fputc(',', f); else - need_colon = true; + need_comma = true; fputs(days[x], f); l = x; @@ -225,7 +225,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } else if (l >= 0) { if (x > l + 1) { - fputc(x > l + 2 ? '-' : ',', f); + fputs(x > l + 2 ? ".." : ",", f); fputs(days[x-1], f); } @@ -234,7 +234,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } if (l >= 0 && x > l + 1) { - fputc(x > l + 2 ? '-' : ',', f); + fputs(x > l + 2 ? ".." : ",", f); fputs(days[x-1], f); } } @@ -359,6 +359,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { skip = strlen(day_nr[i].name); if ((*p)[skip] != '-' && + (*p)[skip] != '.' && (*p)[skip] != ',' && (*p)[skip] != ' ' && (*p)[skip] != 0) @@ -396,7 +397,18 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { return 0; } - if (**p == '-') { + if (**p == '.') { + if (l >= 0) + return -EINVAL; + + if ((*p)[1] != '.') + return -EINVAL; + + l = day_nr[i].nr; + *p += 1; + + /* Support ranges with "-" for backwards compatibility */ + } else if (**p == '-') { if (l >= 0) return -EINVAL; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index cb2538ed7f..4a2b93de59 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -91,12 +91,15 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ int main(int argc, char* argv[]) { CalendarSpec *c; - test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon-Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon..Wed,Sat..Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00"); test_one("Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00"); + test_one("Wed..Wed,Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed, 17:48", "Wed *-*-* 17:48:00"); - test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue-Sat 2012-10-15 01:02:03"); + test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); + test_one("Wed..Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); test_one("*-*-7 0:0:0", "*-*-07 00:00:00"); test_one("10-15", "*-10-15 00:00:00"); test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00"); -- cgit v1.2.3-54-g00ecf From 3a1707fff139e957b915e392ac3b5a293c8dc17b Mon Sep 17 00:00:00 2001 From: 0xAX <0xAX@users.noreply.github.com> Date: Sat, 2 Jul 2016 18:17:26 +0300 Subject: sd-resolve: use close_many() (#3643) --- src/libsystemd/sd-resolve/sd-resolve.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d8303e2e69..60aa55de3b 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -585,9 +585,7 @@ static void resolve_free(sd_resolve *resolve) { (void) pthread_join(resolve->workers[i], NULL); /* Close all communication channels */ - for (i = 0; i < _FD_MAX; i++) - safe_close(resolve->fds[i]); - + close_many(resolve->fds, _FD_MAX); free(resolve); } -- cgit v1.2.3-54-g00ecf From 3b9a1d87cc468cfcd6f9ddfd98ac389fa5840f10 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sat, 2 Jul 2016 23:38:47 +0600 Subject: basic/fd-util: introduce stdio_unset_cloexec() function There are some places in the systemd which are use the same pattern: fd_cloexec(STDIN_FILENO, false); fd_cloexec(STDOUT_FILENO, false); fd_cloexec(STDERR_FILENO, false); to unset CLOEXEC for standard file descriptors. This patch introduces the stdio_unset_cloexec() function to hide this and make code cleaner. --- src/basic/fd-util.c | 6 ++++++ src/basic/fd-util.h | 1 + 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 8b466cff15..5c820332a5 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -186,6 +186,12 @@ int fd_cloexec(int fd, bool cloexec) { return 0; } +void stdio_unset_cloexec(void) { + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); +} + _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { unsigned i; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index b86e41698a..34b98d4aec 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -63,6 +63,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); +void stdio_unset_cloexec(void); int close_all_fds(const int except[], unsigned n_except); -- cgit v1.2.3-54-g00ecf From 913f38e4402ad19529b13fdb56db77eaa2b9f30a Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sat, 2 Jul 2016 23:42:01 +0600 Subject: treewide: use stdio_unset_cloexec() function --- src/basic/terminal-util.c | 4 +--- src/import/import-common.c | 8 ++------ src/import/importd.c | 4 +--- src/import/pull-common.c | 4 +--- 4 files changed, 5 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index d8cca55378..df56d85317 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -888,9 +888,7 @@ int make_stdio(int fd) { /* 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); + stdio_unset_cloexec(); return 0; } diff --git a/src/import/import-common.c b/src/import/import-common.c index 287a3382a1..81209cdaf6 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -125,9 +125,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) { if (null_fd != STDOUT_FILENO) null_fd = safe_close(null_fd); - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_cloexec(STDERR_FILENO, false); + stdio_unset_cloexec(); if (unshare(CLONE_NEWNET) < 0) log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); @@ -199,9 +197,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) { if (null_fd != STDIN_FILENO) null_fd = safe_close(null_fd); - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_cloexec(STDERR_FILENO, false); + stdio_unset_cloexec(); if (unshare(CLONE_NEWNET) < 0) log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); diff --git a/src/import/importd.c b/src/import/importd.c index 956a82945c..28b4302cb3 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -448,9 +448,7 @@ static int transfer_start(Transfer *t) { safe_close(null_fd); } - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_cloexec(STDERR_FILENO, false); + stdio_unset_cloexec(); setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1); setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1); diff --git a/src/import/pull-common.c b/src/import/pull-common.c index dc4e4667a9..2ae2a4174c 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -506,9 +506,7 @@ int pull_verify(PullJob *main_job, cmd[k++] = "-"; cmd[k++] = NULL; - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_cloexec(STDERR_FILENO, false); + stdio_unset_cloexec(); execvp("gpg2", (char * const *) cmd); execvp("gpg", (char * const *) cmd); -- cgit v1.2.3-54-g00ecf From 57681e84ce7c44ebc442bc3e7e22d487c4ce703a Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 4 Jul 2016 11:11:07 +0300 Subject: tests: fix memory leak in test_strv_fnmatch (#3653) ==1447== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==1447== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) ==1447== by 0x5350F19: strdup (in /usr/lib64/libc-2.23.so) ==1447== by 0x4E9D435: strv_new_ap (strv.c:166) ==1447== by 0x4E9D5FA: strv_new (strv.c:199) ==1447== by 0x10E665: test_strv_fnmatch (test-strv.c:693) ==1447== by 0x10EAD5: main (test-strv.c:763) ==1447== --- src/test/test-strv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/test-strv.c b/src/test/test-strv.c index cf5887d258..f7a1217df7 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -686,7 +686,7 @@ static void test_foreach_string(void) { } static void test_strv_fnmatch(void) { - _cleanup_free_ char **v = NULL; + _cleanup_strv_free_ char **v = NULL; assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); -- cgit v1.2.3-54-g00ecf From 6dd6a9c4930462a847e3f3924d88124ba9cc0522 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Thu, 12 May 2016 11:23:35 +0200 Subject: treewide: fix typos --- NEWS | 2 +- man/sd_bus_get_fd.xml | 2 +- man/systemd-nspawn.xml | 4 ++-- man/systemd.netdev.xml | 2 +- src/login/logind-core.c | 2 +- src/nspawn/nspawn-network.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index e4efb476c6..7a0d1d573e 100644 --- a/NEWS +++ b/NEWS @@ -851,7 +851,7 @@ CHANGES WITH 227: files controlled by the number of files that shall remain, in addition to the already existing control by size and by date. This is useful as journal interleaving performance - degrades with too many seperate journal files, and allows + degrades with too many separate journal files, and allows putting an effective limit on them. The new setting defaults to 100, but this may be changed by setting SystemMaxFiles= and RuntimeMaxFiles= in journald.conf. Also, the diff --git a/man/sd_bus_get_fd.xml b/man/sd_bus_get_fd.xml index 49162a6e65..9f7019069f 100644 --- a/man/sd_bus_get_fd.xml +++ b/man/sd_bus_get_fd.xml @@ -68,7 +68,7 @@ project='die-net'>select3, poll3, - or similar functions to wait for incmming messages. + or similar functions to wait for incoming messages. diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index c436f42948..cb0468fbf5 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -109,9 +109,9 @@ service in the background. In this mode each container instance runs as its own service instance; a default template unit file systemd-nspawn@.service is provided to make this easy, taking the container name as instance identifier. Note that different default options apply when systemd-nspawn is - invoked by the template unit file than interactively on the commnd line. Most importanly the template unit file + invoked by the template unit file than interactively on the command line. Most importantly the template unit file makes use of the which is not the default in case systemd-nspawn is - invoked from the interactive command line. Further differences with the defaults are documented dalong with the + invoked from the interactive command line. Further differences with the defaults are documented along with the various supported options below. The machinectl1 tool may diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 2be1efee2f..571e9aa946 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -163,7 +163,7 @@ A virtual extensible LAN (vxlan), for connecting Cloud computing deployments. vrf - A Virtual Routing and Forwarding (VRF) interface to create seperate routing and forwarding domains. + A Virtual Routing and Forwarding (VRF) interface to create separate routing and forwarding domains. diff --git a/src/login/logind-core.c b/src/login/logind-core.c index cbf8d757fe..eff5a4a36f 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -496,7 +496,7 @@ static int manager_count_external_displays(Manager *m) { continue; /* Ignore internal displays: the type is encoded in - * the sysfs name, as the second dash seperated item + * the sysfs name, as the second dash separated item * (the first is the card name, the last the connector * number). We implement a whitelist of external * displays here, rather than a whitelist, to ensure diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 8da47a2ca6..428cc04de0 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -350,7 +350,7 @@ int setup_bridge(const char *veth_name, const char *bridge_name, bool create) { if (create) { /* We take a system-wide lock here, so that we can safely check whether there's still a member in the - * bridge before removing it, without risking interferance from other nspawn instances. */ + * bridge before removing it, without risking interference from other nspawn instances. */ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock); if (r < 0) -- cgit v1.2.3-54-g00ecf From a17402291b627e330c44d1461c105de3277f4d88 Mon Sep 17 00:00:00 2001 From: Michał Bartoszkiewicz Date: Tue, 5 Jul 2016 19:23:23 +0200 Subject: systemd-run: really make -E an alias for --setenv (#3654) systemd-run --help says: -E --setenv=NAME=VALUE Set environment --- src/run/run.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/run/run.c b/src/run/run.c index d6c9b6d37a..58fa49a4d1 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -187,7 +187,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hrH:M:p:tq", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tq", options, NULL)) >= 0) switch (c) { -- cgit v1.2.3-54-g00ecf From 79c954405fd77e36c5567767676b81b79ed80ed5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 7 Jul 2016 06:30:34 +0200 Subject: basic: log: Increase static buffer for source file location (#3674) Commit d054f0a4 ("tree-wide: use xsprintf() where applicable") used a semantic patch approach to change a number of locations from snprintf(buf, sizeof(buf), FMT, ...) to xsprintf(buf, FMT, ...) The problem is that xsprintf() wraps the snprintf() in an assert_message_se(), so if snprintf() reports an overflow of the destination buffer, the binary will now terminate. This hit a user running a version of systemd that was built from a deeply nested system path. Fix this by a) Switching back to snprintf() for this particular case. We should really rather truncate the location string than crash in such situations. b) Increasing the size of that static string buffer, to make the event more unlikely. --- src/basic/log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/log.c b/src/basic/log.c index 3ea643b6e6..49b4598b7c 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -334,7 +334,7 @@ static int write_to_console( const char *object, const char *buffer) { - char location[64], prefix[1 + DECIMAL_STR_MAX(int) + 2]; + char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2]; struct iovec iovec[6] = {}; unsigned n = 0; bool highlight; @@ -350,7 +350,7 @@ static int write_to_console( highlight = LOG_PRI(level) <= LOG_ERR && show_color; if (show_location) { - xsprintf(location, "(%s:%i) ", file, line); + snprintf(location, sizeof(location), "(%s:%i) ", file, line); IOVEC_SET_STRING(iovec[n++], location); } -- cgit v1.2.3-54-g00ecf From 1280503b7e74cacfa091f7e270a89c5811388c2b Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Thu, 7 Jul 2016 12:36:33 +0200 Subject: execute: Cleanup the environment early By cleaning up before setting up PAM we maintain control of overriding behavior in setting variables. Otherwise, pam_putenv is in control. This also makes sure we use a cleaned up environment in replacing variables in argv. --- src/core/execute.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 8cb18dbd5b..1a7620b084 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1858,6 +1858,7 @@ static int exec_child( *exit_status = EXIT_MEMORY; return -ENOMEM; } + accum_env = strv_env_clean(accum_env); umask(context->umask); @@ -2166,8 +2167,6 @@ static int exec_child( return -ENOMEM; } - accum_env = strv_env_clean(accum_env); - if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { _cleanup_free_ char *line; -- cgit v1.2.3-54-g00ecf From 78a4ee591acc1424945ecfba517e97dc979cfd3b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 8 Jul 2016 04:29:35 +0200 Subject: cgroup: fix memory cgroup limit regression on kernel 3.10 (#3673) Commit da4d897e ("core: add cgroup memory controller support on the unified hierarchy (#3315)") changed the code in src/core/cgroup.c to always write the real numeric value from the cgroup parameters to the "memory.limit_in_bytes" attribute file. For parameters set to CGROUP_LIMIT_MAX, this results in the string "18446744073709551615" being written into that file, which is UINT64_MAX. Before that commit, CGROUP_LIMIT_MAX was special-cased to the string "-1". This causes a regression on CentOS 7, which is based on kernel 3.10, as the value is interpreted as *signed* 64 bit, and clamped to 0: [root@n54 ~]# echo 18446744073709551615 >/sys/fs/cgroup/memory/user.slice/memory.limit_in_bytes [root@n54 ~]# cat /sys/fs/cgroup/memory/user.slice/memory.limit_in_bytes 0 [root@n54 ~]# echo -1 >/sys/fs/cgroup/memory/user.slice/memory.limit_in_bytes [root@n54 ~]# cat /sys/fs/cgroup/memory/user.slice/memory.limit_in_bytes 9223372036854775807 Hence, all units that are subject to the limits enforced by the memory controller will crash immediately, even though they have no actual limit set. This happens to for the user.slice, for instance: [ 453.577153] Hardware name: SeaMicro SM15000-64-CC-AA-1Ox1/AMD Server CRB, BIOS Estoc.3.72.19.0018 08/19/2014 [ 453.587024] ffff880810c56780 00000000aae9501f ffff880813d7fcd0 ffffffff816360fc [ 453.594544] ffff880813d7fd60 ffffffff8163109c ffff88080ffc5000 ffff880813d7fd28 [ 453.602120] ffffffff00000202 fffeefff00000000 0000000000000001 ffff880810c56c03 [ 453.609680] Call Trace: [ 453.612156] [] dump_stack+0x19/0x1b [ 453.617324] [] dump_header+0x8e/0x214 [ 453.622671] [] oom_kill_process+0x24e/0x3b0 [ 453.628559] [] ? has_capability_noaudit+0x1e/0x30 [ 453.634969] [] mem_cgroup_oom_synchronize+0x575/0x5a0 [ 453.641721] [] ? mem_cgroup_charge_common+0xc0/0xc0 [ 453.648299] [] pagefault_out_of_memory+0x14/0x90 [ 453.654621] [] mm_fault_error+0x68/0x12b [ 453.660233] [] __do_page_fault+0x3e2/0x450 [ 453.666017] [] do_page_fault+0x23/0x80 [ 453.671467] [] page_fault+0x28/0x30 [ 453.676656] Task in /user.slice/user-0.slice/user@0.service killed as a result of limit of /user.slice/user-0.slice/user@0.service [ 453.688477] memory: usage 0kB, limit 0kB, failcnt 7 [ 453.693391] memory+swap: usage 0kB, limit 9007199254740991kB, failcnt 0 [ 453.700039] kmem: usage 0kB, limit 9007199254740991kB, failcnt 0 [ 453.706076] Memory cgroup stats for /user.slice/user-0.slice/user@0.service: cache:0KB rss:0KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB [ 453.725702] [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name [ 453.733614] [ 2837] 0 2837 11950 899 23 0 0 (systemd) [ 453.741919] Memory cgroup out of memory: Kill process 2837 ((systemd)) score 1 or sacrifice child [ 453.750831] Killed process 2837 ((systemd)) total-vm:47800kB, anon-rss:3188kB, file-rss:408kB Fix this issue by special-casing the UINT64_MAX case again. --- src/core/cgroup.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 932160d276..6e36e6b340 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -755,16 +755,20 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { cgroup_apply_unified_memory_limit(u, "memory.max", max); } else { char buf[DECIMAL_STR_MAX(uint64_t) + 1]; + uint64_t val = c->memory_limit; - if (c->memory_limit != CGROUP_LIMIT_MAX) - xsprintf(buf, "%" PRIu64 "\n", c->memory_limit); - else { - xsprintf(buf, "%" PRIu64 "\n", c->memory_max); + if (val == CGROUP_LIMIT_MAX) { + val = c->memory_max; - if (c->memory_max != CGROUP_LIMIT_MAX) - log_cgroup_compat(u, "Applying MemoryMax %" PRIu64 " as MemoryLimit", c->memory_max); + if (val != CGROUP_LIMIT_MAX) + log_cgroup_compat(u, "Applying MemoryMax %" PRIi64 " as MemoryLimit", c->memory_max); } + if (val == CGROUP_LIMIT_MAX) + strncpy(buf, "-1\n", sizeof(buf)); + else + xsprintf(buf, "%" PRIu64 "\n", val); + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); if (r < 0) log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, -- cgit v1.2.3-54-g00ecf From 4f952a3f07313e0373e568cb777cd90b27304b63 Mon Sep 17 00:00:00 2001 From: David Michael Date: Thu, 7 Jul 2016 20:43:01 -0700 Subject: core: queue loading transient units after setting their properties (#3676) The unit load queue can be processed in the middle of setting the unit's properties, so its load_state would no longer be UNIT_STUB for the check in bus_unit_set_properties(), which would cause it to incorrectly return an error. --- src/core/dbus-manager.c | 1 + src/core/unit.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 86722e1162..d05968bd65 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -781,6 +781,7 @@ static int transient_unit_from_message( return r; /* Now load the missing bits of the unit we just created */ + unit_add_to_load_queue(u); manager_dispatch_load_queue(m); *unit = u; diff --git a/src/core/unit.c b/src/core/unit.c index 8e5395361d..5f06a7dfe7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3505,7 +3505,6 @@ int unit_make_transient(Unit *u) { unit_add_to_dbus_queue(u); unit_add_to_gc_queue(u); - unit_add_to_load_queue(u); fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n", u->transient_file); -- cgit v1.2.3-54-g00ecf From 84eada2f7fc1b9039f783653c592e52f5ccab48f Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Thu, 7 Jul 2016 12:41:52 +0200 Subject: execute: Do not alter call-by-ref parameter on failure Prevent free from being called on (a part of) the call-by-reference variable env when setup_pam fails. --- src/core/execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 1a7620b084..8c487b371f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -835,7 +835,7 @@ static int setup_pam( pam_handle_t *handle = NULL; sigset_t old_ss; int pam_code = PAM_SUCCESS, r; - char **e = NULL; + char **nv, **e = NULL; bool close_session = false; pid_t pam_pid = 0, parent_pid; int flags = 0; @@ -870,8 +870,8 @@ static int setup_pam( goto fail; } - STRV_FOREACH(e, *env) { - pam_code = pam_putenv(handle, *e); + STRV_FOREACH(nv, *env) { + pam_code = pam_putenv(handle, *nv); if (pam_code != PAM_SUCCESS) goto fail; } -- cgit v1.2.3-54-g00ecf From 905c37e60ef653557d0354c2afa94546c31efe50 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Fri, 8 Jul 2016 17:43:05 +0200 Subject: udevadm: explicitly relabel /etc/udev/hwdb.bin after rename (#3686) This is basically the same change as ea68351. --- src/udev/udevadm-hwdb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 948ad0f5a5..1bffe8e8ab 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -28,6 +28,8 @@ #include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" +#include "label.h" +#include "mkdir.h" #include "strbuf.h" #include "string-util.h" #include "udev.h" @@ -656,12 +658,16 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { rc = EXIT_FAILURE; goto out; } - mkdir_parents(hwdb_bin, 0755); + + mkdir_parents_label(hwdb_bin, 0755); + err = trie_store(trie, hwdb_bin); if (err < 0) { log_error_errno(err, "Failure writing database %s: %m", hwdb_bin); rc = EXIT_FAILURE; } + + label_fix(hwdb_bin, false, false); } if (test) { -- cgit v1.2.3-54-g00ecf From d5db7fe66a349574a000f47c4bb5623064d47d86 Mon Sep 17 00:00:00 2001 From: WaLyong Cho Date: Thu, 7 Jul 2016 22:45:05 +0900 Subject: systemctl: show failed condition list When unit has multiple condition list, systemctl is not showing which conditions were failed. When user want to know which conditions were failed, user has to check for each conditions. So, show failed condition list also. --- src/systemctl/systemctl.c | 85 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b575437bcb..84278e9bdb 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3455,6 +3455,24 @@ static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) { return 1; } +typedef struct UnitCondition { + char *name; + bool trigger; + bool negate; + char *param; + int tristate; + + LIST_FIELDS(struct UnitCondition, condition); +} UnitCondition; + +static void unit_condition_free(UnitCondition *c) { + assert(c); + + free(c->name); + free(c->param); + free(c); +} + typedef struct UnitStatusInfo { const char *id; const char *load_state; @@ -3501,10 +3519,7 @@ typedef struct UnitStatusInfo { usec_t condition_timestamp; bool condition_result; - bool failed_condition_trigger; - bool failed_condition_negate; - const char *failed_condition; - const char *failed_condition_parameter; + LIST_HEAD(UnitCondition, condition); usec_t assert_timestamp; bool assert_result; @@ -3664,19 +3679,32 @@ static void print_status_info( printf("\n"); if (!i->condition_result && i->condition_timestamp > 0) { + UnitCondition *c; + int n = 0; + s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); printf("Condition: start %scondition failed%s at %s%s%s\n", ansi_highlight_yellow(), ansi_normal(), s2, s1 ? "; " : "", strempty(s1)); - if (i->failed_condition_trigger) - printf(" none of the trigger conditions were met\n"); - else if (i->failed_condition) - printf(" %s=%s%s was not met\n", - i->failed_condition, - i->failed_condition_negate ? "!" : "", - i->failed_condition_parameter); + + LIST_FOREACH(condition, c, i->condition) { + if (c->tristate < 0) + n++; + } + + LIST_FOREACH(condition, c, i->condition) { + if (c->tristate >= 0) + continue; + + printf(" %s %s=%s%s%s was not met\n", + --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT), + c->name, + c->trigger ? "|" : "", + c->negate ? "!" : "", + c->param); + } } if (!i->assert_result && i->assert_timestamp > 0) { @@ -4169,13 +4197,32 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &state)) > 0) { + UnitCondition *c; + log_debug("%s %d %d %s %d", cond, trigger, negate, param, state); - if (state < 0 && (!trigger || !i->failed_condition)) { - i->failed_condition = cond; - i->failed_condition_trigger = trigger; - i->failed_condition_negate = negate; - i->failed_condition_parameter = param; + + c = new0(UnitCondition, 1); + if (!c) + return log_oom(); + + c->name = strdup(cond); + if (!c->name) { + free(c); + return log_oom(); } + + c->param = strdup(param); + if (!c->param) { + free(c->name); + free(c); + return log_oom(); + } + + c->trigger = trigger; + c->negate = negate; + c->tristate = state; + + LIST_PREPEND(condition, i->condition, c); } if (r < 0) return bus_log_parse_error(r); @@ -4583,6 +4630,7 @@ static int show_one( .tasks_max = (uint64_t) -1, }; ExecStatusInfo *p; + UnitCondition *c; int r; assert(path); @@ -4701,6 +4749,11 @@ static int show_one( strv_free(info.dropin_paths); strv_free(info.listen); + while ((c = info.condition)) { + LIST_REMOVE(condition, info.condition, c); + unit_condition_free(c); + } + while ((p = info.exec)) { LIST_REMOVE(exec, info.exec, p); exec_status_info_free(p); -- cgit v1.2.3-54-g00ecf From 61233823aa4b0fe9605e0a7cd77261b3c5bca8e9 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Sun, 10 Jul 2016 14:48:23 +0200 Subject: treewide: fix typos and remove accidental repetition of words --- NEWS | 4 ++-- TODO | 4 ++-- hwdb/70-pointingstick.hwdb | 2 +- man/systemd.offline-updates.xml | 2 +- src/basic/copy.c | 2 +- src/basic/fileio.c | 2 +- src/basic/mount-util.c | 2 +- src/basic/strv.c | 2 +- src/basic/user-util.c | 2 +- src/core/cgroup.c | 2 +- src/core/execute.c | 2 +- src/core/execute.h | 2 +- src/core/killall.c | 2 +- src/core/load-fragment.c | 4 ++-- src/core/machine-id-setup.c | 2 +- src/core/main.c | 2 +- src/core/transaction.c | 4 ++-- src/core/unit.c | 2 +- src/coredump/coredump.c | 2 +- src/journal/journald-server.c | 2 +- src/journal/sd-journal.c | 2 +- src/libsystemd/sd-bus/bus-message.c | 4 ++-- src/libsystemd/sd-device/sd-device.c | 2 +- src/libudev/libudev-device.c | 2 +- src/machine/machined.c | 2 +- src/machine/operation.c | 4 ++-- src/network/networkd-link.c | 2 +- src/nspawn/nspawn-cgroup.c | 2 +- src/nss-myhostname/nss-myhostname.c | 2 +- src/resolve/resolved-dns-answer.c | 2 +- src/resolve/resolved-dns-cache.c | 2 +- src/resolve/resolved-dns-dnssec.c | 2 +- src/resolve/resolved-dns-query.c | 2 +- src/shared/path-lookup.c | 2 +- src/sysusers/sysusers.c | 2 +- src/udev/udev-event.c | 2 +- sysctl.d/50-default.conf | 2 +- tmpfiles.d/systemd-nspawn.conf | 2 +- 38 files changed, 44 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index 7a0d1d573e..dcc1d55048 100644 --- a/NEWS +++ b/NEWS @@ -569,7 +569,7 @@ CHANGES WITH 228: the service. * Timer units gained support for a new RemainAfterElapse= - setting which takes a boolean argument. It defaults on on, + setting which takes a boolean argument. It defaults on, exposing behaviour unchanged to previous releases. If set to off, timer units are unloaded after they elapsed if they cannot elapse again. This is particularly useful for @@ -5236,7 +5236,7 @@ CHANGES WITH 192: * We do not mount the "cpuset" controller anymore together with "cpu" and "cpuacct", as "cpuset" groups generally cannot be started if no parameters are assigned to it. "cpuset" hence - broke code that assumed it it could create "cpu" groups and + broke code that assumed it could create "cpu" groups and just start them. * journalctl -f will now subscribe to terminal size changes, diff --git a/TODO b/TODO index 5208bdb818..06659ee50d 100644 --- a/TODO +++ b/TODO @@ -126,7 +126,7 @@ Features: * docs: bring http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date * mounting and unmounting mount points manually with different source - devices will result in collected collected on all devices used. + devices will result in collected on all devices used. http://lists.freedesktop.org/archives/systemd-devel/2015-April/030225.html * add a job mode that will fail if a transaction would mean stopping @@ -554,7 +554,7 @@ Features: - systemctl enable: fail if target to alias into does not exist? maybe show how many units are enabled afterwards? - systemctl: "Journal has been rotated since unit was started." message is misleading - better error message if you run systemctl without systemd running - - systemctl status output should should include list of triggering units and their status + - systemctl status output should include list of triggering units and their status * unit install: - "systemctl mask" should find all names by which a unit is accessible diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb index 9adcf6d804..ec166ead40 100644 --- a/hwdb/70-pointingstick.hwdb +++ b/hwdb/70-pointingstick.hwdb @@ -69,7 +69,7 @@ # # -# Sort by by brand, model +# Sort by brand, model ######################################### # Dell diff --git a/man/systemd.offline-updates.xml b/man/systemd.offline-updates.xml index 946234ad90..ae53b8552d 100644 --- a/man/systemd.offline-updates.xml +++ b/man/systemd.offline-updates.xml @@ -93,7 +93,7 @@ As the first step, the update script should check if the - /system-update symlink points to the the location used by that update + /system-update symlink points to the location used by that update script. In case it does not exists or points to a different location, the script must exit without error. It is possible for multiple update services to be installed, and for multiple update scripts to be launched in parallel, and only the one that corresponds to the tool diff --git a/src/basic/copy.c b/src/basic/copy.c index c3586728d0..9883f5fa31 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -169,7 +169,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, * so reduce our maximum by the amount we already copied, * but don't go below our copy buffer size, unless we are - * close the the limit of bytes we are allowed to copy. */ + * close the limit of bytes we are allowed to copy. */ m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); } diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 0360a8eab3..47ccfc39d8 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1067,7 +1067,7 @@ int fflush_and_check(FILE *f) { return 0; } -/* This is much like like mkostemp() but is subject to umask(). */ +/* This is much like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { _cleanup_umask_ mode_t u = 0; int fd; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index ba698959b7..f5b5a70d21 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -104,7 +104,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * * As last fallback we do traditional fstat() based st_dev * comparisons. This is how things were traditionally done, - * but unionfs breaks breaks this since it exposes file + * but unionfs breaks this since it exposes file * systems with a variety of st_dev reported. Also, btrfs * subvolumes have different st_dev, even though they aren't * real mounts of their own. */ diff --git a/src/basic/strv.c b/src/basic/strv.c index 53298268f4..e0e2d1ebbe 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -876,7 +876,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) { if (n == 0) return 0; - /* Adds the value value n times to l */ + /* Adds the value n times to l */ k = strv_length(*l); diff --git a/src/basic/user-util.c b/src/basic/user-util.c index f65ca3edaa..e9d668ddfc 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -458,7 +458,7 @@ int take_etc_passwd_lock(const char *root) { * * Note that shadow-utils also takes per-database locks in * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep + * are redundant as they invoke lckpwdf() first and keep * it during everything they do. The per-database locks are * awfully racy, and thus we just won't do them. */ diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6e36e6b340..2ba1627b85 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1658,7 +1658,7 @@ int manager_setup_cgroup(Manager *m) { /* 3. Install agent */ if (unified) { - /* In the unified hierarchy we can can get + /* In the unified hierarchy we can get * cgroup empty notifications via inotify. */ m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source); diff --git a/src/core/execute.c b/src/core/execute.c index 8c487b371f..f4f5723c35 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2827,7 +2827,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { bool exec_context_maintains_privileges(ExecContext *c) { assert(c); - /* Returns true if the process forked off would run run under + /* Returns true if the process forked off would run under * an unchanged UID or as root. */ if (!c->user) diff --git a/src/core/execute.h b/src/core/execute.h index 210eea0e82..cacf66cf51 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -130,7 +130,7 @@ struct ExecContext { bool ignore_sigpipe; - /* Since resolving these names might might involve socket + /* Since resolving these names might involve socket * connections and we don't want to deadlock ourselves these * names are resolved on execution only and in the child * process. */ diff --git a/src/core/killall.c b/src/core/killall.c index 09378f7085..e1359b72d2 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -80,7 +80,7 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) { get_process_comm(pid, &comm); if (r) - log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is " + log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is " "running from the root file system, and thus likely to block re-mounting of the " "root file system to read-only. Please consider moving it into an initrd file " "system instead.", pid, strna(comm)); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 8295cf45a6..61b333b506 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3594,7 +3594,7 @@ int config_parse_protect_home( assert(data); /* Our enum shall be a superset of booleans, hence first try - * to parse as as boolean, and then as enum */ + * to parse as boolean, and then as enum */ k = parse_boolean(rvalue); if (k > 0) @@ -3637,7 +3637,7 @@ int config_parse_protect_system( assert(data); /* Our enum shall be a superset of booleans, hence first try - * to parse as as boolean, and then as enum */ + * to parse as boolean, and then as enum */ k = parse_boolean(rvalue); if (k > 0) diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 0145fe2894..ea6b085e4f 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -303,7 +303,7 @@ int machine_id_commit(const char *root) { if (r < 0) return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id); if (r == 0) { - log_debug("%s is is not a mount point. Nothing to do.", etc_machine_id); + log_debug("%s is not a mount point. Nothing to do.", etc_machine_id); return 0; } diff --git a/src/core/main.c b/src/core/main.c index 3d74ef1adf..fc04fb8051 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1444,7 +1444,7 @@ int main(int argc, char *argv[]) { /* * Do a dummy very first call to seal the kernel's time warp magic. * - * Do not call this this from inside the initrd. The initrd might not + * Do not call this from inside the initrd. The initrd might not * carry /etc/adjtime with LOCAL, but the real system could be set up * that way. In such case, we need to delay the time-warp or the sealing * until we reach the real system. diff --git a/src/core/transaction.c b/src/core/transaction.c index e06a48a2f1..af539171fd 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -373,7 +373,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi delete = NULL; for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { - /* logging for j not k here here to provide consistent narrative */ + /* logging for j not k here to provide consistent narrative */ log_unit_warning(j->unit, "Found dependency on %s/%s", k->unit->id, job_type_to_string(k->type)); @@ -392,7 +392,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi if (delete) { const char *status; - /* logging for j not k here here to provide consistent narrative */ + /* logging for j not k here to provide consistent narrative */ log_unit_warning(j->unit, "Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type)); diff --git a/src/core/unit.c b/src/core/unit.c index 5f06a7dfe7..1479d06606 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3790,7 +3790,7 @@ bool unit_is_pristine(Unit *u) { /* Check if the unit already exists or is already around, * in a number of different ways. Note that to cater for unit * types such as slice, we are generally fine with units that - * are marked UNIT_LOADED even even though nothing was + * are marked UNIT_LOADED even though nothing was * actually loaded, as those unit types don't require a file * on disk to validly load. */ diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 999de63900..82a54968e7 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -811,7 +811,7 @@ static int process_socket(int fd) { goto finish; } - /* Make sure we we got all data we really need */ + /* Make sure we got all data we really need */ assert(context[CONTEXT_PID]); assert(context[CONTEXT_UID]); assert(context[CONTEXT_GID]); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 8f82d2a838..b1cbda0fff 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1607,7 +1607,7 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, /* Dispatch one stream notification event */ stdout_stream_send_notify(s->stdout_streams_notify_queue); - /* Leave us enabled if there's still more to to do. */ + /* Leave us enabled if there's still more to do. */ if (s->send_watchdog || s->stdout_streams_notify_queue) return 0; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 1cea68ad42..75a0ffb49b 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1438,7 +1438,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) if (j->toplevel_fd < 0) d = opendir(path); else - /* Open the specified directory relative to the the toplevel fd. Enforce that the path specified is + /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is * relative, by dropping the initial slash */ d = xopendirat(j->toplevel_fd, skip_slash(path), 0); if (!d) { diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index b8958ec7bb..5cec804e32 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -181,7 +181,7 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, b if (!np) goto poison; } else { - /* Initially, the header is allocated as part of of + /* Initially, the header is allocated as part of * the sd_bus_message itself, let's replace it by * dynamic data */ @@ -2865,7 +2865,7 @@ static int bus_message_close_header(sd_bus_message *m) { /* The actual user data is finished now, we just complete the variant and struct now (at least on gvariant). Remember - this position, so that during parsing we know where to to + this position, so that during parsing we know where to put the outer container end. */ m->user_body_size = m->body_size; diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d503232505..0c4ad966bd 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -197,7 +197,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { return -errno; } } else { - /* everything else just just needs to be a directory */ + /* everything else just needs to be a directory */ if (!is_dir(syspath, false)) return -ENODEV; } diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 814e016800..995bf56586 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -619,7 +619,7 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device) * * Get the kernel device name in /sys. * - * Returns: the name string of the device device + * Returns: the name string of the device **/ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) { diff --git a/src/machine/machined.c b/src/machine/machined.c index f7ceb5e603..57121945f3 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -303,7 +303,7 @@ void manager_gc(Manager *m, bool drop_not_started) { machine_get_state(machine) != MACHINE_CLOSING) machine_stop(machine); - /* Now, the stop stop probably made this referenced + /* Now, the stop probably made this referenced * again, but if it didn't, then it's time to let it * go entirely. */ if (!machine_check_gc(machine, drop_not_started)) { diff --git a/src/machine/operation.c b/src/machine/operation.c index 8f8321a8b3..2bf93cb493 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -30,7 +30,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat assert(o); assert(si); - log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i", + log_debug("Operating " PID_FMT " is now complete with code=%s status=%i", o->pid, sigchld_code_to_string(si->si_code), si->si_status); @@ -59,7 +59,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat } } else { - /* The default default operaton when done is to simply return an error on failure or an empty success + /* The default operation when done is to simply return an error on failure or an empty success * message on success. */ if (r < 0) goto fail; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1842685180..2a9a7bb7c7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2173,7 +2173,7 @@ static int link_set_ipv6_forward(Link *link) { if (!link_ipv6_forward_enabled(link)) return 0; - /* On Linux, the IPv6 stack does not not know a per-interface + /* On Linux, the IPv6 stack does not know a per-interface * packet forwarding setting: either packet forwarding is on * for all, or off for all. We hence don't bother with a * per-interface setting, but simply propagate the interface diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index f50f1ad6c2..b1580236c9 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -123,7 +123,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) { int unified, r; CGroupMask supported; - /* In the unified hierarchy inner nodes may only only contain + /* In the unified hierarchy inner nodes may only contain * subgroups, but not processes. Hence, if we running in the * unified hierarchy and the container does the same, and we * did not create a scope unit for the container move us and diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 9a6e157e12..11c27575c0 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -96,7 +96,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( return NSS_STATUS_TRYAGAIN; } - /* We respond to our local host name, our our hostname suffixed with a single dot. */ + /* We respond to our local host name, our hostname suffixed with a single dot. */ if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) { *errnop = ENOENT; *h_errnop = HOST_NOT_FOUND; diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 13dcba8421..ab85754bf7 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -702,7 +702,7 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) { if (a->items[i].rr->key->class == DNS_CLASS_IN && ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) || (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local))) - /* Order address records that are are not preferred to the end of the array */ + /* Order address records that are not preferred to the end of the array */ items[end--] = a->items[i]; else /* Order all other records to the beginning of the array */ diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 87f7c21d03..9233fb0ac1 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -691,7 +691,7 @@ int dns_cache_put( return 0; /* See https://tools.ietf.org/html/rfc2308, which say that a - * matching SOA record in the packet is used to to enable + * matching SOA record in the packet is used to enable * negative caching. */ r = dns_answer_find_soa(answer, key, &soa, &flags); if (r < 0) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index a54aed3a63..d4a267c89f 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -1642,7 +1642,7 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) { if (r <= 0) return r; - /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ + /* If the name we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index c8af5579f0..53be18efc6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -520,7 +520,7 @@ int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) { assert(q); assert(auxiliary_for); - /* Ensure that that the query is not auxiliary yet, and + /* Ensure that the query is not auxiliary yet, and * nothing else is auxiliary to it either */ assert(!q->auxiliary_for); assert(!q->auxiliary_queries); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index ca593b6963..862096ae7b 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -88,7 +88,7 @@ static int user_data_dir(char **ret, const char *suffix) { assert(suffix); /* We don't treat /etc/xdg/systemd here as the spec - * suggests because we assume that that is a link to + * suggests because we assume that is a link to * /etc/systemd/ anyway. */ e = getenv("XDG_DATA_HOME"); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 4377f1b910..787d68a009 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1418,7 +1418,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) { - log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]); + log_error("[%s:%u] Unknown command type '%c'.", fname, line, action[0]); return -EBADMSG; } diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 8d601c9c2c..54cd741bb1 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -249,7 +249,7 @@ subst: if (event->program_result == NULL) break; - /* get part part of the result string */ + /* get part of the result string */ i = 0; if (attr != NULL) i = strtoul(attr, &rest, 10); diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf index def151bb84..f08f32e849 100644 --- a/sysctl.d/50-default.conf +++ b/sysctl.d/50-default.conf @@ -5,7 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See sysctl.d(5) and core(5) for for documentation. +# See sysctl.d(5) and core(5) for documentation. # To override settings in this file, create a local file in /etc # (e.g. /etc/sysctl.d/90-override.conf), and put any assignments diff --git a/tmpfiles.d/systemd-nspawn.conf b/tmpfiles.d/systemd-nspawn.conf index 9fa3878d6b..78bd1c670e 100644 --- a/tmpfiles.d/systemd-nspawn.conf +++ b/tmpfiles.d/systemd-nspawn.conf @@ -10,7 +10,7 @@ Q /var/lib/machines 0700 - - - # Remove old temporary snapshots, but only at boot. Ideally we'd have -# "self-destroying" btrfs snapshots that go away if the last last +# "self-destroying" btrfs snapshots that go away if the last # reference to it does. To mimic a scheme like this at least remove # the old snapshots on fresh boots, where we know they cannot be # referenced anymore. Note that we actually remove all temporary files -- cgit v1.2.3-54-g00ecf From 391b81cd03f0829e8a5c45b0eaefad4ef41f1285 Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Tue, 12 Jul 2016 11:55:26 +0200 Subject: seccomp: only abort on syscall name resolution failures (#3701) seccomp_syscall_resolve_name() can return a mix of positive and negative (pseudo-) syscall numbers, while errors are signaled via __NR_SCMP_ERROR. This commit lets the syscall filter parser only abort on real parsing failures, letting libseccomp handle pseudo-syscall number on its own and allowing proper multiplexed syscalls filtering. --- src/core/load-fragment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 61b333b506..782e420e4c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2429,7 +2429,7 @@ static int syscall_filter_parse_one( int id; id = seccomp_syscall_resolve_name(t); - if (id < 0) { + if (id == __NR_SCMP_ERROR) { if (warn) log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); return 0; -- cgit v1.2.3-54-g00ecf From 595bfe7df2999cfb99b274ce510695aed4aba6d5 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 12 Jul 2016 12:52:11 +0200 Subject: Various fixes for typos found by lintian (#3705) --- NEWS | 4 ++-- man/libudev.xml | 2 +- man/sd_event_add_time.xml | 2 +- man/systemd-socket-activate.xml | 2 +- man/systemd.special.xml | 2 +- man/systemd.timer.xml | 2 +- src/boot/bootctl.c | 2 +- src/core/cgroup.c | 2 +- src/core/unit.c | 4 ++-- src/journal-remote/microhttpd-util.c | 2 +- src/libsystemd-network/lldp-neighbor.c | 2 +- src/libsystemd/sd-login/sd-login.c | 2 +- src/machine/machined-dbus.c | 2 +- src/network/networkd-link.c | 4 ++-- src/nspawn/nspawn.c | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index dcc1d55048..bdba05eb2a 100644 --- a/NEWS +++ b/NEWS @@ -569,7 +569,7 @@ CHANGES WITH 228: the service. * Timer units gained support for a new RemainAfterElapse= - setting which takes a boolean argument. It defaults on, + setting which takes a boolean argument. It defaults to on, exposing behaviour unchanged to previous releases. If set to off, timer units are unloaded after they elapsed if they cannot elapse again. This is particularly useful for @@ -760,7 +760,7 @@ CHANGES WITH 227: * Support for USB FunctionFS activation has been added. This allows implementation of USB gadget services that are activated as soon as they are requested, so that they don't - have to run continously, similar to classic socket + have to run continuously, similar to classic socket activation. * The "systemctl exit" command now optionally takes an diff --git a/man/libudev.xml b/man/libudev.xml index 7ef978463c..53b68dcc89 100644 --- a/man/libudev.xml +++ b/man/libudev.xml @@ -81,7 +81,7 @@ To introspect a local device on a system, a udev device object can be created via udev_device_new_from_syspath3 - and friends. The device object allows to query current state, + and friends. The device object allows one to query current state, read and write attributes and lookup properties of the device in question. diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index 2c0bd0ba10..5496b71529 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -123,7 +123,7 @@ regarding the various types of clocks. The usec parameter specifies the earliest time, in microseconds (µs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past is specified (including 0), this timer source "fires" immediately and is ready to be - dispatched. If the paramater is specified as UINT64_MAX the timer event will never elapse, + dispatched. If the parameter is specified as UINT64_MAX the timer event will never elapse, which may be used as an alternative to explicitly disabling a timer event source with sd_event_source_set_enabled3. The accuracy parameter specifies an additional accuracy value in µs specifying how much the diff --git a/man/systemd-socket-activate.xml b/man/systemd-socket-activate.xml index 5d7f157c72..2cf3a7d377 100644 --- a/man/systemd-socket-activate.xml +++ b/man/systemd-socket-activate.xml @@ -142,7 +142,7 @@ FileDescriptorName= in socket unit files, and enables use of sd_listen_fds_with_names3. Multiple entries may be specifies using separate options or by separating names with colons - (:) in one option. In case more names are given than descriptors, superflous ones willl be + (:) in one option. In case more names are given than descriptors, superfluous ones willl be ignored. In case less names are given than descriptors, the remaining file descriptors will be unnamed. diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 19ca6d6837..9d79315069 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -473,7 +473,7 @@ systemd-fstab-generator3 and systemd-gpt-auto-generator3 - automatically setup the appropiate dependencies to make this happen. + automatically setup the appropriate dependencies to make this happen. diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 0fa95e97a8..4fe140e4bc 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -76,7 +76,7 @@ Note that in case the unit to activate is already active at the time the timer elapses it is not restarted, but simply left running. There is no concept of spawning new service instances in this case. Due to this, services - with RemainAfterExit= set (which stay around continously even after the service's main process + with RemainAfterExit= set (which stay around continuously even after the service's main process exited) are usually not suitable for activation via repetitive timers, as they will only be activated once, and then stay around forever. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index d0af41498f..0d42948720 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -101,7 +101,7 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t errno = 0; r = blkid_do_safeprobe(b); if (r == -2) { - log_error("File system \"%s\" is ambigious.", p); + log_error("File system \"%s\" is ambiguous.", p); return -ENODEV; } else if (r == 1) { log_error("File system \"%s\" does not contain a label.", p); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 2ba1627b85..94d1161605 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1136,7 +1136,7 @@ int unit_watch_cgroup(Unit *u) { /* Only applies to the unified hierarchy */ r = cg_unified(); if (r < 0) - return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m"); + return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m"); if (r == 0) return 0; diff --git a/src/core/unit.c b/src/core/unit.c index 1479d06606..fdf7ce3af3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1683,7 +1683,7 @@ static void unit_check_unneeded(Unit *u) { if (unit_active_or_pending(other)) return; - /* If stopping a unit fails continously we might enter a stop + /* If stopping a unit fails continuously we might enter a stop * loop here, hence stop acting on the service being * unnecessary after a while. */ if (!ratelimit_test(&u->auto_stop_ratelimit)) { @@ -1728,7 +1728,7 @@ static void unit_check_binds_to(Unit *u) { if (!stop) return; - /* If stopping a unit fails continously we might enter a stop + /* If stopping a unit fails continuously we might enter a stop * loop here, hence stop acting on the service being * unnecessary after a while. */ if (!ratelimit_test(&u->auto_stop_ratelimit)) { diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index c65c43186f..2f16b02e9a 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -60,7 +60,7 @@ static int mhd_respond_internal(struct MHD_Connection *connection, if (!response) return MHD_NO; - log_debug("Queing response %u: %s", code, buffer); + log_debug("Queueing response %u: %s", code, buffer); MHD_add_response_header(response, "Content-Type", "text/plain"); r = MHD_queue_response(connection, code, response); MHD_destroy_response(response); diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 88f7e329b0..53e29377b3 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -197,7 +197,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { assert(n); if (n->raw_size < sizeof(struct ether_header)) { - log_lldp("Recieved truncated packet, ignoring."); + log_lldp("Received truncated packet, ignoring."); return -EBADMSG; } diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 9d4f187502..3fcefada3f 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -124,7 +124,7 @@ _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) { /* The internal APIs return the empty string for the root * cgroup, let's return the "/" in the public APIs instead, as - * that's easier and less ambigious for people to grok. */ + * that's easier and less ambiguous for people to grok. */ if (isempty(c)) { free(c); c = strdup("/"); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 52ce83a185..1923e8b971 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -953,7 +953,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this - * continously */ + * continuously */ result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC); if (result_fd < 0) return -errno; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2a9a7bb7c7..82f56158be 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2726,7 +2726,7 @@ network_file_fail: r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in); if (r < 0) - return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address); + return log_link_error_errno(link, r, "Falied to set initial DHCPv4 address %s: %m", dhcp4_address); } dhcp4_address_fail: @@ -2744,7 +2744,7 @@ dhcp4_address_fail: r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); if (r < 0) - return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address); + return log_link_error_errno(link, r, "Falied to set initial IPv4LL address %s: %m", ipv4ll_address); } ipv4ll_address_fail: diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 73c56d7310..0bab2557b0 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2873,7 +2873,7 @@ static int outer_child( if (l < 0) return log_error_errno(errno, "Failed to recv UID shift: %m"); if (l != sizeof(arg_uid_shift)) { - log_error("Short read while recieving UID shift."); + log_error("Short read while receiving UID shift."); return -EIO; } } -- cgit v1.2.3-54-g00ecf From d450612953e6881e2dcbbad7e638160b73a83d77 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Jul 2016 17:18:43 +0200 Subject: shutdown: use 90s SIGKILL timeout There's really no reason to use 10s here, let's instead default to 90s like we do for everything else. The SIGKILL during the final killing spree is in most regards the fourth level of a safety net, after all: any normal service should have already been stopped during the normal service shutdown logic, first via SIGTERM and then SIGKILL, and then also via SIGTERM during the finall killing spree before we send SIGKILL. And as a fourth level safety net it should only be required in exceptional cases, which means it's safe to rais the default timeout, as normal shutdowns should never be delayed by it. Note that journald excludes itself from the normal service shutdown, and relies on the final killing spree to terminate it (this is because it wants to cover the normal shutdown phase's complete logging). If the system's IO is excessively slow, then the 10s might not be enough for journald to sync everything to disk and logs might get lost during shutdown. --- src/core/killall.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/killall.c b/src/core/killall.c index e1359b72d2..a8b814e868 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -23,6 +23,7 @@ #include #include "alloc-util.h" +#include "def.h" #include "fd-util.h" #include "formats-util.h" #include "killall.h" @@ -33,8 +34,6 @@ #include "terminal-util.h" #include "util.h" -#define TIMEOUT_USEC (10 * USEC_PER_SEC) - static bool ignore_proc(pid_t pid, bool warn_rootfs) { _cleanup_fclose_ FILE *f = NULL; char c; @@ -99,7 +98,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) { if (set_isempty(pids)) return; - until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC; + until = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC; for (;;) { struct timespec ts; int k; -- cgit v1.2.3-54-g00ecf From 2e79d1828a8da9b3af1b052297e3617905ec94f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Jul 2016 17:26:52 +0200 Subject: shutdown: already sync IO before we enter the final killing spree This way, slow IO journald has to wait for can't cause it to reach the killing spree timeout and is hit by SIGKILL in addition to SIGTERM. --- src/core/shutdown.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/shutdown.c b/src/core/shutdown.c index e14755d84e..a795d875bb 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -157,7 +157,6 @@ static int switch_root_initramfs(void) { return switch_root("/run/initramfs", "/oldroot", false, MS_BIND); } - int main(int argc, char *argv[]) { bool need_umount, need_swapoff, need_loop_detach, need_dm_detach; bool in_container, use_watchdog = false; @@ -203,20 +202,25 @@ int main(int argc, char *argv[]) { } (void) cg_get_root_path(&cgroup); + in_container = detect_container() > 0; use_watchdog = !!getenv("WATCHDOG_USEC"); - /* lock us into memory */ + /* Lock us into memory */ mlockall(MCL_CURRENT|MCL_FUTURE); + /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that + * slow IO is processed here already and the final process killing spree is not impacted by processes + * desperately trying to sync IO to disk within their timeout. */ + if (!in_container) + sync(); + log_info("Sending SIGTERM to remaining processes..."); broadcast_signal(SIGTERM, true, true); log_info("Sending SIGKILL to remaining processes..."); broadcast_signal(SIGKILL, true, false); - in_container = detect_container() > 0; - need_umount = !in_container; need_swapoff = !in_container; need_loop_detach = !in_container; @@ -345,10 +349,10 @@ int main(int argc, char *argv[]) { need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); - /* The kernel will automaticall flush ATA disks and suchlike - * on reboot(), but the file systems need to be synce'd - * explicitly in advance. So let's do this here, but not - * needlessly slow down containers. */ + /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be + * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we + * sync'ed things already once above, but we did some more work since then which might have caused IO, hence + * let's doit once more. */ if (!in_container) sync(); -- cgit v1.2.3-54-g00ecf From 0a86e6814795782aa4f34a650ef0388200bcc50f Mon Sep 17 00:00:00 2001 From: Valentin Vidić Date: Thu, 14 Jul 2016 07:34:36 +0200 Subject: basic/mount-util: recognize ocfs2 as network fs (#3713) --- src/basic/mount-util.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index f5b5a70d21..90b7a885a8 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -500,6 +500,7 @@ bool fstype_is_network(const char *fstype) { "gfs2\0" "glusterfs\0" "pvfs2\0" /* OrangeFS */ + "ocfs2\0" ; const char *x; -- cgit v1.2.3-54-g00ecf From d3a37494e6e8ee9de7f4a018076d28bdf0e665ac Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Thu, 14 Jul 2016 22:42:10 +0200 Subject: Fix tablet detection, by replicating decision tree of non-multi-touch axes (#3724) Signed-off-by: Andreas Pokorny --- src/udev/udev-builtin-input_id.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 51a55cdbc4..59b9804dc4 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -210,8 +210,14 @@ static bool test_pointers(struct udev_device *dev, else if (has_joystick_axes_or_buttons) is_joystick = true; } - if (has_mt_coordinates && (is_direct || has_touch)) - is_touchscreen = true; + if (has_mt_coordinates) { + if (stylus_or_pen) + is_tablet = true; + else if (finger_but_no_pen && !is_direct) + is_touchpad = true; + else if (has_touch || is_direct) + is_touchscreen = true; + } if (has_rel_coordinates && has_mouse_button) is_mouse = true; -- cgit v1.2.3-54-g00ecf From a34349e73348d16d0f41910a38f515f78d18d396 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 15 Jul 2016 04:56:11 +0200 Subject: network-ndisc: avoid VLAs (#3725) Do not allocate objects of dynamic and potentially large size on the stack to avoid both clang compilation errors and unpredictable runtime behavior on exotic platforms. Use the heap for that instead. While at it, refactor the code a bit. Access 's->domain' via NDISC_DNSSL_DOMAIN(), and refrain from allocating 'x' independently, but rather reuse 's' if we're dealing with a new entry to the set. Fixes #3717 --- src/network/networkd-ndisc.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 2a1ba2bac7..d9c18b32a5 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -449,22 +449,24 @@ static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { } STRV_FOREACH(i, l) { - struct { - NDiscDNSSL header; - char domain[strlen(*i)]; - } s; + _cleanup_free_ NDiscDNSSL *s; NDiscDNSSL *x; - zero(s.header); - strcpy(s.domain, *i); + s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1); + if (!s) { + log_oom(); + return; + } + + strcpy(NDISC_DNSSL_DOMAIN(s), *i); if (lifetime == 0) { - (void) set_remove(link->ndisc_dnssl, &s); + (void) set_remove(link->ndisc_dnssl, s); link_dirty(link); continue; } - x = set_get(link->ndisc_dnssl, &s); + x = set_get(link->ndisc_dnssl, s); if (x) { x->valid_until = time_now + lifetime * USEC_PER_SEC; continue; @@ -483,22 +485,15 @@ static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { return; } - x = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1); - if (!x) { - log_oom(); - return; - } + s->valid_until = time_now + lifetime * USEC_PER_SEC; - strcpy(NDISC_DNSSL_DOMAIN(x), *i); - x->valid_until = time_now + lifetime * USEC_PER_SEC; - - r = set_put(link->ndisc_dnssl, x); + r = set_put(link->ndisc_dnssl, s); if (r < 0) { - free(x); log_oom(); return; } + s = NULL; assert(r > 0); link_dirty(link); } -- cgit v1.2.3-54-g00ecf From 1071fd0823eb744c097597c62dc92c837df57e20 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 15 Jul 2016 03:35:49 -0400 Subject: macros: provide %_systemdgeneratordir and %_systemdusergeneratordir (#3672) ... as requested in https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/message/DJ7HDNRM5JGBSA4HL3UWW5ZGLQDJ6Y7M/. Adding the macro makes it marginally easier to create generators for outside projects. I opted for "generatordir" and "usergeneratordir" to match %unitdir and %userunitdir. OTOH, "_systemd" prefix makes it obvious that this is related to systemd. "%_generatordir" would be to generic of a name. --- src/core/macros.systemd.in | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in index 2cace3d3ba..028db1cc4a 100644 --- a/src/core/macros.systemd.in +++ b/src/core/macros.systemd.in @@ -29,6 +29,8 @@ %_sysusersdir @sysusersdir@ %_sysctldir @sysctldir@ %_binfmtdir @binfmtdir@ +%_systemdgeneratordir @systemgeneratordir@ +%_systemdusergeneratordir @usergeneratordir@ %systemd_requires \ Requires(post): systemd \ -- cgit v1.2.3-54-g00ecf From 8d00539d992266050eca672358c185aa2eb0bab3 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 15 Jul 2016 12:24:34 +0200 Subject: udev: Line buffer 'udev monitor' output (#3733) Callers of the 'udev monitor' tool expect to see output when an event occurs. The stdio buffering defeats that. This patch switches it to line buffering. --- src/udev/udevadm-monitor.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index c0ef073476..f656c2198e 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -151,6 +151,9 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) { sigaddset(&mask, SIGTERM); sigprocmask(SIG_UNBLOCK, &mask, NULL); + /* Callers are expecting to see events as they happen: Line buffering */ + setlinebuf(stdout); + fd_ep = epoll_create1(EPOLL_CLOEXEC); if (fd_ep < 0) { log_error_errno(errno, "error creating epoll fd: %m"); -- cgit v1.2.3-54-g00ecf From 2ed968802c8b7db2ec872d1a733b7eb70993f021 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 15 Jul 2016 12:44:02 -0400 Subject: tree-wide: get rid of selinux_context_t (#3732) https://github.com/SELinuxProject/selinux/commit/9eb9c9327563014ad6a807814e7975424642d5b9 deprecated selinux_context_t. Replace with a simple char* everywhere. Alternative fix for #3719. --- src/basic/selinux-util.c | 24 ++++++++++++------------ src/core/selinux-access.c | 2 +- src/core/selinux-setup.c | 2 +- src/journal/journald-server.c | 2 +- src/nspawn/nspawn.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 10c2f39369..bc07654668 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -41,10 +41,10 @@ #include "util.h" #ifdef HAVE_SELINUX -DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon); +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon); DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); -#define _cleanup_security_context_free_ _cleanup_(freeconp) +#define _cleanup_freecon_ _cleanup_(freeconp) #define _cleanup_context_free_ _cleanup_(context_freep) static int cached_use = -1; @@ -143,7 +143,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { r = lstat(path, &st); if (r >= 0) { - _cleanup_security_context_free_ security_context_t fcon = NULL; + _cleanup_freecon_ char* fcon = NULL; r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); @@ -186,7 +186,7 @@ int mac_selinux_apply(const char *path, const char *label) { assert(path); assert(label); - if (setfilecon(path, (security_context_t) label) < 0) { + if (setfilecon(path, label) < 0) { log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path); if (security_getenforce() > 0) return -errno; @@ -199,7 +199,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { int r = -EOPNOTSUPP; #ifdef HAVE_SELINUX - _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL; + _cleanup_freecon_ char *mycon = NULL, *fcon = NULL; security_class_t sclass; assert(exe); @@ -217,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { return -errno; sclass = string_to_security_class("process"); - r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, label); if (r < 0) return -errno; #endif @@ -246,7 +246,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * int r = -EOPNOTSUPP; #ifdef HAVE_SELINUX - _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL; + _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL; _cleanup_context_free_ context_t pcon = NULL, bcon = NULL; security_class_t sclass; const char *range = NULL; @@ -296,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return -ENOMEM; sclass = string_to_security_class("process"); - r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, label); if (r < 0) return -errno; #endif @@ -314,7 +314,7 @@ char* mac_selinux_free(char *label) { return NULL; - freecon((security_context_t) label); + freecon(label); #endif return NULL; @@ -323,7 +323,7 @@ char* mac_selinux_free(char *label) { int mac_selinux_create_file_prepare(const char *path, mode_t mode) { #ifdef HAVE_SELINUX - _cleanup_security_context_free_ security_context_t filecon = NULL; + _cleanup_freecon_ char *filecon = NULL; int r; assert(path); @@ -383,7 +383,7 @@ int mac_selinux_create_socket_prepare(const char *label) { assert(label); - if (setsockcreatecon((security_context_t) label) < 0) { + if (setsockcreatecon(label) < 0) { log_enforcing("Failed to set SELinux security context %s for sockets: %m", label); if (security_getenforce() == 1) @@ -411,7 +411,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { /* Binds a socket and label its file system object according to the SELinux policy */ #ifdef HAVE_SELINUX - _cleanup_security_context_free_ security_context_t fcon = NULL; + _cleanup_freecon_ char *fcon = NULL; const struct sockaddr_un *un; bool context_changed = false; char *path; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index cc287d602d..2b96a9551b 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -191,7 +191,7 @@ int mac_selinux_generic_access_check( const char *tclass = NULL, *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; - security_context_t fcon = NULL; + char *fcon = NULL; char **cmdline = NULL; int r = 0; diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index 4072df58e6..527aa8add0 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -44,7 +44,7 @@ int mac_selinux_setup(bool *loaded_policy) { #ifdef HAVE_SELINUX int enforce = 0; usec_t before_load, after_load; - security_context_t con; + char *con; int r; union selinux_callback cb; bool initialized = false; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index b1cbda0fff..886e0ec856 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -727,7 +727,7 @@ static void dispatch_message_real( *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0; IOVEC_SET_STRING(iovec[n++], x); } else { - security_context_t con; + char *con; if (getpidcon(ucred->pid, &con) >= 0) { x = strjoina("_SELINUX_CONTEXT=", con); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 0bab2557b0..bedc5bf20b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2642,7 +2642,7 @@ static int inner_child( #ifdef HAVE_SELINUX if (arg_selinux_context) - if (setexeccon((security_context_t) arg_selinux_context) < 0) + if (setexeccon(arg_selinux_context) < 0) return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context); #endif -- cgit v1.2.3-54-g00ecf From 2f27e2c5565e421283718d9bccc6fba52fd3ad21 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Fri, 15 Jul 2016 22:20:51 +0530 Subject: networkd: fix for 3692 (#3699) We should look that the kind is invalid rather than pointer is NULL. --- src/network/networkd-netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index b192884fd9..e7edc366af 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -619,7 +619,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { NULL, NULL, NULL, NULL, NULL, NULL) <= 0) return 0; - if (!NETDEV_VTABLE(netdev_raw)) { + if (netdev_raw->kind == _NETDEV_KIND_INVALID) { log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename); return 0; } -- cgit v1.2.3-54-g00ecf From ccc2c98e1b0c06861577632440b996ca16cefd53 Mon Sep 17 00:00:00 2001 From: Lukáš Nykrýn Date: Sat, 16 Jul 2016 21:04:13 +0200 Subject: manager: don't skip sigchld handler for main and control pid for services (#3738) During stop when service has one "regular" pid one main pid and one control pid and the sighld for the regular one is processed first the unit_tidy_watch_pids will skip the main and control pid and does not remove them from u->pids(). But then we skip the sigchld event because we already did one in the iteration and there are two pids in u->pids. v2: Use general unit_main_pid() and unit_control_pid() instead of reaching directly to service structure. --- src/core/manager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 902c2a0a27..c69b797430 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1729,7 +1729,10 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { unit_unwatch_pid(u, si->si_pid); if (UNIT_VTABLE(u)->sigchld_event) { - if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { + if (set_size(u->pids) <= 1 || + iteration != u->sigchldgen || + unit_main_pid(u) == si->si_pid || + unit_control_pid(u) == si->si_pid) { UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); u->sigchldgen = iteration; } else -- cgit v1.2.3-54-g00ecf From f41794d0360b8e3a705db58df14957ceb37c6f27 Mon Sep 17 00:00:00 2001 From: Jean-Sébastien Bour Date: Sat, 9 Jul 2016 02:38:00 +0200 Subject: basic/strv: exhibit strv_make_nulstr missing final NUL char (systemd/systemd#3689) --- src/test/test-strv.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/test/test-strv.c b/src/test/test-strv.c index f7a1217df7..91265c9cba 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -647,7 +647,9 @@ static void test_strv_extend_n(void) { static void test_strv_make_nulstr_one(char **l) { _cleanup_free_ char *b = NULL, *c = NULL; _cleanup_strv_free_ char **q = NULL; + const char *s = NULL; size_t n, m; + unsigned i = 0; assert_se(strv_make_nulstr(l, &b, &n) >= 0); assert_se(q = strv_parse_nulstr(b, n)); @@ -656,6 +658,11 @@ static void test_strv_make_nulstr_one(char **l) { assert_se(strv_make_nulstr(q, &c, &m) >= 0); assert_se(m == n); assert_se(memcmp(b, c, m) == 0); + + NULSTR_FOREACH(s, b) { + assert_se(streq(s, l[i++])); + } + assert_se(i == strv_length(l)); } static void test_strv_make_nulstr(void) { -- cgit v1.2.3-54-g00ecf From b60df13b39c0237f9cb1114076464d2431e6bee5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Jul 2016 15:25:01 -0400 Subject: basic/strv: add an extra NUL after strings in strv_make_nulstr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strv_make_nulstr was creating a nulstr which was not a valid nulstr, because it was missing the terminating NUL. This didn't cause any issues, because strv_parse_nulstr correctly parsed the result, using the separately specified length. But it's confusing to have something called nulstr which really isn't. It is likely that somebody will try to use strv_make_nulstr() in some other place, incorrectly. This patch changes strv_parse_nulstr() to produce a valid nulstr, and changes the output length parameter to be the minimum number of bytes which can be later on parsed by strv_parse_nulstr(). This allows the only user in ask-password-api to be slightly simplified. Based-on-patch-by: Jean-Sébastien Bour Fixes #3689. --- src/basic/strv.c | 29 +++++++++++++++++++++++++---- src/shared/ask-password-api.c | 6 +----- src/test/test-strv.c | 3 +-- 3 files changed, 27 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index e0e2d1ebbe..98d6f61067 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -638,6 +638,17 @@ char **strv_remove(char **l, const char *s) { } char **strv_parse_nulstr(const char *s, size_t l) { + /* l is the length of the input data, which will be split at NULs into + * elements of the resulting strv. Hence, the number of items in the resulting strv + * will be equal to one plus the number of NUL bytes in the l bytes starting at s, + * unless s[l-1] is NUL, in which case the final empty string is not stored in + * the resulting strv, and length is equal to the number of NUL bytes. + * + * Note that contrary to a normal nulstr which cannot contain empty strings, because + * the input data is terminated by any two consequent NUL bytes, this parser accepts + * empty strings in s. + */ + const char *p; unsigned c = 0, i = 0; char **v; @@ -700,6 +711,13 @@ char **strv_split_nulstr(const char *s) { } int strv_make_nulstr(char **l, char **p, size_t *q) { + /* A valid nulstr with two NULs at the end will be created, but + * q will be the length without the two trailing NULs. Thus the output + * string is a valid nulstr and can be iterated over using NULSTR_FOREACH, + * and can also be parsed by strv_parse_nulstr as long as the length + * is provided separately. + */ + size_t n_allocated = 0, n = 0; _cleanup_free_ char *m = NULL; char **i; @@ -712,7 +730,7 @@ int strv_make_nulstr(char **l, char **p, size_t *q) { z = strlen(*i); - if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) + if (!GREEDY_REALLOC(m, n_allocated, n + z + 2)) return -ENOMEM; memcpy(m + n, *i, z + 1); @@ -723,11 +741,14 @@ int strv_make_nulstr(char **l, char **p, size_t *q) { m = new0(char, 1); if (!m) return -ENOMEM; - n = 0; - } + n = 1; + } else + /* make sure there is a second extra NUL at the end of resulting nulstr */ + m[n] = '\0'; + assert(n > 0); *p = m; - *q = n; + *q = n - 1; m = NULL; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index a86b0db554..65151b19a6 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -139,11 +139,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa if (r < 0) return r; - /* Truncate trailing NUL */ - assert(n > 0); - assert(p[n-1] == 0); - - serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING); + serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING); memory_erase(p, n); if (serial == -1) return -errno; diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 91265c9cba..841a36782f 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -659,9 +659,8 @@ static void test_strv_make_nulstr_one(char **l) { assert_se(m == n); assert_se(memcmp(b, c, m) == 0); - NULSTR_FOREACH(s, b) { + NULSTR_FOREACH(s, b) assert_se(streq(s, l[i++])); - } assert_se(i == strv_length(l)); } -- cgit v1.2.3-54-g00ecf From 7b7c1aacf6caf45834ddc7e50d2ef8bad15456d3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 13:51:30 -0400 Subject: systemd-resolve: use plural "DNS Servers" Usually multiple DNS servers are configured, and it looks strange to have singular in the heading. --- src/resolve/resolve-tool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 4e1e916669..859dc1920b 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1229,8 +1229,8 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt yes_no(link_info.dnssec_supported)); STRV_FOREACH(i, link_info.dns) { - printf(" %s %s\n", - i == link_info.dns ? "DNS Server:" : " ", + printf(" %s %s\n", + i == link_info.dns ? "DNS Servers:" : " ", *i); } @@ -1412,8 +1412,8 @@ static int status_global(sd_bus *bus, bool *empty_line) { printf("%sGlobal%s\n", ansi_highlight(), ansi_normal()); STRV_FOREACH(i, global_info.dns) { - printf(" %s %s\n", - i == global_info.dns ? "DNS Server:" : " ", + printf(" %s %s\n", + i == global_info.dns ? "DNS Servers:" : " ", *i); } -- cgit v1.2.3-54-g00ecf From 96ace31dcdd8534e8c68d34398cd5093e86401b6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 13:55:58 -0400 Subject: systemd-resolve: remove spurious newline with no global settings --- src/resolve/resolve-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 859dc1920b..6ae3750417 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1446,7 +1446,7 @@ static int status_all(sd_bus *bus) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; sd_netlink_message *i; - bool empty_line = true; + bool empty_line = false; int r; assert(bus); -- cgit v1.2.3-54-g00ecf From fc549b96054d52bbde68a4aa773bf4037700d389 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 15:12:01 -0400 Subject: Drop parentheses in two places --- man/systemd-resolved.service.xml | 4 ++-- src/basic/strv.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 0df037ba69..141b06e374 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -68,8 +68,8 @@ link-local networking). The glibc - getaddrinfo3 API (as defined - by RFC3493) and its related resolver functions, + getaddrinfo3 API as defined + by RFC3493 and its related resolver functions, including gethostbyname3. This API is widely supported, including beyond the Linux platform. In its current form it does not expose DNSSEC validation status information however, and is synchronous only. This API is backed by the glibc Name Service diff --git a/src/basic/strv.c b/src/basic/strv.c index e0e2d1ebbe..db315ac10a 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -803,9 +803,8 @@ char **strv_reverse(char **l) { if (n <= 1) return l; - for (i = 0; i < n / 2; i++) { + for (i = 0; i < n / 2; i++) SWAP_TWO(l[i], l[n-1-i]); - } return l; } -- cgit v1.2.3-54-g00ecf From 201b13c81eb05b28c21bc462aa4bba54040509b8 Mon Sep 17 00:00:00 2001 From: tblume Date: Mon, 18 Jul 2016 12:23:08 +0200 Subject: nspawn: decrease mkdir error logging in /sys to debug priority (#3748) Such mkdir errors happen for example when trying to mkdir /sys/fs/selinux. /sys is documented to be readonly in the container, so mkdir errors below /sys can be expected. They shouldn't be logged as warnings since they lead users to think that there is something wrong. --- src/nspawn/nspawn-mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 8e2d2d543c..9f4903c842 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -342,7 +342,7 @@ int mount_all(const char *dest, if (mount_table[k].fatal) return log_error_errno(r, "Failed to create directory %s: %m", where); - log_warning_errno(r, "Failed to create directory %s: %m", where); + log_debug_errno(r, "Failed to create directory %s: %m", where); continue; } -- cgit v1.2.3-54-g00ecf From 03e749af53bc6671270c300cdc5df4f2c5e0b9ae Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 18 Jul 2016 21:19:32 +0200 Subject: sd-boot: Fix waiting for keyboard input (#3735) WaitForKeyEx may never return on some UEFI systems depending on firmware, hardware configuration and the phase of the moon. Use ConIn->WaitForKey unconditionally instead. Fixes #3632 --- src/boot/efi/console.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index c436f8b476..2b797c9a5f 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -93,12 +93,8 @@ EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) { } /* wait until key is pressed */ - if (wait) { - if (TextInputEx) - uefi_call_wrapper(BS->WaitForEvent, 3, 1, &TextInputEx->WaitForKeyEx, &index); - else - uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); - } + if (wait) + uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); if (TextInputEx) { EFI_KEY_DATA keydata; -- cgit v1.2.3-54-g00ecf From 82edec5451c377197d514bd0549436a5471a695f Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Mon, 18 Jul 2016 22:09:57 +0200 Subject: network: fix indentation --- src/network/networkd-conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index b67a1f6d09..c03e2b2ebf 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -70,7 +70,7 @@ int config_parse_duid_rawdata( for (;;) { int n1, n2, len, r; uint32_t byte; - _cleanup_free_ char *cbyte = NULL; + _cleanup_free_ char *cbyte = NULL; r = extract_first_word(&rvalue, &cbyte, ":", 0); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 65a6195e765c3b87f01e1b19211788e5ed3d22a7 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Mon, 18 Jul 2016 22:14:23 +0200 Subject: basic: fix whitespace --- src/basic/process-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 3afb5e0a40..e38b67405e 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -196,7 +196,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * *(k++) = (char) c; left--; - } else if (k > r) + } else if (k > r) space = true; } -- cgit v1.2.3-54-g00ecf From ba19c6e1819a89d3b90811ce4fd785a606dfd223 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Mon, 18 Jul 2016 22:31:34 +0200 Subject: treewide: remove unused variables --- src/machine/machinectl.c | 1 - src/nspawn/nspawn.c | 1 - src/systemctl/systemctl.c | 2 +- src/test/test-process-util.c | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 161dd3922b..96e0ab4b8a 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1551,7 +1551,6 @@ static int image_exists(sd_bus *bus, const char *name) { } static int make_service_name(const char *name, char **ret) { - _cleanup_free_ char *e = NULL; int r; assert(name); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index bedc5bf20b..e4be0a2251 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3125,7 +3125,6 @@ static int setup_uid_map(pid_t pid) { } static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - _cleanup_fdset_free_ FDSet *fds = NULL; char buf[NOTIFY_BUFFER_MAX+1]; char *p = NULL; struct iovec iovec = { diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b575437bcb..d3f437411a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5606,7 +5606,7 @@ static int mangle_names(char **original_names, char ***mangled_names) { } static int unit_exists(const char *unit) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *path = NULL; static const struct bus_properties_map property_map[] = { diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 99c92780b8..562ad4acb8 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -45,7 +45,7 @@ static void test_get_process_comm(pid_t pid) { struct stat st; - _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL; + _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL; _cleanup_free_ char *env = NULL; char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)]; pid_t e; -- cgit v1.2.3-54-g00ecf From 12c40d4cc4332161baa928092c08455bfee36096 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Mon, 18 Jul 2016 22:42:09 +0200 Subject: resolved: replace bitwise and with logical and --- src/resolve/resolved-dns-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index ea0be56d98..a8ad8fe342 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -720,7 +720,7 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, in goto fail; /* RDLENGTH */ - if (edns0_do & !DNS_PACKET_QR(p)) { + if (edns0_do && !DNS_PACKET_QR(p)) { /* If DO is on and this is not a reply, also append RFC6975 Algorithm data */ static const uint8_t rfc6975[] = { -- cgit v1.2.3-54-g00ecf From 340defcd06b4219eaec6b63f62e0fc4ad8c7ac96 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 19 Jul 2016 12:10:09 +0200 Subject: kernel-install: recognize /boot/efi mountpoint (#3751) install everything in /boot/efi, if this is a mountpoint --- src/kernel-install/90-loaderentry.install | 3 ++- src/kernel-install/kernel-install | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 4c9b1f0327..a0bca05c9a 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -16,7 +16,8 @@ if ! [[ $MACHINE_ID ]]; then fi BOOT_DIR="/$MACHINE_ID/$KERNEL_VERSION" -LOADER_ENTRY="/boot/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" +BOOT_ROOT=${BOOT_DIR_ABS%$BOOT_DIR} +LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" if [[ $COMMAND == remove ]]; then exec rm -f "$LOADER_ENTRY" diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index 3ae1d77e33..1159dc384d 100644 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -86,7 +86,15 @@ if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then exit 1 fi -BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" +if [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then + BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" +elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]] \ + || mountpoint -q /boot/efi; then + BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION" +else + BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" +fi + ret=0 readarray -t PLUGINS < <( -- cgit v1.2.3-54-g00ecf From c24f1f9df1a79f413dc1cdad27341027e58d2a1f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jun 2016 17:37:21 -0700 Subject: sd-journal: when formatting log messages, implicitly strip trailing whitespace When converting log messages from human readable text into binary records to send off to journald in sd_journal_print(), strip trailing whitespace in the log message. This way, handling of logs made via syslog(), stdout/stderr and sd_journal_print() are treated the same way: trailing (but not leading) whitespace is automatically removed, in particular \n and \r. Note that in case of syslog() and stdout/stderr based logging the stripping takes place server-side though, while for the native protocol based transport this takes place client-side. This is because in the former cases conversion from free-form human-readable strings into structured, binary log records takes place on the server-side while for journal-native logging it happens on the client side, and after conversion into binary records we probably shouldn't alter the data anymore. See: #3416 --- src/journal/journal-send.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 5e8a3e3200..1b92585488 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -107,6 +107,9 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); + /* Strip trailing whitespace, keep prefix whitespace. */ + (void) strstrip(buffer); + zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); @@ -158,6 +161,8 @@ _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int VA_FORMAT_ADVANCE(format, ap); + (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ + IOVEC_SET_STRING(iov[i++], buffer); format = va_arg(ap, char *); @@ -471,6 +476,8 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); + (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ + /* func is initialized from __func__ which is not a macro, but * a static const char[], hence cannot easily be prefixed with * CODE_FUNC=, hence let's do it manually here. */ -- cgit v1.2.3-54-g00ecf From 8980058a3715f2dc96f38373b9550ef4e5b83662 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jun 2016 17:41:19 -0700 Subject: journalctl: make sure that journalctl's --all switch also has an effect on json output With this change, binary record data is formatted as string if --all is specified when using json output. This is inline with the effect of --all on the other available output modes. Fixes: #3416 --- src/shared/logs-show.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 9351b85eed..d04728f505 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -489,7 +489,7 @@ static int output_verbose( off = ANSI_NORMAL; } - if (flags & OUTPUT_SHOW_ALL || + if ((flags & OUTPUT_SHOW_ALL) || (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) { fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data); @@ -607,7 +607,7 @@ void json_escape( if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD) fputs("null", f); - else if (!utf8_is_printable(p, l)) { + else if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(p, l)) { bool not_first = false; fputs("[ ", f); -- cgit v1.2.3-54-g00ecf From c4b41707462a74eb7008e8d12a0b4d0a0c09bff4 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Wed, 6 Jul 2016 09:48:58 +0200 Subject: namespace: unify limit behavior on non-directory paths Despite the name, `Read{Write,Only}Directories=` already allows for regular file paths to be masked. This commit adds the same behavior to `InaccessibleDirectories=` and makes it explicit in the doc. This patch introduces `/run/systemd/inaccessible/{reg,dir,chr,blk,fifo,sock}` {dile,device}nodes and mounts on the appropriate one the paths specified in `InacessibleDirectories=`. Based on Luca's patch from https://github.com/systemd/systemd/pull/3327 --- man/systemd.exec.xml | 14 ++++++++------ src/basic/mount-util.c | 18 ++++++++++++++++++ src/basic/mount-util.h | 2 ++ src/core/dbus-execute.c | 12 ++++++------ src/core/mount-setup.c | 14 +++++++++++--- src/core/namespace.c | 31 +++++++++++++++++++++++-------- 6 files changed, 68 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index ed02666daf..e982333434 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -855,24 +855,26 @@ Sets up a new file system namespace for executed processes. These options may be used to limit access a process might have to the main file system hierarchy. Each - setting takes a space-separated list of directory paths relative to + setting takes a space-separated list of paths relative to the host's root directory (i.e. the system running the service manager). - Directories listed in + Note that if entries contain symlinks, they are resolved from the host's root directory as well. + Entries (files or directories) listed in ReadWriteDirectories= are accessible from within the namespace with the same access rights as from - outside. Directories listed in + outside. Entries listed in ReadOnlyDirectories= are accessible for reading only, writing will be refused even if the usual file - access controls would permit this. Directories listed in + access controls would permit this. Entries listed in InaccessibleDirectories= will be made inaccessible for processes inside the namespace, and may not countain any other mountpoints, including those specified by ReadWriteDirectories= or ReadOnlyDirectories=. Note that restricting access with these options does not extend - to submounts of a directory that are created later on. These + to submounts of a directory that are created later on. + Non-directory paths can be specified as well. These options may be specified more than once, in which case all - directories listed will have limited access from within the + paths listed will have limited access from within the namespace. If the empty string is assigned to this option, the specific list is reset, and all prior assignments have no effect. diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 90b7a885a8..63dff3dd5c 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -532,3 +532,21 @@ int repeat_unmount(const char *path, int flags) { done = true; } } + +const char* mode_to_inaccessible_node(mode_t mode) { + switch(mode & S_IFMT) { + case S_IFREG: + return "/run/systemd/inaccessible/reg"; + case S_IFDIR: + return "/run/systemd/inaccessible/dir"; + case S_IFCHR: + return "/run/systemd/inaccessible/chr"; + case S_IFBLK: + return "/run/systemd/inaccessible/blk"; + case S_IFIFO: + return "/run/systemd/inaccessible/fifo"; + case S_IFSOCK: + return "/run/systemd/inaccessible/sock"; + } + return NULL; +} diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index bdb525d6b0..f46989ebb3 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -49,4 +49,6 @@ union file_handle_union { char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; }; +const char* mode_to_inaccessible_node(mode_t mode); + #define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 644b9561b5..4588ecad09 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1346,12 +1346,12 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { _cleanup_free_ char *joined = NULL; - if (streq(name, "ReadWriteDirectories")) - dirs = &c->read_write_dirs; - else if (streq(name, "ReadOnlyDirectories")) - dirs = &c->read_only_dirs; - else /* "InaccessibleDirectories" */ - dirs = &c->inaccessible_dirs; + if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths")) + dirs = &c->read_write_paths; + else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths")) + dirs = &c->read_only_paths; + else /* "InaccessiblePaths" */ + dirs = &c->inaccessible_paths; if (strv_length(l) == 0) { *dirs = strv_free(*dirs); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index f9c9b4a91f..5d8ab0ec70 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -28,6 +28,7 @@ #include "cgroup-util.h" #include "dev-setup.h" #include "efivars.h" +#include "fs-util.h" #include "label.h" #include "log.h" #include "macro.h" @@ -403,9 +404,16 @@ int mount_setup(bool loaded_policy) { * really needs to stay for good, otherwise software that * copied sd-daemon.c into their sources will misdetect * systemd. */ - mkdir_label("/run/systemd", 0755); - mkdir_label("/run/systemd/system", 0755); - mkdir_label("/run/systemd/inaccessible", 0000); + (void) mkdir_label("/run/systemd", 0755); + (void) mkdir_label("/run/systemd/system", 0755); + (void) mkdir_label("/run/systemd/inaccessible", 0000); + /* Set up inaccessible items */ + (void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0); + (void) mkdir_label("/run/systemd/inaccessible/dir", 0000); + (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0)); + (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0)); + (void) mkfifo("/run/systemd/inaccessible/fifo", 0000); + (void) mknod("/run/systemd/inaccessible/sock", S_IFSOCK | 0000, 0); return 0; } diff --git a/src/core/namespace.c b/src/core/namespace.c index 203d122810..e465e825a1 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -278,6 +278,7 @@ static int apply_mount( const char *what; int r; + struct stat target; assert(m); @@ -287,12 +288,22 @@ static int apply_mount( /* First, get rid of everything that is below if there * is anything... Then, overmount it with an - * inaccessible directory. */ + * inaccessible path. */ umount_recursive(m->path, 0); - what = "/run/systemd/inaccessible"; - break; + r = lstat(m->path, &target); + if (r != 0) { + if (m->ignore && errno == ENOENT) + return 0; + return -errno; + } + what = mode_to_inaccessible_node(target.st_mode); + if (what == NULL) { + log_debug("File type not supported. Note that symlinks are not allowed"); + return -ELOOP; + } + break; case READONLY: case READWRITE: /* Nothing to mount here, we just later toggle the @@ -317,12 +328,16 @@ static int apply_mount( assert(what); r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL); - if (r >= 0) + if (r >= 0) { log_debug("Successfully mounted %s to %s", what, m->path); - else if (m->ignore && errno == ENOENT) - return 0; - - return r; + return r; + } + else { + if (m->ignore && errno == ENOENT) + return 0; + log_debug("Failed mounting %s to %s: %s", what, m->path, strerror(errno)); + return -errno; + } } static int make_read_only(BindMount *m) { -- cgit v1.2.3-54-g00ecf From 2a624c36e646e9ef8d204a506b12e7dbd380e111 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Thu, 7 Jul 2016 11:17:00 +0200 Subject: doc,core: Read{Write,Only}Paths= and InaccessiblePaths= This patch renames Read{Write,Only}Directories= and InaccessibleDirectories= to Read{Write,Only}Paths= and InaccessiblePaths=, previous names are kept as aliases but they are not advertised in the documentation. Renamed variables: `read_write_dirs` --> `read_write_paths` `read_only_dirs` --> `read_only_paths` `inaccessible_dirs` --> `inaccessible_paths` --- man/systemd.exec.xml | 28 +++++++++++++-------------- shell-completion/bash/systemd-run | 4 ++-- shell-completion/zsh/_systemd-run | 4 ++-- src/core/dbus-execute.c | 13 ++++++++----- src/core/execute.c | 36 +++++++++++++++++------------------ src/core/execute.h | 2 +- src/core/load-fragment-gperf.gperf.m4 | 9 ++++++--- src/core/namespace.c | 18 +++++++++--------- src/core/namespace.h | 6 +++--- src/shared/bus-unit-util.c | 3 ++- 10 files changed, 65 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index e982333434..49fea98a95 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -848,9 +848,9 @@ - ReadWriteDirectories= - ReadOnlyDirectories= - InaccessibleDirectories= + ReadWritePaths= + ReadOnlyPaths= + InaccessiblePaths= Sets up a new file system namespace for executed processes. These options may be used to limit access @@ -858,18 +858,18 @@ setting takes a space-separated list of paths relative to the host's root directory (i.e. the system running the service manager). Note that if entries contain symlinks, they are resolved from the host's root directory as well. - Entries (files or directories) listed in - ReadWriteDirectories= are accessible from + Entries (files or directories) listed in + ReadWritePaths= are accessible from within the namespace with the same access rights as from outside. Entries listed in - ReadOnlyDirectories= are accessible for + ReadOnlyPaths= are accessible for reading only, writing will be refused even if the usual file access controls would permit this. Entries listed in - InaccessibleDirectories= will be made + InaccessiblePaths= will be made inaccessible for processes inside the namespace, and may not countain any other mountpoints, including those specified by - ReadWriteDirectories= or - ReadOnlyDirectories=. + ReadWritePaths= or + ReadOnlyPaths=. Note that restricting access with these options does not extend to submounts of a directory that are created later on. Non-directory paths can be specified as well. These @@ -879,9 +879,9 @@ specific list is reset, and all prior assignments have no effect. Paths in - ReadOnlyDirectories= + ReadOnlyPaths= and - InaccessibleDirectories= + InaccessiblePaths= may be prefixed with -, in which case they will be ignored when they do not @@ -1036,9 +1036,9 @@ PrivateDevices=, ProtectSystem=, ProtectHome=, - ReadOnlyDirectories=, - InaccessibleDirectories= and - ReadWriteDirectories=) require that mount + ReadOnlyPaths=, + InaccessiblePaths= and + ReadWritePaths=) require that mount and unmount propagation from the unit's file system namespace is disabled, and hence downgrade to . diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index 8152b021e7..022331e6a9 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -84,8 +84,8 @@ _systemd_run() { LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= - SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= - ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths= + ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment=' COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index c425085cd8..6362b97766 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -37,8 +37,8 @@ _arguments \ LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \ PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \ TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= \ - SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= \ - ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= \ + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths= \ + ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= \ ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \ ))' \ '--description=[Description for unit]:description' \ diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4588ecad09..b2ef3db491 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -695,9 +695,12 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1323,8 +1326,8 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { - + } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { _cleanup_strv_free_ char **l = NULL; char ***dirs; char **p; diff --git a/src/core/execute.c b/src/core/execute.c index f4f5723c35..05dc1aaec1 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1507,9 +1507,9 @@ static bool exec_needs_mount_namespace( assert(context); assert(params); - if (!strv_isempty(context->read_write_dirs) || - !strv_isempty(context->read_only_dirs) || - !strv_isempty(context->inaccessible_dirs)) + if (!strv_isempty(context->read_write_paths) || + !strv_isempty(context->read_only_paths) || + !strv_isempty(context->inaccessible_paths)) return true; if (context->mount_flags != 0) @@ -1933,9 +1933,9 @@ static int exec_child( r = setup_namespace( params->apply_chroot ? context->root_directory : NULL, - context->read_write_dirs, - context->read_only_dirs, - context->inaccessible_dirs, + context->read_write_paths, + context->read_only_paths, + context->inaccessible_paths, tmp, var, context->private_devices, @@ -2324,9 +2324,9 @@ void exec_context_done(ExecContext *c) { c->pam_name = mfree(c->pam_name); - c->read_only_dirs = strv_free(c->read_only_dirs); - c->read_write_dirs = strv_free(c->read_write_dirs); - c->inaccessible_dirs = strv_free(c->inaccessible_dirs); + c->read_only_paths = strv_free(c->read_only_paths); + c->read_write_paths = strv_free(c->read_write_paths); + c->inaccessible_paths = strv_free(c->inaccessible_paths); if (c->cpuset) CPU_FREE(c->cpuset); @@ -2732,21 +2732,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { if (c->pam_name) fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); - if (strv_length(c->read_write_dirs) > 0) { - fprintf(f, "%sReadWriteDirs:", prefix); - strv_fprintf(f, c->read_write_dirs); + if (strv_length(c->read_write_paths) > 0) { + fprintf(f, "%sReadWritePaths:", prefix); + strv_fprintf(f, c->read_write_paths); fputs("\n", f); } - if (strv_length(c->read_only_dirs) > 0) { - fprintf(f, "%sReadOnlyDirs:", prefix); - strv_fprintf(f, c->read_only_dirs); + if (strv_length(c->read_only_paths) > 0) { + fprintf(f, "%sReadOnlyPaths:", prefix); + strv_fprintf(f, c->read_only_paths); fputs("\n", f); } - if (strv_length(c->inaccessible_dirs) > 0) { - fprintf(f, "%sInaccessibleDirs:", prefix); - strv_fprintf(f, c->inaccessible_dirs); + if (strv_length(c->inaccessible_paths) > 0) { + fprintf(f, "%sInaccessiblePaths:", prefix); + strv_fprintf(f, c->inaccessible_paths); fputs("\n", f); } diff --git a/src/core/execute.h b/src/core/execute.h index cacf66cf51..73b8a119b0 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -152,7 +152,7 @@ struct ExecContext { bool smack_process_label_ignore; char *smack_process_label; - char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; + char **read_write_paths, **read_only_paths, **inaccessible_paths; unsigned long mount_flags; uint64_t capability_bounding_set; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fe1006830b..6a5c16a000 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -80,9 +80,12 @@ $1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQ $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) $1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) -$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) -$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) -$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths) +$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths) +$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths) +$1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths) +$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths) +$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths) $1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) diff --git a/src/core/namespace.c b/src/core/namespace.c index e465e825a1..722538caf1 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -362,9 +362,9 @@ static int make_read_only(BindMount *m) { int setup_namespace( const char* root_directory, - char** read_write_dirs, - char** read_only_dirs, - char** inaccessible_dirs, + char** read_write_paths, + char** read_only_paths, + char** inaccessible_paths, const char* tmp_dir, const char* var_tmp_dir, bool private_dev, @@ -383,9 +383,9 @@ int setup_namespace( return -errno; n = !!tmp_dir + !!var_tmp_dir + - strv_length(read_write_dirs) + - strv_length(read_only_dirs) + - strv_length(inaccessible_dirs) + + strv_length(read_write_paths) + + strv_length(read_only_paths) + + strv_length(inaccessible_paths) + private_dev + (protect_home != PROTECT_HOME_NO ? 3 : 0) + (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) + @@ -393,15 +393,15 @@ int setup_namespace( if (n > 0) { m = mounts = (BindMount *) alloca0(n * sizeof(BindMount)); - r = append_mounts(&m, read_write_dirs, READWRITE); + r = append_mounts(&m, read_write_paths, READWRITE); if (r < 0) return r; - r = append_mounts(&m, read_only_dirs, READONLY); + r = append_mounts(&m, read_only_paths, READONLY); if (r < 0) return r; - r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE); + r = append_mounts(&m, inaccessible_paths, INACCESSIBLE); if (r < 0) return r; diff --git a/src/core/namespace.h b/src/core/namespace.h index b54b7b47d6..1aedf5f208 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -40,9 +40,9 @@ typedef enum ProtectSystem { } ProtectSystem; int setup_namespace(const char *chroot, - char **read_write_dirs, - char **read_only_dirs, - char **inaccessible_dirs, + char **read_write_paths, + char **read_only_paths, + char **inaccessible_paths, const char *tmp_dir, const char *var_tmp_dir, bool private_dev, diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 04471e2373..94ffa8af87 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -453,7 +453,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } r = sd_bus_message_append(m, "v", "i", oa); - } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { const char *p; r = sd_bus_message_open_container(m, 'v', "as"); -- cgit v1.2.3-54-g00ecf From 0d23bc57da6a3aeb1e7f92cfd7da2cd831b7c11c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 14:27:05 +0200 Subject: sd-journal: suppress empty lines Let's make sure our logging APIs is in sync with how stdout/stderr logging works. --- man/sd_journal_print.xml | 3 ++- src/journal/journal-send.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml index 6fe078d88e..76542527fc 100644 --- a/man/sd_journal_print.xml +++ b/man/sd_journal_print.xml @@ -106,7 +106,8 @@ but no such restrictions are enforced. Note that log messages written using this function are generally not expected to end in a new-line character. However, as all trailing whitespace (including spaces, new-lines, tabulators and carriage returns) are automatically stripped from the logged string, it is acceptable to specify one - (or more). Leading whitespace (as well as inner whitespace) is left unmodified however. + (or more). Empty lines (after trailing whitespace removal) are suppressed. On non-empty lines, leading whitespace + (as well as inner whitespace) is left unmodified. sd_journal_printv() is similar to sd_journal_print() but takes a variable diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 1b92585488..440fba67ca 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -110,6 +110,10 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { /* Strip trailing whitespace, keep prefix whitespace. */ (void) strstrip(buffer); + /* Suppress empty lines */ + if (isempty(buffer+8)) + return 0; + zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); @@ -476,7 +480,12 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); - (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ + /* Strip trailing whitespace, keep prefixing whitespace */ + (void) strstrip(buffer); + + /* Suppress empty lines */ + if (isempty(buffer+8)) + return 0; /* func is initialized from __func__ which is not a macro, but * a static const char[], hence cannot easily be prefixed with -- cgit v1.2.3-54-g00ecf From d724118e207f6c1b7e99498bfc0b4bb090752932 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 08:55:50 +0200 Subject: core: hide legacy bus properties We usually hide legacy bus properties from introspection. Let's do that for the InaccessibleDirectories= properties too. The properties stay accessible if requested, but they won't be listed anymore if people introspect the unit. --- src/core/dbus-execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index b2ef3db491..307c3d8e7a 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -695,9 +695,9 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), -- cgit v1.2.3-54-g00ecf From 5fd7cf6fe23aa3c96891ef4d2d76786e935ec7aa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 08:57:25 +0200 Subject: namespace: minor improvements We generally try to avoid strerror(), due to its threads-unsafety, let's do this here, too. Also, let's be tiny bit more explanatory with the log messages, and let's shorten a few things. --- src/core/namespace.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/namespace.c b/src/core/namespace.c index 722538caf1..8df82c031c 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -291,16 +291,15 @@ static int apply_mount( * inaccessible path. */ umount_recursive(m->path, 0); - r = lstat(m->path, &target); - if (r != 0) { + if (lstat(m->path, &target) < 0) { if (m->ignore && errno == ENOENT) return 0; return -errno; } what = mode_to_inaccessible_node(target.st_mode); - if (what == NULL) { - log_debug("File type not supported. Note that symlinks are not allowed"); + if (!what) { + log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed"); return -ELOOP; } break; @@ -331,12 +330,10 @@ static int apply_mount( if (r >= 0) { log_debug("Successfully mounted %s to %s", what, m->path); return r; - } - else { + } else { if (m->ignore && errno == ENOENT) return 0; - log_debug("Failed mounting %s to %s: %s", what, m->path, strerror(errno)); - return -errno; + return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, m->path); } } -- cgit v1.2.3-54-g00ecf From 801a884d1ec66d8174b0e6dd9834f69165da94b5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 11:14:18 +0200 Subject: logind: minor coding style improvements --- src/login/logind-session.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 1e0666884a..0b917c23e1 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -603,7 +603,6 @@ int session_start(Session *s) { static int session_stop_scope(Session *s, bool force) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - char *job = NULL; int r; assert(s); @@ -612,20 +611,18 @@ static int session_stop_scope(Session *s, bool force) { return 0; if (force || manager_shall_kill(s->manager, s->user->name)) { + char *job = NULL; + r = manager_stop_unit(s->manager, s->scope, &error, &job); - if (r < 0) { - log_error("Failed to stop session scope: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r)); free(s->scope_job); s->scope_job = job; } else { r = manager_abandon_scope(s->manager, s->scope, &error); - if (r < 0) { - log_error("Failed to abandon session scope: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to abandon session scope: %s", bus_error_message(&error, r)); } return 0; -- cgit v1.2.3-54-g00ecf From 26f417d3e8dd2522adfdc4c8fed4c36fa40f48fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 11:14:48 +0200 Subject: util: don't send SIGCONT following a SIGCONT or SIGKILL in kill_and_sigcont() --- src/basic/process-util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index e38b67405e..54b644ad56 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -625,8 +625,10 @@ int kill_and_sigcont(pid_t pid, int sig) { r = kill(pid, sig) < 0 ? -errno : 0; - if (r >= 0) - kill(pid, SIGCONT); + /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't + * affected by a process being suspended anyway. */ + if (r >= 0 && !IN_SET(SIGCONT, SIGKILL)) + (void) kill(pid, SIGCONT); return r; } -- cgit v1.2.3-54-g00ecf From 1d98fef17d5fd746be163b3aac306068ecec3438 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 11:16:05 +0200 Subject: core: when forcibly killing/aborting left-over unit processes log about it Let's lot at LOG_NOTICE about any processes that we are going to SIGKILL/SIGABRT because clean termination of them didn't work. This turns the various boolean flag parameters to cg_kill(), cg_migrate() and related calls into a single binary flags parameter, simply because the function now gained even more parameters and the parameter listed shouldn't get too long. Logging for killing processes is done either when the kill signal is SIGABRT or SIGKILL, or on explicit request if KILL_TERMINATE_AND_LOG instead of LOG_TERMINATE is passed. This isn't used yet in this patch, but is made use of in a later patch. --- src/basic/cgroup-util.c | 64 +++++++++++++++++++++----------- src/basic/cgroup-util.h | 18 ++++++--- src/core/cgroup.c | 2 +- src/core/scope.c | 2 +- src/core/service.c | 2 +- src/core/unit.c | 98 +++++++++++++++++++++++++++++++++++++------------ src/core/unit.h | 1 + src/test/test-cgroup.c | 10 ++--- src/udev/udevd.c | 2 +- 9 files changed, 140 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 7cdc97ee3c..630e15b141 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -197,7 +197,15 @@ int cg_rmdir(const char *controller, const char *path) { return 0; } -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { +int cg_kill( + const char *controller, + const char *path, + int sig, + CGroupFlags flags, + Set *s, + cg_kill_log_func_t log_kill, + void *userdata) { + _cleanup_set_free_ Set *allocated_set = NULL; bool done = false; int r, ret = 0; @@ -232,19 +240,22 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo while ((r = cg_read_pid(f, &pid)) > 0) { - if (ignore_self && pid == my_pid) + if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid) continue; if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid)) continue; + if (log_kill) + log_kill(pid, sig, userdata); + /* If we haven't killed this process yet, kill * it */ if (kill(pid, sig) < 0) { if (ret >= 0 && errno != ESRCH) ret = -errno; } else { - if (sigcont && sig != SIGKILL) + if (flags & CGROUP_SIGCONT) (void) kill(pid, SIGCONT); if (ret == 0) @@ -278,7 +289,15 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo return ret; } -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) { +int cg_kill_recursive( + const char *controller, + const char *path, + int sig, + CGroupFlags flags, + Set *s, + cg_kill_log_func_t log_kill, + void *userdata) { + _cleanup_set_free_ Set *allocated_set = NULL; _cleanup_closedir_ DIR *d = NULL; int r, ret; @@ -293,7 +312,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si return -ENOMEM; } - ret = cg_kill(controller, path, sig, sigcont, ignore_self, s); + ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata); r = cg_enumerate_subgroups(controller, path, &d); if (r < 0) { @@ -311,15 +330,14 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si if (!p) return -ENOMEM; - r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s); + r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata); if (r != 0 && ret >= 0) ret = r; } - if (ret >= 0 && r < 0) ret = r; - if (rem) { + if (flags & CGROUP_REMOVE) { r = cg_rmdir(controller, path); if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY) return r; @@ -328,7 +346,13 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si return ret; } -int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) { +int cg_migrate( + const char *cfrom, + const char *pfrom, + const char *cto, + const char *pto, + CGroupFlags flags) { + bool done = false; _cleanup_set_free_ Set *s = NULL; int r, ret = 0; @@ -363,7 +387,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char /* This might do weird stuff if we aren't a * single-threaded program. However, we * luckily know we are not */ - if (ignore_self && pid == my_pid) + if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid) continue; if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid)) @@ -411,8 +435,7 @@ int cg_migrate_recursive( const char *pfrom, const char *cto, const char *pto, - bool ignore_self, - bool rem) { + CGroupFlags flags) { _cleanup_closedir_ DIR *d = NULL; int r, ret = 0; @@ -423,7 +446,7 @@ int cg_migrate_recursive( assert(cto); assert(pto); - ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self); + ret = cg_migrate(cfrom, pfrom, cto, pto, flags); r = cg_enumerate_subgroups(cfrom, pfrom, &d); if (r < 0) { @@ -441,7 +464,7 @@ int cg_migrate_recursive( if (!p) return -ENOMEM; - r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem); + r = cg_migrate_recursive(cfrom, p, cto, pto, flags); if (r != 0 && ret >= 0) ret = r; } @@ -449,7 +472,7 @@ int cg_migrate_recursive( if (r < 0 && ret >= 0) ret = r; - if (rem) { + if (flags & CGROUP_REMOVE) { r = cg_rmdir(cfrom, pfrom); if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY) return r; @@ -463,8 +486,7 @@ int cg_migrate_recursive_fallback( const char *pfrom, const char *cto, const char *pto, - bool ignore_self, - bool rem) { + CGroupFlags flags) { int r; @@ -473,7 +495,7 @@ int cg_migrate_recursive_fallback( assert(cto); assert(pto); - r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem); + r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags); if (r < 0) { char prefix[strlen(pto) + 1]; @@ -482,7 +504,7 @@ int cg_migrate_recursive_fallback( PATH_FOREACH_PREFIX(prefix, pto) { int q; - q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem); + q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags); if (q >= 0) return q; } @@ -1955,7 +1977,7 @@ int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to int r = 0, unified; if (!path_equal(from, to)) { - r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true); + r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE); if (r < 0) return r; } @@ -1979,7 +2001,7 @@ int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to if (!p) p = to; - (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, false, false); + (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0); } return 0; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 4bb5291296..14ebde5fc9 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -135,12 +135,20 @@ int cg_read_event(const char *controller, const char *path, const char *event, int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); int cg_read_subgroup(DIR *d, char **fn); -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool remove, Set *s); +typedef enum CGroupFlags { + CGROUP_SIGCONT = 1, + CGROUP_IGNORE_SELF = 2, + CGROUP_REMOVE = 4, +} CGroupFlags; -int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self); -int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool remove); -int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem); +typedef void (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata); + +int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata); +int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata); + +int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags); +int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags); +int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags); int cg_split_spec(const char *spec, char **controller, char **path); int cg_mangle_path(const char *path, char **result); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 94d1161605..8b0f11ed50 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1705,7 +1705,7 @@ int manager_setup_cgroup(Manager *m) { /* also, move all other userspace processes remaining * in the root cgroup into that scope. */ - r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, false); + r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0); if (r < 0) log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m"); diff --git a/src/core/scope.c b/src/core/scope.c index decd1a1f3f..66a5058a57 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -240,7 +240,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { /* If we have a controller set let's ask the controller nicely * to terminate the scope, instead of us going directly into - * SIGTERM beserk mode */ + * SIGTERM berserk mode */ if (state == SCOPE_STOP_SIGTERM) skip_signal = bus_scope_send_request_stop(s) > 0; diff --git a/src/core/service.c b/src/core/service.c index 13de671700..afb198507b 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1674,7 +1674,7 @@ static void service_kill_control_processes(Service *s) { return; p = strjoina(UNIT(s)->cgroup_path, "/control"); - cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, true, true, true, NULL); + cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, CGROUP_SIGCONT|CGROUP_IGNORE_SELF|CGROUP_REMOVE, NULL, NULL, NULL); } static void service_enter_start(Service *s) { diff --git a/src/core/unit.c b/src/core/unit.c index fdf7ce3af3..4934a0e56f 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3144,7 +3144,7 @@ int unit_kill_common( if (!pid_set) return -ENOMEM; - q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set); + q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, NULL, NULL); if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT) r = q; else @@ -3512,6 +3512,43 @@ int unit_make_transient(Unit *u) { return 0; } +static void log_kill(pid_t pid, int sig, void *userdata) { + _cleanup_free_ char *comm = NULL; + + (void) get_process_comm(pid, &comm); + + /* Don't log about processes marked with brackets, under the assumption that these are temporary processes + only, like for example systemd's own PAM stub process. */ + if (comm && comm[0] == '(') + return; + + log_unit_notice(userdata, + "Killing process " PID_FMT " (%s) with signal SIG%s.", + pid, + strna(comm), + signal_to_string(sig)); +} + +static int operation_to_signal(KillContext *c, KillOperation k) { + assert(c); + + switch (k) { + + case KILL_TERMINATE: + case KILL_TERMINATE_AND_LOG: + return c->kill_signal; + + case KILL_KILL: + return SIGKILL; + + case KILL_ABORT: + return SIGABRT; + + default: + assert_not_reached("KillOperation unknown"); + } +} + int unit_kill_context( Unit *u, KillContext *c, @@ -3520,58 +3557,63 @@ int unit_kill_context( pid_t control_pid, bool main_pid_alien) { - bool wait_for_exit = false; + bool wait_for_exit = false, send_sighup; + cg_kill_log_func_t log_func; int sig, r; assert(u); assert(c); + /* Kill the processes belonging to this unit, in preparation for shutting the unit down. Returns > 0 if we + * killed something worth waiting for, 0 otherwise. */ + if (c->kill_mode == KILL_NONE) return 0; - switch (k) { - case KILL_KILL: - sig = SIGKILL; - break; - case KILL_ABORT: - sig = SIGABRT; - break; - case KILL_TERMINATE: - sig = c->kill_signal; - break; - default: - assert_not_reached("KillOperation unknown"); - } + sig = operation_to_signal(c, k); + + send_sighup = + c->send_sighup && + IN_SET(k, KILL_TERMINATE, KILL_TERMINATE_AND_LOG) && + sig != SIGHUP; + + log_func = + k != KILL_TERMINATE || + IN_SET(sig, SIGKILL, SIGABRT) ? log_kill : NULL; if (main_pid > 0) { - r = kill_and_sigcont(main_pid, sig); + if (log_func) + log_func(main_pid, sig, u); + r = kill_and_sigcont(main_pid, sig); if (r < 0 && r != -ESRCH) { _cleanup_free_ char *comm = NULL; - get_process_comm(main_pid, &comm); + (void) get_process_comm(main_pid, &comm); log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid, strna(comm)); } else { if (!main_pid_alien) wait_for_exit = true; - if (c->send_sighup && k == KILL_TERMINATE) + if (r != -ESRCH && send_sighup) (void) kill(main_pid, SIGHUP); } } if (control_pid > 0) { - r = kill_and_sigcont(control_pid, sig); + if (log_func) + log_func(control_pid, sig, u); + r = kill_and_sigcont(control_pid, sig); if (r < 0 && r != -ESRCH) { _cleanup_free_ char *comm = NULL; - get_process_comm(control_pid, &comm); + (void) get_process_comm(control_pid, &comm); log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid, strna(comm)); } else { wait_for_exit = true; - if (c->send_sighup && k == KILL_TERMINATE) + if (r != -ESRCH && send_sighup) (void) kill(control_pid, SIGHUP); } } @@ -3585,7 +3627,11 @@ int unit_kill_context( if (!pid_set) return -ENOMEM; - r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, k != KILL_TERMINATE, false, pid_set); + r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, + sig, + CGROUP_SIGCONT|CGROUP_IGNORE_SELF, + pid_set, + log_func, u); if (r < 0) { if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) log_unit_warning_errno(u, r, "Failed to kill control group %s, ignoring: %m", u->cgroup_path); @@ -3610,14 +3656,18 @@ int unit_kill_context( (detect_container() == 0 && !unit_cgroup_delegate(u))) wait_for_exit = true; - if (c->send_sighup && k != KILL_KILL) { + if (send_sighup) { set_free(pid_set); pid_set = unit_pid_set(main_pid, control_pid); if (!pid_set) return -ENOMEM; - cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, false, true, false, pid_set); + cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, + SIGHUP, + CGROUP_IGNORE_SELF, + pid_set, + NULL, NULL); } } } diff --git a/src/core/unit.h b/src/core/unit.h index c41011ed9d..1eabfa51e2 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -36,6 +36,7 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; typedef enum KillOperation { KILL_TERMINATE, + KILL_TERMINATE_AND_LOG, KILL_KILL, KILL_ABORT, _KILL_OPERATION_MAX, diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 72c32d9c8f..5336c19652 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -60,16 +60,16 @@ int main(int argc, char*argv[]) { assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") > 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, 0, NULL, NULL, NULL) == 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, 0, NULL, NULL, NULL) > 0); - assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0); + assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) > 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") > 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, 0, NULL, NULL, NULL) > 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, 0, NULL, NULL, NULL) == 0); cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index a8ab208816..a893a2b3d9 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1256,7 +1256,7 @@ static int on_post(sd_event_source *s, void *userdata) { return r; } else if (manager->cgroup) /* cleanup possible left-over processes in our cgroup */ - cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL); + cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, NULL, NULL, NULL); } } -- cgit v1.2.3-54-g00ecf From 0d5b4810929f3e224c392ede913bb81042800101 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 11:16:53 +0200 Subject: cgroup: suppress sending follow-up SIGCONT after sending SIGCONT/SIGKILL anyway --- src/basic/cgroup-util.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 630e15b141..472e24b7a3 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -213,6 +213,11 @@ int cg_kill( assert(sig >= 0); + /* Don't send SIGCONT twice. Also, SIGKILL always works even when process is suspended, hence don't send + * SIGCONT on SIGKILL. */ + if (IN_SET(sig, SIGCONT, SIGKILL)) + flags &= ~CGROUP_SIGCONT; + /* This goes through the tasks list and kills them all. This * is repeated until no further processes are added to the * tasks list, to properly handle forking processes */ -- cgit v1.2.3-54-g00ecf From f4b0fb236ba85f4aab483d3749a90ab3a85ed1a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 13:39:23 +0200 Subject: core: make sure RequestStop signal is send directed This was accidentally left commented out for debugging purposes, let's fix that and make the signal directed again. --- src/core/dbus-scope.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index f557eedfc3..1abaf9f658 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -225,5 +225,5 @@ int bus_scope_send_request_stop(Scope *s) { if (r < 0) return r; - return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL); + return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL); } -- cgit v1.2.3-54-g00ecf From 3862e809d04f4119d294719982a1dce9a0f444d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 13:41:32 +0200 Subject: core: when a scope was abandoned, always log about processes we kill After all, if a unit is abandoned, all processes inside of it may be considered "left over" and are something we should better log about. --- src/core/scope.c | 14 +++++++++++++- src/core/scope.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/scope.c b/src/core/scope.c index 66a5058a57..b45e238974 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -248,7 +248,9 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { r = unit_kill_context( UNIT(s), &s->kill_context, - state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE, + state != SCOPE_STOP_SIGTERM ? KILL_KILL : + s->was_abandoned ? KILL_TERMINATE_AND_LOG : + KILL_TERMINATE, -1, -1, false); if (r < 0) goto fail; @@ -369,6 +371,7 @@ static int scope_serialize(Unit *u, FILE *f, FDSet *fds) { assert(fds); unit_serialize_item(u, f, "state", scope_state_to_string(s->state)); + unit_serialize_item(u, f, "was-abandoned", yes_no(s->was_abandoned)); return 0; } @@ -389,6 +392,14 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F else s->deserialized_state = state; + } else if (streq(key, "was-abandoned")) { + int k; + + k = parse_boolean(value); + if (k < 0) + log_unit_debug(u, "Failed to parse boolean value: %s", value); + else + s->was_abandoned = k; } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -474,6 +485,7 @@ int scope_abandon(Scope *s) { if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED)) return -ESTALE; + s->was_abandoned = true; s->controller = mfree(s->controller); /* The client is no longer watching the remaining processes, diff --git a/src/core/scope.h b/src/core/scope.h index 2dc86325c5..94e9807bff 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -43,6 +43,7 @@ struct Scope { usec_t timeout_stop_usec; char *controller; + bool was_abandoned; sd_event_source *timer_event_source; }; -- cgit v1.2.3-54-g00ecf From 756ed0e238b7243c2e4616083e838d90de6e33ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 13:42:36 +0200 Subject: logind: always abandon session scopes before killing them This way systemd is informed that we consider everything inside the scope as "left-over", and systemd can log about killing it. With this change systemd will log about all processes killed due to the session clean-up on KillUserProcesses=yes. --- src/login/logind-session.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 0b917c23e1..b6da237397 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -610,6 +610,14 @@ static int session_stop_scope(Session *s, bool force) { if (!s->scope) return 0; + /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything + * that is left in in the scope is "left-over". Informing systemd about this has the benefit that it will log + * when killing any processes left after this point. */ + r = manager_abandon_scope(s->manager, s->scope, &error); + if (r < 0) + log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r)); + + /* Optionally, let's kill everything that's left now. */ if (force || manager_shall_kill(s->manager, s->user->name)) { char *job = NULL; @@ -619,11 +627,8 @@ static int session_stop_scope(Session *s, bool force) { free(s->scope_job); s->scope_job = job; - } else { - r = manager_abandon_scope(s->manager, s->scope, &error); - if (r < 0) - return log_error_errno(r, "Failed to abandon session scope: %s", bus_error_message(&error, r)); - } + } else + s->scope_job = mfree(s->scope_job); return 0; } -- cgit v1.2.3-54-g00ecf From 7a1ab780c4de9eba20c6800a51b5cdeae1d19790 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Jul 2016 19:57:21 -0700 Subject: execute: normalize connect_logger_as() parameters slightly All other functions in execute.c that need the unit id take a Unit* parameter as first argument. Let's change connect_logger_as() to follow a similar logic. --- src/core/execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 05dc1aaec1..40466ad53c 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -290,10 +290,10 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { } static int connect_logger_as( + Unit *unit, const ExecContext *context, ExecOutput output, const char *ident, - const char *unit_id, int nfd, uid_t uid, gid_t gid) { @@ -329,7 +329,7 @@ static int connect_logger_as( "%i\n" "%i\n", context->syslog_identifier ? context->syslog_identifier : ident, - unit_id, + unit->id, context->syslog_priority, !!context->syslog_level_prefix, output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE, @@ -544,7 +544,7 @@ static int setup_output( case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE: - r = connect_logger_as(context, o, ident, unit->id, fileno, uid, gid); + r = connect_logger_as(unit, context, o, ident, fileno, uid, gid); if (r < 0) { log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr"); r = open_null_as(O_WRONLY, fileno); -- cgit v1.2.3-54-g00ecf From 9ce93478809de9a421b4a710c7c9de55ecf15187 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Jul 2016 19:58:14 -0700 Subject: core: normalize header inclusion in execute.h a bit We don't actually need any functionality from cgroup.h in execute.h, hence don't include that. However, we do need the Unit structure from unit.h, hence include that, and move it as late as possible, since it needs the definitions from execute.h. --- src/core/execute.h | 6 +++--- src/core/scope.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/execute.h b/src/core/execute.h index 73b8a119b0..189c4d0999 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -30,6 +30,7 @@ typedef struct ExecParameters ExecParameters; #include #include +#include "cgroup-util.h" #include "fdset.h" #include "list.h" #include "missing.h" @@ -203,9 +204,6 @@ struct ExecContext { bool no_new_privileges_set:1; }; -#include "cgroup-util.h" -#include "cgroup.h" - struct ExecParameters { char **argv; char **environment; @@ -236,6 +234,8 @@ struct ExecParameters { int stderr_fd; }; +#include "unit.h" + int exec_spawn(Unit *unit, ExecCommand *command, const ExecContext *context, diff --git a/src/core/scope.h b/src/core/scope.h index 2dc86325c5..713b8b9f02 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -21,7 +21,9 @@ typedef struct Scope Scope; +#include "cgroup.h" #include "kill.h" +#include "unit.h" typedef enum ScopeResult { SCOPE_SUCCESS, -- cgit v1.2.3-54-g00ecf From 00d0fd0619a8651a6fb65c056eddfc87ff8f56ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 12:24:59 +0200 Subject: conf-parser: minor coding style improvements --- src/shared/conf-parser.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 83be79a4f5..d85ab5441e 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -708,6 +708,7 @@ int config_parse_strv(const char *unit, void *userdata) { char ***sv = data; + int r; assert(filename); assert(lvalue); @@ -721,18 +722,19 @@ int config_parse_strv(const char *unit, * we actually fill in a real empty array here rather * than NULL, since some code wants to know if * something was set at all... */ - empty = strv_new(NULL, NULL); + empty = new0(char*, 1); if (!empty) return log_oom(); strv_free(*sv); *sv = empty; + return 0; } for (;;) { char *word = NULL; - int r; + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE); if (r == 0) break; -- cgit v1.2.3-54-g00ecf From 065d31c3601a80dffd278f43619773682ac35b29 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 12:25:32 +0200 Subject: nspawn: document why the uid shift range is the way it is --- src/nspawn/nspawn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e4be0a2251..32e40f5d21 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -101,9 +101,11 @@ #include "util.h" /* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit - * UID range here */ + * UID range here. We leave a bit of room at the lower end and a lot of room at the upper end, so that other subsystems + * may have their own allocation ranges too. */ #define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000)) #define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000)) + /* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path * nspawn_notify_socket_path is relative to the container * the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */ -- cgit v1.2.3-54-g00ecf From 1ddc1272e7ea6d68b7e966a6c5e37f84a1810bd8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 16:53:13 +0200 Subject: nspawn: when netns is on, mount /proc/sys/net writable Normally we make all of /proc/sys read-only in a container, but if we do have netns enabled we can make /proc/sys/net writable, as things are virtualized then. --- src/nspawn/nspawn-mount.c | 23 ++++++++++++----------- src/nspawn/nspawn.c | 1 - 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 9f4903c842..85e2c943e3 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -297,18 +297,19 @@ int mount_all(const char *dest, } MountPoint; static const MountPoint mount_table[] = { - { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false }, - { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first */ - { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* Then, make it r/o */ - { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true }, - { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false }, - { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false }, - { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, - { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false }, + { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false }, + { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first ...*/ + { "/proc/sys/net", "/proc/sys/net", NULL, NULL, MS_BIND, true, true, true }, /* (except for this) */ + { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* ... then, make it r/o */ + { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true }, + { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false }, + { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false }, #ifdef HAVE_SELINUX - { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */ - { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */ + { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */ + { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */ #endif }; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 32e40f5d21..6c8263d3d5 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -279,7 +279,6 @@ static void help(void) { , program_invocation_short_name); } - static int custom_mounts_prepare(void) { unsigned i; int r; -- cgit v1.2.3-54-g00ecf From fe048ce56ab430a73e7118df87cb9f0f3488be26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 12:28:54 +0200 Subject: namespace: add a (void) cast --- src/core/namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/namespace.c b/src/core/namespace.c index 8df82c031c..02ec81f71c 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -641,7 +641,7 @@ int setup_netns(int netns_storage_socket[2]) { } fail: - lockf(netns_storage_socket[0], F_ULOCK, 0); + (void) lockf(netns_storage_socket[0], F_ULOCK, 0); return r; } -- cgit v1.2.3-54-g00ecf From 33df919d5c4de51b88244d2e82ffe5c9c8abe950 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 13:12:01 +0200 Subject: execute: make sure JoinsNamespaceOf= doesn't leak ns fds to executed processes --- src/core/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 40466ad53c..7c178b97c3 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3062,7 +3062,7 @@ int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) { return r; if (c->private_network && (*rt)->netns_storage_socket[0] < 0) { - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (*rt)->netns_storage_socket) < 0) + if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, (*rt)->netns_storage_socket) < 0) return -errno; } -- cgit v1.2.3-54-g00ecf From c0f81393d137a258a5c255755c08b498860a5241 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2016 19:16:19 +0200 Subject: basic: fix macro definition in nss-util.h Fix a copy/paste mistake. --- src/basic/nss-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index bf7c4854fc..e7844fff96 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -137,7 +137,7 @@ enum nss_status _nss_##module##_getpwnam_r( \ struct passwd *pwd, \ char *buffer, size_t buflen, \ int *errnop) _public_; \ -enum nss_status _nss_mymachines_getpwuid_r( \ +enum nss_status _nss_##module##_getpwuid_r( \ uid_t uid, \ struct passwd *pwd, \ char *buffer, size_t buflen, \ -- cgit v1.2.3-54-g00ecf From 176e51b7102d7bba875e58b85b59e2ed7e30bc89 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Wed, 20 Jul 2016 14:43:21 +0000 Subject: namespace: fix wrong return value from mount(2) (#3758) Fix bug introduced by #3263: mount(2) return value is 0 or -1, not errno. Thanks to Evgeny Vereshchagin (@evverx) for reporting. --- src/core/namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/namespace.c b/src/core/namespace.c index 8df82c031c..4baf4750f4 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -347,7 +347,8 @@ static int make_read_only(BindMount *m) { else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) { r = bind_remount_recursive(m->path, false); if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/ - r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL); + if (mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0) + r = -errno; } else r = 0; -- cgit v1.2.3-54-g00ecf From b7536c45ef7307a4e2c4921ad2201d4bcaa4bac6 Mon Sep 17 00:00:00 2001 From: Alexander Kurtz Date: Thu, 21 Jul 2016 02:20:12 +0200 Subject: bootctl: Use lower case string constants in case-insensitive comparisons. --- src/boot/bootctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 0d42948720..52d79f1c67 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -797,7 +797,7 @@ static int remove_boot_efi(const char *esp_path) { if (!endswith_no_case(de->d_name, ".efi")) continue; - if (!startswith_no_case(de->d_name, "Boot")) + if (!startswith_no_case(de->d_name, "boot")) continue; fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC); -- cgit v1.2.3-54-g00ecf From 00f69504a2c1861d98a027afdebc22c873f09083 Mon Sep 17 00:00:00 2001 From: Alexander Kurtz Date: Thu, 21 Jul 2016 02:29:54 +0200 Subject: bootctl: Always use upper case for "/EFI/BOOT" and "/EFI/BOOT/BOOT*.EFI". If the ESP is not mounted with "iocharset=ascii", but with "iocharset=utf8" (which is for example the default in Debian), the file system becomes case sensitive. This means that a file created as "FooBarBaz" cannot be accessed as "foobarbaz" since those are then considered different files. Moreover, a file created as "FooBar" can then also not be accessed as "foobar", and it also prevents such a file from being created, as both would use the same 8.3 short name "FOOBAR". Even though the UEFI specification [0] does give the canonical spelling for the files mentioned above, not all implementations completely conform to that, so it's possible that those files would already exist, but with a different spelling, causing subtle bugs when scanning or modifying the ESP. While the proper fix would of course be that everybody conformed to the standard, we can work around this problem by just referencing the files by their 8.3 short names, i.e. using upper case. Fixes: #3740 [0] , version 2.6, section 3.5.1.1 --- man/bootctl.xml | 4 ++-- src/boot/bootctl.c | 8 ++++---- test/test-efi-create-disk.sh | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/bootctl.xml b/man/bootctl.xml index ebd58750d3..6e835c037f 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -74,14 +74,14 @@ bootctl update updates all installed versions of systemd-boot, if the current version is newer than the version installed in the EFI system partition. This also includes - the EFI default/fallback loader at /EFI/Boot/boot*.efi. A + the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A systemd-boot entry in the EFI boot variables is created if there is no current entry. The created entry will be added to the end of the boot order list. bootctl install installs systemd-boot into the EFI system partition. A copy of systemd-boot will be stored as - the EFI default/fallback loader at /EFI/Boot/boot*.efi. A systemd-boot + the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A systemd-boot entry in the EFI boot variables is created and added to the top of the boot order list. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 52d79f1c67..7cb2259717 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -288,7 +288,7 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) { else if (r < 0) return r; - r = enumerate_binaries(esp_path, "EFI/Boot", "boot"); + r = enumerate_binaries(esp_path, "EFI/BOOT", "boot"); if (r == 0) log_error("No default/fallback boot loader installed in ESP."); else if (r < 0) @@ -548,7 +548,7 @@ static int mkdir_one(const char *prefix, const char *suffix) { static const char *efi_subdirs[] = { "EFI", "EFI/systemd", - "EFI/Boot", + "EFI/BOOT", "loader", "loader/entries" }; @@ -579,7 +579,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) { char *v; /* Create the EFI default boot loader name (specified for removable devices) */ - v = strjoina(esp_path, "/EFI/Boot/BOOT", name + strlen("systemd-boot")); + v = strjoina(esp_path, "/EFI/BOOT/BOOT", name + strlen("systemd-boot")); strupper(strrchr(v, '/') + 1); k = copy_file(p, v, force); @@ -781,7 +781,7 @@ static int remove_boot_efi(const char *esp_path) { struct dirent *de; int r, c = 0; - p = strjoina(esp_path, "/EFI/Boot"); + p = strjoina(esp_path, "/EFI/BOOT"); d = opendir(p); if (!d) { if (errno == ENOENT) diff --git a/test/test-efi-create-disk.sh b/test/test-efi-create-disk.sh index 56dd09abd7..cd4699dc18 100755 --- a/test/test-efi-create-disk.sh +++ b/test/test-efi-create-disk.sh @@ -11,8 +11,8 @@ mkfs.vfat -F32 ${LOOP}p1 mkdir -p mnt mount ${LOOP}p1 mnt -mkdir -p mnt/EFI/{Boot,systemd} -cp systemd-bootx64.efi mnt/EFI/Boot/bootx64.efi +mkdir -p mnt/EFI/{BOOT,systemd} +cp systemd-bootx64.efi mnt/EFI/BOOT/BOOTX64.efi [ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/ -- cgit v1.2.3-54-g00ecf From f8298f7be39f405eea062295f17d527109b6b463 Mon Sep 17 00:00:00 2001 From: "Thomas H. P. Andersen" Date: Thu, 21 Jul 2016 10:52:07 +0200 Subject: core: remove duplicate includes (#3771) --- src/core/cgroup.h | 1 - src/core/manager.c | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.h b/src/core/cgroup.h index f21409bd5d..a57403e79f 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -119,7 +119,6 @@ struct CGroupContext { bool delegate; }; -#include "cgroup-util.h" #include "unit.h" void cgroup_context_init(CGroupContext *c); diff --git a/src/core/manager.c b/src/core/manager.c index c69b797430..a0181e2138 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -64,7 +64,6 @@ #include "manager.h" #include "missing.h" #include "mkdir.h" -#include "mkdir.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" -- cgit v1.2.3-54-g00ecf From 4d07c8d386b6f025c8834d133a54cea40fd7fc6f Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Thu, 21 Jul 2016 11:40:35 +0200 Subject: missing_syscall: add __NR_copy_file_range for powerpc architecture (#3772) --- src/basic/missing_syscall.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index e102083684..e6fd67cb9d 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -279,6 +279,8 @@ static inline key_serial_t request_key(const char *type, const char *description # define __NR_copy_file_range 391 # elif defined __aarch64__ # define __NR_copy_file_range 285 +# elif defined __powerpc__ +# define __NR_copy_file_range 379 # else # warning "__NR_copy_file_range not defined for your architecture" # endif -- cgit v1.2.3-54-g00ecf From 31d28eabc10967daf06ae6ac4959a59556f1e7ff Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Thu, 21 Jul 2016 17:39:38 +0200 Subject: nspawn: enable major=0/minor=0 devices inside the container (#3773) https://github.com/systemd/systemd/pull/3685 introduced /run/systemd/inaccessible/{chr,blk} to map inacessible devices, this patch allows systemd running inside a nspawn container to create /run/systemd/inaccessible/{chr,blk}. --- src/core/dbus-cgroup.c | 1 + src/nspawn/nspawn-register.c | 8 ++++++-- units/systemd-nspawn@.service.in | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 27bbe2d26d..6167ce92cd 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -960,6 +960,7 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { if ((!startswith(path, "/dev/") && + !startswith(path, "/run/systemd/inaccessible/") && !startswith(path, "block-") && !startswith(path, "char-")) || strpbrk(path, WHITESPACE)) diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 20103c5e88..7fd711b8a4 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -112,7 +112,7 @@ int register_machine( * systemd-nspawn@.service, to keep the device * policies in sync regardless if we are run with or * without the --keep-unit switch. */ - r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9, + r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 11, /* Allow the container to * access and create the API * device nodes, so that @@ -132,7 +132,11 @@ int register_machine( * container to ever create * these device nodes. */ "/dev/pts/ptmx", "rw", - "char-pts", "rw"); + "char-pts", "rw", + /* Allow /run/systemd/inaccessible/{chr,blk} + * devices inside the container */ + "/run/systemd/inaccessible/chr", "rwm", + "/run/systemd/inaccessible/blk", "rwm"); if (r < 0) return bus_log_create_error(r); diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index ea28941507..a88774a495 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -35,6 +35,8 @@ DeviceAllow=/dev/tty rwm DeviceAllow=/dev/net/tun rwm DeviceAllow=/dev/pts/ptmx rw DeviceAllow=char-pts rw +DeviceAllow=/run/systemd/inaccessible/chr rwm +DeviceAllow=/run/systemd/inaccessible/blk rwm # nspawn itself needs access to /dev/loop-control and /dev/loop, to # implement the --image= option. Add these here, too. -- cgit v1.2.3-54-g00ecf From 3bbaff3e08070f03487958818edbd161d439ce15 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 16:06:31 +0200 Subject: tree-wide: use sd_id128_is_null() instead of sd_id128_equal where appropriate It's a bit easier to read because shorter. Also, most likely a tiny bit faster. --- src/boot/bootctl.c | 4 ++-- src/firstboot/firstboot.c | 2 +- src/journal/journalctl.c | 2 +- src/journal/journald-server.c | 2 +- src/libsystemd/sd-bus/bus-socket.c | 2 +- src/machine/machine.c | 2 +- src/machine/machinectl.c | 2 +- src/nspawn/nspawn.c | 10 +++++----- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7cb2259717..37fa049ecf 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -311,7 +311,7 @@ static int print_efi_option(uint16_t id, bool in_order) { return r; /* print only configured entries with partition information */ - if (!path || sd_id128_equal(partition, SD_ID128_NULL)) + if (!path || sd_id128_is_null(partition)) return 0; efi_tilt_backslashes(path); @@ -1072,7 +1072,7 @@ static int bootctl_main(int argc, char*argv[]) { printf("Loader:\n"); printf(" Product: %s\n", strna(loader)); - if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL)) + if (!sd_id128_is_null(loader_part_uuid)) printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(loader_part_uuid)); else diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 3df72460ef..c9e8e54ee3 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -427,7 +427,7 @@ static int process_machine_id(void) { if (laccess(etc_machine_id, F_OK) >= 0) return 0; - if (sd_id128_equal(arg_machine_id, SD_ID128_NULL)) + if (sd_id128_is_null(arg_machine_id)) return 0; mkdir_parents(etc_machine_id, 0755); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 4cc0c2b6c2..53c6180864 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1266,7 +1266,7 @@ static int add_boot(sd_journal *j) { /* Take a shortcut and use the current boot_id, which we can do very quickly. * We can do this only when we logs are coming from the current machine, * so take the slow path if log location is specified. */ - if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL) && + if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) && !arg_directory && !arg_file) return add_match_this_boot(j, arg_machine); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 886e0ec856..587c343b31 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -877,7 +877,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format, assert_cc(6 == LOG_INFO); IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); - if (!sd_id128_equal(message_id, SD_ID128_NULL)) { + if (!sd_id128_is_null(message_id)) { snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id)); IOVEC_SET_STRING(iovec[n++], mid); } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index f1e2a06050..cfd7753139 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -221,7 +221,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) { peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y); } - if (!sd_id128_equal(b->server_id, SD_ID128_NULL) && + if (!sd_id128_is_null(b->server_id) && !sd_id128_equal(b->server_id, peer)) return -EPERM; diff --git a/src/machine/machine.c b/src/machine/machine.c index c1fae57084..dd046d6563 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -181,7 +181,7 @@ int machine_save(Machine *m) { fprintf(f, "ROOT=%s\n", escaped); } - if (!sd_id128_equal(m->id, SD_ID128_NULL)) + if (!sd_id128_is_null(m->id)) fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id)); if (m->leader != 0) diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 96e0ab4b8a..ddec6cb4d6 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -528,7 +528,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) { fputs(strna(i->name), stdout); - if (!sd_id128_equal(i->id, SD_ID128_NULL)) + if (!sd_id128_is_null(i->id)) printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id)); else putchar('\n'); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 6c8263d3d5..ae0d2a8deb 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1277,8 +1277,8 @@ static char* id128_format_as_uuid(sd_id128_t id, char s[37]) { } static int setup_boot_id(const char *dest) { + sd_id128_t rnd = SD_ID128_NULL; const char *from, *to; - sd_id128_t rnd = {}; char as_uuid[37]; int r; @@ -1304,9 +1304,9 @@ static int setup_boot_id(const char *dest) { if (mount(from, to, NULL, MS_BIND, NULL) < 0) r = log_error_errno(errno, "Failed to bind mount boot id: %m"); else if (mount(NULL, to, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL) < 0) - log_warning_errno(errno, "Failed to make boot id read-only: %m"); + log_warning_errno(errno, "Failed to make boot id read-only, ignoring: %m"); - unlink(from); + (void) unlink(from); return r; } @@ -2232,9 +2232,9 @@ static int mount_device(const char *what, const char *where, const char *directo } static int setup_machine_id(const char *directory) { - int r; const char *etc_machine_id, *t; _cleanup_free_ char *s = NULL; + int r; etc_machine_id = prefix_roota(directory, "/etc/machine-id"); @@ -2663,7 +2663,7 @@ static int inner_child( (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) return log_oom(); - assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL)); + assert(!sd_id128_is_null(arg_uuid)); if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0) return log_oom(); -- cgit v1.2.3-54-g00ecf From 910fd145f46f0916adbc6035b0433eb586bd6ce0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 17:57:57 +0200 Subject: sd-id128: split UUID file read/write code into new id128-util.[ch] We currently have code to read and write files containing UUIDs at various places. Unify this in id128-util.[ch], and move some other stuff there too. The new files are located in src/libsystemd/sd-id128/ (instead of src/shared/), because they are actually the backend of sd_id128_get_machine() and sd_id128_get_boot(). In follow-up patches we can use this reduce the code in nspawn and machine-id-setup by adopted the common implementation. --- Makefile.am | 3 + src/basic/util.c | 41 --------- src/basic/util.h | 2 - src/core/machine-id-setup.c | 1 + src/libsystemd/sd-id128/id128-util.c | 171 +++++++++++++++++++++++++++++++++++ src/libsystemd/sd-id128/id128-util.h | 45 +++++++++ src/libsystemd/sd-id128/sd-id128.c | 114 +++++------------------ src/nspawn/nspawn.c | 3 +- src/test/test-id128.c | 14 ++- 9 files changed, 260 insertions(+), 134 deletions(-) create mode 100644 src/libsystemd/sd-id128/id128-util.c create mode 100644 src/libsystemd/sd-id128/id128-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c9fb4917ad..f7288f6df7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -242,6 +242,7 @@ AM_CPPFLAGS = \ -I $(top_srcdir)/src/libsystemd/sd-network \ -I $(top_srcdir)/src/libsystemd/sd-hwdb \ -I $(top_srcdir)/src/libsystemd/sd-device \ + -I $(top_srcdir)/src/libsystemd/sd-id128 \ -I $(top_srcdir)/src/libsystemd-network \ $(OUR_CPPFLAGS) @@ -3213,6 +3214,8 @@ libsystemd_internal_la_SOURCES = \ src/libsystemd/sd-netlink/local-addresses.h \ src/libsystemd/sd-netlink/local-addresses.c \ src/libsystemd/sd-id128/sd-id128.c \ + src/libsystemd/sd-id128/id128-util.h \ + src/libsystemd/sd-id128/id128-util.c \ src/libsystemd/sd-daemon/sd-daemon.c \ src/libsystemd/sd-login/sd-login.c \ src/libsystemd/sd-path/sd-path.c \ diff --git a/src/basic/util.c b/src/basic/util.c index 09d16697b7..41e79315ae 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -581,47 +581,6 @@ int on_ac_power(void) { return found_online || !found_offline; } -bool id128_is_valid(const char *s) { - size_t i, l; - - l = strlen(s); - if (l == 32) { - - /* Simple formatted 128bit hex string */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - - } else if (l == 36) { - - /* Formatted UUID */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if ((i == 8 || i == 13 || i == 18 || i == 23)) { - if (c != '-') - return false; - } else { - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - } - - } else - return false; - - return true; -} - int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; diff --git a/src/basic/util.h b/src/basic/util.h index db105197e8..94b8091906 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -176,8 +176,6 @@ static inline unsigned log2u_round_up(unsigned x) { return log2u(x - 1) + 1; } -bool id128_is_valid(const char *s) _pure_; - int container_get_leader(const char *machine, pid_t *pid); int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index ea6b085e4f..62f80833dd 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -32,6 +32,7 @@ #include "fileio.h" #include "fs-util.h" #include "hexdecoct.h" +#include "id128-util.h" #include "io-util.h" #include "log.h" #include "machine-id-setup.h" diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c new file mode 100644 index 0000000000..c1742cab0e --- /dev/null +++ b/src/libsystemd/sd-id128/id128-util.c @@ -0,0 +1,171 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "fd-util.h" +#include "hexdecoct.h" +#include "id128-util.h" +#include "io-util.h" +#include "stdio-util.h" + +char *id128_to_uuid_string(sd_id128_t id, char s[37]) { + unsigned n, k = 0; + + assert(s); + + /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */ + + for (n = 0; n < 16; n++) { + + if (IN_SET(n, 4, 6, 8, 10)) + s[k++] = '-'; + + s[k++] = hexchar(id.bytes[n] >> 4); + s[k++] = hexchar(id.bytes[n] & 0xF); + } + + assert(k == 36); + + s[k] = 0; + + return s; +} + +bool id128_is_valid(const char *s) { + size_t i, l; + + assert(s); + + l = strlen(s); + if (l == 32) { + + /* Plain formatted 128bit hex string */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + + } else if (l == 36) { + + /* Formatted UUID */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if ((i == 8 || i == 13 || i == 18 || i == 23)) { + if (c != '-') + return false; + } else { + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + } + + } else + return false; + + return true; +} + +int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { + char buffer[36 + 2]; + ssize_t l; + + assert(fd >= 0); + assert(f < _ID128_FORMAT_MAX); + + /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both + * followed by a newline and nothing else. */ + + l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 33 or 37 chars */ + if (l < 0) + return (int) l; + if (l == 0) /* empty? */ + return -ENOMEDIUM; + + if (l == 33) { + if (f == ID128_UUID) + return -EINVAL; + + if (buffer[32] != '\n') + return -EINVAL; + + buffer[32] = 0; + + } else if (l == 37) { + if (f == ID128_PLAIN) + return -EINVAL; + + if (buffer[36] != '\n') + return -EINVAL; + + buffer[36] = 0; + } else + return -EINVAL; + + return sd_id128_from_string(buffer, ret); +} + +int id128_read(const char *p, Id128Format f, sd_id128_t *ret) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + return id128_read_fd(fd, f, ret); +} + +int id128_write_fd(int fd, Id128Format f, sd_id128_t id) { + char buffer[36 + 2]; + size_t sz; + + assert(fd >= 0); + assert(f < _ID128_FORMAT_MAX); + + if (f != ID128_UUID) { + sd_id128_to_string(id, buffer); + buffer[32] = '\n'; + sz = 33; + } else { + id128_to_uuid_string(id, buffer); + buffer[36] = '\n'; + sz = 37; + } + + return loop_write(fd, buffer, sz, false); +} + +int id128_write(const char *p, Id128Format f, sd_id128_t id) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); + if (fd < 0) + return -errno; + + return id128_write_fd(fd, f, id); +} diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h new file mode 100644 index 0000000000..73e4c710c4 --- /dev/null +++ b/src/libsystemd/sd-id128/id128-util.h @@ -0,0 +1,45 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "sd-id128.h" +#include "macro.h" + +char *id128_to_uuid_string(sd_id128_t id, char s[37]); + +/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */ +#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" + +bool id128_is_valid(const char *s) _pure_; + +typedef enum Id128Format { + ID128_ANY, + ID128_PLAIN, /* formatted as 32 hex chars as-is */ + ID128_UUID, /* formatted as 36 character uuid string */ + _ID128_FORMAT_MAX, +} Id128Format; + +int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret); +int id128_read(const char *p, Id128Format f, sd_id128_t *ret); + +int id128_write_fd(int fd, Id128Format f, sd_id128_t id); +int id128_write(const char *p, Id128Format f, sd_id128_t id); diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index d9c0116f60..1470e4c01a 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -25,6 +25,7 @@ #include "fd-util.h" #include "hexdecoct.h" +#include "id128-util.h" #include "io-util.h" #include "macro.h" #include "random-util.h" @@ -93,117 +94,52 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { 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; -} - _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]; - unsigned j; - sd_id128_t t; + static thread_local sd_id128_t saved_machine_id = {}; int r; 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; - - r = loop_read_exact(fd, buf, 33, false); - if (r < 0) - return r; - 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 (sd_id128_is_null(saved_machine_id)) { + r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id); + if (r < 0) + return r; - if (a < 0 || b < 0) - return -EIO; - - t.bytes[j] = a << 4 | b; + if (sd_id128_is_null(saved_machine_id)) + return -EINVAL; } - saved_machine_id = t; - saved_machine_id_valid = true; - - *ret = t; + *ret = saved_machine_id; return 0; } _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]; - unsigned j; - sd_id128_t t; - char *p; + static thread_local sd_id128_t saved_boot_id = {}; int r; assert_return(ret, -EINVAL); - if (saved_boot_id_valid) { - *ret = saved_boot_id; - return 0; + if (sd_id128_is_null(saved_boot_id)) { + r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id); + if (r < 0) + return r; } - fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - r = loop_read_exact(fd, buf, 36, false); - if (r < 0) - return r; - - for (j = 0, p = buf; j < 16; j++) { - int a, b; - - if (p >= buf + 35) - return -EIO; - - if (*p == '-') { - p++; - if (p >= buf + 35) - return -EIO; - } - - a = unhexchar(p[0]); - b = unhexchar(p[1]); - - if (a < 0 || b < 0) - return -EIO; + *ret = saved_boot_id; + return 0; +} - t.bytes[j] = a << 4 | b; +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 */ - p += 2; - } + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; - saved_boot_id = t; - saved_boot_id_valid = true; + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; - *ret = t; - return 0; + return id; } _public_ int sd_id128_randomize(sd_id128_t *ret) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ae0d2a8deb..d9301bd4dc 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -61,6 +61,7 @@ #include "fs-util.h" #include "gpt.h" #include "hostname-util.h" +#include "id128-util.h" #include "log.h" #include "loopback-setup.h" #include "machine-id-setup.h" @@ -76,10 +77,10 @@ #include "nspawn-network.h" #include "nspawn-patch-uid.h" #include "nspawn-register.h" +#include "nspawn-seccomp.h" #include "nspawn-settings.h" #include "nspawn-setuid.h" #include "nspawn-stub-pid1.h" -#include "nspawn-seccomp.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" diff --git a/src/test/test-id128.c b/src/test/test-id128.c index 96aa008c06..324c7a2019 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -26,6 +26,7 @@ #include "macro.h" #include "string-util.h" #include "util.h" +#include "id128-util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" @@ -33,7 +34,7 @@ int main(int argc, char *argv[]) { sd_id128_t id, id2; - char t[33]; + char t[33], q[37]; _cleanup_free_ char *b = NULL; assert_se(sd_id128_randomize(&id) == 0); @@ -57,6 +58,17 @@ int main(int argc, char *argv[]) { printf("waldi2: %s\n", b); assert_se(streq(t, b)); + printf("waldi3: %s\n", id128_to_uuid_string(ID128_WALDI, q)); + assert_se(streq(q, UUID_WALDI)); + + b = mfree(b); + assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36); + printf("waldi4: %s\n", b); + assert_se(streq(q, b)); + + assert_se(sd_id128_from_string(STR_WALDI, &id) >= 0); + assert_se(sd_id128_equal(id, ID128_WALDI)); + assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0); assert_se(sd_id128_equal(id, ID128_WALDI)); -- cgit v1.2.3-54-g00ecf From 691675ba9f7c783b94ccad99e7c34e36812b17d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 18:01:55 +0200 Subject: nspawn: rework machine/boot ID handling code to use new calls from id128-util.[ch] --- src/nspawn/nspawn.c | 54 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d9301bd4dc..d971cded5e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1267,20 +1267,9 @@ static int setup_resolv_conf(const char *dest) { return 0; } -static char* id128_format_as_uuid(sd_id128_t id, char s[37]) { - assert(s); - - snprintf(s, 37, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - SD_ID128_FORMAT_VAL(id)); - - return s; -} - static int setup_boot_id(const char *dest) { sd_id128_t rnd = SD_ID128_NULL; const char *from, *to; - char as_uuid[37]; int r; if (arg_share_system) @@ -1296,9 +1285,7 @@ static int setup_boot_id(const char *dest) { if (r < 0) return log_error_errno(r, "Failed to generate random boot id: %m"); - id128_format_as_uuid(rnd, as_uuid); - - r = write_string_file(from, as_uuid, WRITE_STRING_FILE_CREATE); + r = id128_write(from, ID128_UUID, rnd); if (r < 0) return log_error_errno(r, "Failed to write boot id: %m"); @@ -2232,35 +2219,38 @@ static int mount_device(const char *what, const char *where, const char *directo #endif } -static int setup_machine_id(const char *directory) { - const char *etc_machine_id, *t; - _cleanup_free_ char *s = NULL; +static int machine_id_read(const char *directory, sd_id128_t *ret) { + const char *etc_machine_id; + sd_id128_t id; int r; etc_machine_id = prefix_roota(directory, "/etc/machine-id"); - r = read_one_line_file(etc_machine_id, &s); + r = id128_read(etc_machine_id, ID128_PLAIN, &id); if (r < 0) - return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id); + return r; - t = strstrip(s); + if (sd_id128_is_null(id)) + return -EINVAL; - if (!isempty(t)) { - r = sd_id128_from_string(t, &arg_uuid); - if (r < 0) - return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id); - } else { - if (sd_id128_is_null(arg_uuid)) { - r = sd_id128_randomize(&arg_uuid); - if (r < 0) - return log_error_errno(r, "Failed to generate random machine ID: %m"); - } - } + *ret = id; + return 0; +} +static int setup_machine_id(const char *directory) { + int r; + + /* Try to set up the machine ID, if it isn't set up yet. Use a transient one, if necessary. Use the the UUID we + * were configured for if possible for initialization. */ r = machine_id_setup(directory, arg_uuid); if (r < 0) return log_error_errno(r, "Failed to setup machine ID: %m"); + /* Read back what was actually set. */ + r = machine_id_read(directory, &arg_uuid); + if (r < 0) + return log_error_errno(r, "Failed to read machine ID: %m"); + return 0; } @@ -2666,7 +2656,7 @@ static int inner_child( assert(!sd_id128_is_null(arg_uuid)); - if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0) + if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_to_uuid_string(arg_uuid, as_uuid)) < 0) return log_oom(); if (fdset_size(fds) > 0) { -- cgit v1.2.3-54-g00ecf From 1089dcd46966c83d415bb0b8353a8ce543a3bb7f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 18:05:58 +0200 Subject: systemctl: fix output alignment in "systemctl status" If we show both a control and a main PID for a service fix this line in the output of "systemctl status": Main PID: 19670 (sleep); : 19671 (sleep) to become this: Main PID: 19670 (sleep); Control PID: 19671 (sleep) --- src/systemctl/systemctl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d3f437411a..ab3c4fb585 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3761,7 +3761,7 @@ static void print_status_info( if (i->running) { _cleanup_free_ char *comm = NULL; - get_process_comm(i->main_pid, &comm); + (void) get_process_comm(i->main_pid, &comm); if (comm) printf(" (%s)", comm); } else if (i->exit_code > 0) { @@ -3780,17 +3780,19 @@ static void print_status_info( printf("signal=%s", signal_to_string(i->exit_status)); printf(")"); } - - if (i->control_pid > 0) - printf(";"); } if (i->control_pid > 0) { _cleanup_free_ char *c = NULL; - printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid); + if (i->main_pid > 0) + fputs("; Control PID: ", stdout); + else + fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */ + + printf(PID_FMT, i->control_pid); - get_process_comm(i->control_pid, &c); + (void) get_process_comm(i->control_pid, &c); if (c) printf(" (%s)", c); } -- cgit v1.2.3-54-g00ecf From 2a6736ddd080674170e9b9fe225009a0476c68e1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 18:08:52 +0200 Subject: systemctl: fix format string for uint64_t field --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ab3c4fb585..ff76d8287a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3809,7 +3809,7 @@ static void print_status_info( printf(" Tasks: %" PRIu64, i->tasks_current); if (i->tasks_max != (uint64_t) -1) - printf(" (limit: %" PRIi64 ")\n", i->tasks_max); + printf(" (limit: %" PRIu64 ")\n", i->tasks_max); else printf("\n"); } -- cgit v1.2.3-54-g00ecf From 317feb4d9f84cf177aa71496b214bcbbf9682750 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 18:53:40 +0200 Subject: nspawn: rework /etc/machine-id handling With this change we'll no longer write to /etc/machine-id from nspawn, as that breaks the --volatile= operation, as it ensures the image is never considered in "first boot", since that's bound to the pre-existance of /etc/machine-id. The new logic works like this: - If /etc/machine-id already exists in the container, it is read by nspawn and exposed in "machinectl status" and friends. - If the file doesn't exist yet, but --uuid= is passed on the nspawn cmdline, this UUID is passed in $container_uuid to PID 1, and PID 1 is then expected to persist this to /etc/machine-id for future boots (which systemd already does). - If the file doesn#t exist yet, and no --uuid= is passed a random UUID is generated and passed via $container_uuid. The result is that /etc/machine-id is never initialized by nspawn itself, thus unbreaking the volatile mode. However still the machine ID configured in the machine always matches nspawn's and thus machined's idea of it. Fixes: #3611 --- Makefile.am | 4 +--- src/nspawn/nspawn.c | 55 ++++++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index f7288f6df7..d5a70780a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3075,9 +3075,7 @@ systemd_nspawn_SOURCES = \ src/core/mount-setup.c \ src/core/mount-setup.h \ src/core/loopback-setup.c \ - src/core/loopback-setup.h \ - src/core/machine-id-setup.c \ - src/core/machine-id-setup.h + src/core/loopback-setup.h nodist_systemd_nspawn_SOURCES = \ src/nspawn/nspawn-gperf.c diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d971cded5e..4c1d79418d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -64,7 +64,6 @@ #include "id128-util.h" #include "log.h" #include "loopback-setup.h" -#include "machine-id-setup.h" #include "machine-image.h" #include "macro.h" #include "missing.h" @@ -595,9 +594,12 @@ static int parse_argv(int argc, char *argv[]) { case ARG_UUID: r = sd_id128_from_string(optarg, &arg_uuid); - if (r < 0) { - log_error("Invalid UUID: %s", optarg); - return r; + if (r < 0) + return log_error_errno(r, "Invalid UUID: %s", optarg); + + if (sd_id128_is_null(arg_uuid)) { + log_error("Machine UUID may not be all zeroes."); + return -EINVAL; } arg_settings_mask |= SETTING_MACHINE_ID; @@ -2219,37 +2221,38 @@ static int mount_device(const char *what, const char *where, const char *directo #endif } -static int machine_id_read(const char *directory, sd_id128_t *ret) { +static int setup_machine_id(const char *directory) { const char *etc_machine_id; sd_id128_t id; int r; + /* If the UUID in the container is already set, then that's what counts, and we use. If it isn't set, and the + * caller passed --uuid=, then we'll pass it in the $container_uuid env var to PID 1 of the container. The + * assumption is that PID 1 will then write it to /etc/machine-id to make it persistent. If --uuid= is not + * passed we generate a random UUID, and pass it via $container_uuid. In effect this means that /etc/machine-id + * in the container and our idea of the container UUID will always be in sync (at least if PID 1 in the + * container behaves nicely). */ + etc_machine_id = prefix_roota(directory, "/etc/machine-id"); r = id128_read(etc_machine_id, ID128_PLAIN, &id); - if (r < 0) - return r; - - if (sd_id128_is_null(id)) - return -EINVAL; - - *ret = id; - return 0; -} - -static int setup_machine_id(const char *directory) { - int r; + if (r < 0) { + if (!IN_SET(r, -ENOENT, -ENOMEDIUM)) /* If the file is missing or empty, we don't mind */ + return log_error_errno(r, "Failed to read machine ID from container image: %m"); - /* Try to set up the machine ID, if it isn't set up yet. Use a transient one, if necessary. Use the the UUID we - * were configured for if possible for initialization. */ - r = machine_id_setup(directory, arg_uuid); - if (r < 0) - return log_error_errno(r, "Failed to setup machine ID: %m"); + if (sd_id128_is_null(arg_uuid)) { + r = sd_id128_randomize(&arg_uuid); + if (r < 0) + return log_error_errno(r, "Failed to acquire randomized machine UUID: %m"); + } + } else { + if (sd_id128_is_null(id)) { + log_error("Machine ID in container image is zero, refusing."); + return -EINVAL; + } - /* Read back what was actually set. */ - r = machine_id_read(directory, &arg_uuid); - if (r < 0) - return log_error_errno(r, "Failed to read machine ID: %m"); + arg_uuid = id; + } return 0; } -- cgit v1.2.3-54-g00ecf From 15b1248a6b63448c2081fb2ed433f83b32febe47 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 19:12:50 +0200 Subject: machine-id-setup: port machine_id_commit() to new id128-util.c APIs --- src/core/machine-id-setup.c | 24 +++++++++++------------- src/libsystemd/sd-id128/id128-util.c | 19 +++++++++++++++---- src/libsystemd/sd-id128/id128-util.h | 4 ++-- src/nspawn/nspawn.c | 2 +- 4 files changed, 29 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 62f80833dd..423d4ff69d 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -295,9 +295,13 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { int machine_id_commit(const char *root) { _cleanup_close_ int fd = -1, initial_mntns_fd = -1; const char *etc_machine_id; - char id[34]; /* 32 + \n + \0 */ + sd_id128_t id; int r; + /* Replaces a tmpfs bind mount of /etc/machine-id by a proper file, atomically. For this, the umount is removed + * in a mount namespace, a new file is created at the right place. Afterwards the mount is also removed in the + * original mount namespace, thus revealing the file that was just created. */ + etc_machine_id = prefix_roota(root, "/etc/machine-id"); r = path_is_mount_point(etc_machine_id, 0); @@ -313,10 +317,6 @@ int machine_id_commit(const char *root) { if (fd < 0) return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id); - r = read_machine_id(fd, id); - if (r < 0) - return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id); - r = fd_is_temporary_fs(fd); if (r < 0) return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id); @@ -325,6 +325,10 @@ int machine_id_commit(const char *root) { return -EROFS; } + r = id128_read_fd(fd, ID128_PLAIN, &id); + if (r < 0) + return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id); + fd = safe_close(fd); /* Store current mount namespace */ @@ -343,15 +347,9 @@ int machine_id_commit(const char *root) { return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id); /* Update a persistent version of etc_machine_id */ - fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); - if (fd < 0) - return log_error_errno(errno, "Cannot open for writing %s. This is mandatory to get a persistent machine-id: %m", etc_machine_id); - - r = write_machine_id(fd, id); + r = id128_write(etc_machine_id, ID128_PLAIN, id, true); if (r < 0) - return log_error_errno(r, "Cannot write %s: %m", etc_machine_id); - - fd = safe_close(fd); + return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id); /* Return to initial namespace and proceed a lazy tmpfs unmount */ r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1); diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c index c1742cab0e..aaac838b59 100644 --- a/src/libsystemd/sd-id128/id128-util.c +++ b/src/libsystemd/sd-id128/id128-util.c @@ -18,6 +18,7 @@ ***/ #include +#include #include "fd-util.h" #include "hexdecoct.h" @@ -140,9 +141,10 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) { return id128_read_fd(fd, f, ret); } -int id128_write_fd(int fd, Id128Format f, sd_id128_t id) { +int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) { char buffer[36 + 2]; size_t sz; + int r; assert(fd >= 0); assert(f < _ID128_FORMAT_MAX); @@ -157,15 +159,24 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id) { sz = 37; } - return loop_write(fd, buffer, sz, false); + r = loop_write(fd, buffer, sz, false); + if (r < 0) + return r; + + if (do_sync) { + if (fsync(fd) < 0) + return -errno; + } + + return r; } -int id128_write(const char *p, Id128Format f, sd_id128_t id) { +int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { _cleanup_close_ int fd = -1; fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); if (fd < 0) return -errno; - return id128_write_fd(fd, f, id); + return id128_write_fd(fd, f, id, do_sync); } diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h index 73e4c710c4..3ba59acbca 100644 --- a/src/libsystemd/sd-id128/id128-util.h +++ b/src/libsystemd/sd-id128/id128-util.h @@ -41,5 +41,5 @@ typedef enum Id128Format { int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret); int id128_read(const char *p, Id128Format f, sd_id128_t *ret); -int id128_write_fd(int fd, Id128Format f, sd_id128_t id); -int id128_write(const char *p, Id128Format f, sd_id128_t id); +int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); +int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4c1d79418d..da8bee3244 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1287,7 +1287,7 @@ static int setup_boot_id(const char *dest) { if (r < 0) return log_error_errno(r, "Failed to generate random boot id: %m"); - r = id128_write(from, ID128_UUID, rnd); + r = id128_write(from, ID128_UUID, rnd, false); if (r < 0) return log_error_errno(r, "Failed to write boot id: %m"); -- cgit v1.2.3-54-g00ecf From e042eab7200b0c96c19f80100e3624bdba653a92 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 20:22:42 +0200 Subject: main: make sure set_machine_id() doesn't clobber arg_machine_id on failure --- src/core/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index fc04fb8051..fa02455c4a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -291,14 +291,16 @@ static int parse_crash_chvt(const char *value) { } static int set_machine_id(const char *m) { + sd_id128_t t; assert(m); - if (sd_id128_from_string(m, &arg_machine_id) < 0) + if (sd_id128_from_string(m, &t) < 0) return -EINVAL; - if (sd_id128_is_null(arg_machine_id)) + if (sd_id128_is_null(t)) return -EINVAL; + arg_machine_id = t; return 0; } -- cgit v1.2.3-54-g00ecf From 9ca8d43479dc198e8d6fc86492aa6576f97bbfc2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 20:23:51 +0200 Subject: sd-id128: handle NULL return parameter in sd_id128_from_string() nicer If the return parameter is NULL, simply validate the string, and return no error. --- man/sd_id128_to_string.xml | 12 +++++------- src/libsystemd/sd-id128/sd-id128.c | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/man/sd_id128_to_string.xml b/man/sd_id128_to_string.xml index e70c80892e..927d1ad5f2 100644 --- a/man/sd_id128_to_string.xml +++ b/man/sd_id128_to_string.xml @@ -74,13 +74,11 @@ lowercase hexadecimal digits and be terminated by a NUL byte. - sd_id128_from_string() implements the - reverse operation: it takes a 33 character string with 32 - hexadecimal digits (either lowercase or uppercase, terminated by - NUL) and parses them back into a 128-bit ID - returned in ret. Alternatively, this call - can also parse a 37-character string with a 128-bit ID formatted - as RFC UUID. + sd_id128_from_string() implements the reverse operation: it takes a 33 character string + with 32 hexadecimal digits (either lowercase or uppercase, terminated by NUL) and parses them + back into a 128-bit ID returned in ret. Alternatively, this call can also parse a + 37-character string with a 128-bit ID formatted as RFC UUID. If ret is passed as NULL the + function will validate the passed ID string, but not actually return it in parsed form. For more information about the sd_id128_t type see diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 1470e4c01a..9f47d04e61 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -52,7 +52,6 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { bool is_guid = false; assert_return(s, -EINVAL); - assert_return(ret, -EINVAL); for (n = 0, i = 0; n < 16;) { int a, b; @@ -90,7 +89,8 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { if (s[i] != 0) return -EINVAL; - *ret = t; + if (ret) + *ret = t; return 0; } -- cgit v1.2.3-54-g00ecf From 4b1afed01f092a2c6903b69205ca2ba99ead0d1d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 12:12:27 +0200 Subject: core: rework machine-id-setup.c to use the calls from id128-util.[ch] This allows us to delete quite a bit of code and make the whole thing a lot shorter. --- src/core/machine-id-setup.c | 199 +++++++-------------------- src/core/machine-id-setup.h | 2 +- src/core/main.c | 2 +- src/machine-id-setup/machine-id-setup-main.c | 2 +- 4 files changed, 50 insertions(+), 155 deletions(-) (limited to 'src') diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 423d4ff69d..76dfcfa6d7 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -17,11 +17,8 @@ along with systemd; If not, see . ***/ -#include #include #include -#include -#include #include #include @@ -29,11 +26,8 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" -#include "hexdecoct.h" #include "id128-util.h" -#include "io-util.h" #include "log.h" #include "machine-id-setup.h" #include "macro.h" @@ -47,101 +41,23 @@ #include "util.h" #include "virt.h" -static int shorten_uuid(char destination[34], const char source[36]) { - unsigned i, j; - - assert(destination); - assert(source); - - /* Converts a UUID into a machine ID, by lowercasing it and - * removing dashes. Validates everything. */ - - for (i = 0, j = 0; i < 36 && j < 32; i++) { - int t; - - t = unhexchar(source[i]); - if (t < 0) - continue; - - destination[j++] = hexchar(t); - } - - if (i != 36 || j != 32) - return -EINVAL; - - destination[32] = '\n'; - destination[33] = 0; - return 0; -} - -static int read_machine_id(int fd, char id[34]) { - char id_to_validate[34]; - int r; - - assert(fd >= 0); - assert(id); - - /* Reads a machine ID from a file, validates it, and returns - * it. The returned ID ends in a newline. */ - - r = loop_read_exact(fd, id_to_validate, 33, false); - if (r < 0) - return r; - - if (id_to_validate[32] != '\n') - return -EINVAL; - - id_to_validate[32] = 0; - - if (!id128_is_valid(id_to_validate)) - return -EINVAL; - - memcpy(id, id_to_validate, 32); - id[32] = '\n'; - id[33] = 0; - return 0; -} - -static int write_machine_id(int fd, const char id[34]) { - int r; - - assert(fd >= 0); - assert(id); - - if (lseek(fd, 0, SEEK_SET) < 0) - return -errno; - - r = loop_write(fd, id, 33, false); - if (r < 0) - return r; - - if (fsync(fd) < 0) - return -errno; - - return 0; -} - -static int generate_machine_id(char id[34], const char *root) { - int fd, r; - unsigned char *p; - sd_id128_t buf; - char *q; +static int generate_machine_id(const char *root, sd_id128_t *ret) { const char *dbus_machine_id; + _cleanup_close_ int fd = -1; + int r; - assert(id); - - dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id"); + assert(ret); /* First, try reading the D-Bus machine id, unless it is a symlink */ + dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id"); fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd >= 0) { - r = read_machine_id(fd, id); - safe_close(fd); - - if (r >= 0) { + if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) { log_info("Initializing machine ID from D-Bus machine ID."); return 0; } + + fd = safe_close(fd); } if (isempty(root)) { @@ -152,13 +68,10 @@ static int generate_machine_id(char id[34], const char *root) { if (detect_container() > 0) { _cleanup_free_ char *e = NULL; - r = getenv_for_pid(1, "container_uuid", &e); - if (r > 0) { - r = shorten_uuid(id, e); - if (r >= 0) { - log_info("Initializing machine ID from container UUID."); - return 0; - } + if (getenv_for_pid(1, "container_uuid", &e) > 0 && + sd_id128_from_string(e, ret) >= 0) { + log_info("Initializing machine ID from container UUID."); + return 0; } } else if (detect_vm() == VIRTUALIZATION_KVM) { @@ -167,51 +80,29 @@ static int generate_machine_id(char id[34], const char *root) { * running in qemu/kvm and a machine ID was passed in * via -uuid on the qemu/kvm command line */ - char uuid[36]; - - fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd >= 0) { - r = loop_read_exact(fd, uuid, 36, false); - safe_close(fd); - - if (r >= 0) { - r = shorten_uuid(id, uuid); - if (r >= 0) { - log_info("Initializing machine ID from KVM UUID."); - return 0; - } - } + if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) { + log_info("Initializing machine ID from KVM UUID."); + return 0; } } } /* If that didn't work, generate a random machine id */ - r = sd_id128_randomize(&buf); + r = sd_id128_randomize(ret); if (r < 0) - return log_error_errno(r, "Failed to open /dev/urandom: %m"); - - for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) { - q[0] = hexchar(*p >> 4); - q[1] = hexchar(*p & 15); - } - - id[32] = '\n'; - id[33] = 0; + return log_error_errno(r, "Failed to generate randomized : %m"); log_info("Initializing machine ID from random generator."); - return 0; } -int machine_id_setup(const char *root, sd_id128_t machine_id) { +int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) { const char *etc_machine_id, *run_machine_id; _cleanup_close_ int fd = -1; - bool writable = true; - char id[34]; /* 32 + \n + \0 */ + bool writable; int r; etc_machine_id = prefix_roota(root, "/etc/machine-id"); - run_machine_id = prefix_roota(root, "/run/machine-id"); RUN_WITH_UMASK(0000) { /* We create this 0444, to indicate that this isn't really @@ -219,7 +110,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { * will be owned by root it doesn't matter much, but maybe * people look. */ - mkdir_parents(etc_machine_id, 0755); + (void) mkdir_parents(etc_machine_id, 0755); fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); if (fd < 0) { int old_errno = errno; @@ -240,41 +131,41 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { } writable = false; - } + } else + writable = true; } - /* A machine id argument overrides all other machined-ids */ - if (!sd_id128_is_null(machine_id)) { - sd_id128_to_string(machine_id, id); - id[32] = '\n'; - id[33] = 0; - } else { - if (read_machine_id(fd, id) >= 0) - return 0; + /* A we got a valid machine ID argument, that's what counts */ + if (sd_id128_is_null(machine_id)) { - /* Hmm, so, the id currently stored is not useful, then let's - * generate one */ + /* Try to read any existing machine ID */ + if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) + return 0; - r = generate_machine_id(id, root); + /* Hmm, so, the id currently stored is not useful, then let's generate one */ + r = generate_machine_id(root, &machine_id); if (r < 0) return r; + + if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + return log_error_errno(errno, "Failed to seek: %m"); } if (writable) - if (write_machine_id(fd, id) >= 0) - return 0; + if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0) + goto finish; fd = safe_close(fd); - /* Hmm, we couldn't write it? So let's write it to - * /run/machine-id as a replacement */ + /* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */ - RUN_WITH_UMASK(0022) { - r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE); - if (r < 0) { - (void) unlink(run_machine_id); - return log_error_errno(r, "Cannot write %s: %m", run_machine_id); - } + run_machine_id = prefix_roota(root, "/run/machine-id"); + + RUN_WITH_UMASK(0022) + r = id128_write(run_machine_id, ID128_PLAIN, machine_id, false); + if (r < 0) { + (void) unlink(run_machine_id); + return log_error_errno(r, "Cannot write %s: %m", run_machine_id); } /* And now, let's mount it over */ @@ -287,7 +178,11 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { /* Mark the mount read-only */ if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0) - log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id); + log_warning_errno(errno, "Failed to make transient %s read-only, ignoring: %m", etc_machine_id); + +finish: + if (ret) + *ret = machine_id; return 0; } diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h index a7e7678ed9..29f4620646 100644 --- a/src/core/machine-id-setup.h +++ b/src/core/machine-id-setup.h @@ -20,4 +20,4 @@ ***/ int machine_id_commit(const char *root); -int machine_id_setup(const char *root, sd_id128_t machine_id); +int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret); diff --git a/src/core/main.c b/src/core/main.c index fa02455c4a..f49ba82156 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1719,7 +1719,7 @@ int main(int argc, char *argv[]) { status_welcome(); hostname_setup(); - machine_id_setup(NULL, arg_machine_id); + machine_id_setup(NULL, arg_machine_id, NULL); loopback_setup(); bump_unix_max_dgram_qlen(); diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index 1d55fa04af..b0199f181d 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) { if (arg_commit) r = machine_id_commit(arg_root); else - r = machine_id_setup(arg_root, SD_ID128_NULL); + r = machine_id_setup(arg_root, SD_ID128_NULL, NULL); finish: free(arg_root); -- cgit v1.2.3-54-g00ecf From 487ddeb8bc1a05816802adb2d5a9dc4416b386fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 12:21:21 +0200 Subject: machine-id-setup: add new --print switch If specified we'll simply output the used machine ID. --- man/systemd-machine-id-setup.xml | 6 ++++++ src/machine-id-setup/machine-id-setup-main.c | 30 +++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml index bfcd74f436..749987a937 100644 --- a/man/systemd-machine-id-setup.xml +++ b/man/systemd-machine-id-setup.xml @@ -151,6 +151,12 @@ early boot service. + + + + Print the machine ID generated or commited after the operation is complete. + + diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index b0199f181d..cc9b1b38fe 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -29,6 +29,7 @@ static char *arg_root = NULL; static bool arg_commit = false; +static bool arg_print = false; static void help(void) { printf("%s [OPTIONS...]\n\n" @@ -37,6 +38,7 @@ static void help(void) { " --version Show package version\n" " --root=ROOT Filesystem root\n" " --commit Commit transient ID\n" + " --print Print used machine ID\n" , program_invocation_short_name); } @@ -46,6 +48,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_ROOT, ARG_COMMIT, + ARG_PRINT, }; static const struct option options[] = { @@ -53,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "root", required_argument, NULL, ARG_ROOT }, { "commit", no_argument, NULL, ARG_COMMIT }, + { "print", no_argument, NULL, ARG_PRINT }, {} }; @@ -82,6 +86,10 @@ static int parse_argv(int argc, char *argv[]) { arg_commit = true; break; + case ARG_PRINT: + arg_print = true; + break; + case '?': return -EINVAL; @@ -98,6 +106,8 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { + char buf[SD_ID128_STRING_MAX]; + sd_id128_t id; int r; log_parse_environment(); @@ -107,10 +117,24 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - if (arg_commit) + if (arg_commit) { r = machine_id_commit(arg_root); - else - r = machine_id_setup(arg_root, SD_ID128_NULL, NULL); + if (r < 0) + goto finish; + + r = sd_id128_get_machine(&id); + if (r < 0) { + log_error_errno(r, "Failed to read machine ID back: %m"); + goto finish; + } + } else { + r = machine_id_setup(arg_root, SD_ID128_NULL, &id); + if (r < 0) + goto finish; + } + + if (arg_print) + puts(sd_id128_to_string(id, buf)); finish: free(arg_root); -- cgit v1.2.3-54-g00ecf From 83f8e80857090f63cf6a02c54d381dad3c0fad55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 15:58:49 +0200 Subject: core: support percentage specifications on TasksMax= This adds support for a TasksMax=40% syntax for specifying values relative to the system's configured maximum number of processes. This is useful in order to neatly subdivide the available room for tasks within containers. --- man/systemd.resource-control.xml | 15 +++++------ src/basic/util.c | 55 ++++++++++++++++++++++++++++++++++++++++ src/basic/util.h | 3 +++ src/core/dbus-cgroup.c | 22 ++++++++++++++++ src/core/load-fragment.c | 15 ++++++++--- src/shared/bus-unit-util.c | 35 ++++++++++++++----------- src/test/test-util.c | 38 +++++++++++++++++++++++++++ 7 files changed, 156 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 7263c0b329..bf44a68345 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -327,15 +327,12 @@ TasksMax=N - Specify the maximum number of tasks that may be - created in the unit. This ensures that the number of tasks - accounted for the unit (see above) stays below a specific - limit. If assigned the special value - infinity, no tasks limit is applied. This - controls the pids.max control group - attribute. For details about this control group attribute, - see pids.txt. + Specify the maximum number of tasks that may be created in the unit. This ensures that the number of + tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number + of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the + system. If assigned the special value infinity, no tasks limit is applied. This controls + the pids.max control group attribute. For details about this control group attribute, see + pids.txt. Implies TasksAccounting=true. The system default for this setting may be controlled with diff --git a/src/basic/util.c b/src/basic/util.c index 09d16697b7..c4b6fc2925 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -832,6 +832,61 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) { return r; } +uint64_t system_tasks_max(void) { + +#if SIZEOF_PID_T == 4 +#define TASKS_MAX ((uint64_t) (INT32_MAX-1)) +#elif SIZEOF_PID_T == 2 +#define TASKS_MAX ((uint64_t) (INT16_MAX-1)) +#else +#error "Unknown pid_t size" +#endif + + _cleanup_free_ char *value = NULL, *root = NULL; + uint64_t a = TASKS_MAX, b = TASKS_MAX; + + /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this + * limit: + * + * a) the maximum value for the pid_t type + * b) the cgroups pids_max attribute for the system + * c) the kernel's configure maximum PID value + * + * And then pick the smallest of the three */ + + if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0) + (void) safe_atou64(value, &a); + + if (cg_get_root_path(&root) >= 0) { + value = mfree(value); + + if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) + (void) safe_atou64(value, &b); + } + + return MIN3(TASKS_MAX, + a <= 0 ? TASKS_MAX : a, + b <= 0 ? TASKS_MAX : b); +} + +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { + uint64_t t, m; + + assert(max > 0); + + /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages + * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ + + t = system_tasks_max(); + assert(t > 0); + + m = t * v; + if (m / t != v) /* overflow? */ + return UINT64_MAX; + + return m / max; +} + int update_reboot_parameter_and_warn(const char *param) { int r; diff --git a/src/basic/util.h b/src/basic/util.h index db105197e8..8500c3077c 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -186,6 +186,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int uint64_t physical_memory(void); uint64_t physical_memory_scale(uint64_t v, uint64_t max); +uint64_t system_tasks_max(void); +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); + int update_reboot_parameter_and_warn(const char *param); int version(void); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 6167ce92cd..b3e2830c11 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -1060,6 +1060,8 @@ int bus_cgroup_set_property( r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (limit <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { c->tasks_max = limit; @@ -1071,6 +1073,26 @@ int bus_cgroup_set_property( unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); } + return 1; + } else if (streq(name, "TasksMaxScale")) { + uint64_t limit; + uint32_t raw; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + limit = system_tasks_max_scale(raw, UINT32_MAX); + if (limit <= 0 || limit >= UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + c->tasks_max = limit; + unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); + unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%", + (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); + } + return 1; } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 782e420e4c..cd7bf9c707 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2861,9 +2861,18 @@ int config_parse_tasks_max( return 0; } - r = safe_atou64(rvalue, &u); - if (r < 0 || u < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + r = parse_percent(rvalue); + if (r < 0) { + r = safe_atou64(rvalue, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + return 0; + } + } else + u = system_tasks_max_scale(r, 100U); + + if (u <= 0 || u >= UINT64_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue); return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 94ffa8af87..e63e9195f1 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -148,6 +148,26 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", field, "t", bytes); goto finish; + } else if (streq(field, "TasksMax")) { + uint64_t t; + + if (isempty(eq) || streq(eq, "infinity")) + t = (uint64_t) -1; + else { + r = parse_percent(eq); + if (r >= 0) { + r = sd_bus_message_append(m, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); + goto finish; + } else { + r = safe_atou64(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment); + } + + } + + r = sd_bus_message_append(m, "sv", "TasksMax", "t", t); + goto finish; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -191,21 +211,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (streq(field, "TasksMax")) { - uint64_t n; - - if (isempty(eq) || streq(eq, "infinity")) - n = (uint64_t) -1; - else { - r = safe_atou64(eq, &n); - if (r < 0) { - log_error("Failed to parse maximum tasks specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", n); - } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { uint64_t u; diff --git a/src/test/test-util.c b/src/test/test-util.c index e177612a9f..1b5cba86c1 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -308,7 +308,43 @@ static void test_physical_memory_scale(void) { /* overflow */ assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); +} + +static void test_system_tasks_max(void) { + uint64_t t; + + t = system_tasks_max(); + assert_se(t > 0); + assert_se(t < UINT64_MAX); + + log_info("Max tasks: %" PRIu64, t); +} + +static void test_system_tasks_max_scale(void) { + uint64_t t; + + t = system_tasks_max(); + + assert_se(system_tasks_max_scale(0, 100) == 0); + assert_se(system_tasks_max_scale(100, 100) == t); + + assert_se(system_tasks_max_scale(0, 1) == 0); + assert_se(system_tasks_max_scale(1, 1) == t); + assert_se(system_tasks_max_scale(2, 1) == 2*t); + + assert_se(system_tasks_max_scale(0, 2) == 0); + assert_se(system_tasks_max_scale(1, 2) == t/2); + assert_se(system_tasks_max_scale(2, 2) == t); + assert_se(system_tasks_max_scale(3, 2) == (3*t)/2); + assert_se(system_tasks_max_scale(4, 2) == t*2); + + assert_se(system_tasks_max_scale(0, UINT32_MAX) == 0); + assert_se(system_tasks_max_scale((UINT32_MAX-1)/2, UINT32_MAX-1) == t/2); + assert_se(system_tasks_max_scale(UINT32_MAX, UINT32_MAX) == t); + + /* overflow */ + assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } int main(int argc, char *argv[]) { @@ -327,6 +363,8 @@ int main(int argc, char *argv[]) { test_raw_clone(); test_physical_memory(); test_physical_memory_scale(); + test_system_tasks_max(); + test_system_tasks_max_scale(); return 0; } -- cgit v1.2.3-54-g00ecf From f7903e8db673505328ba904f050f5ec52cf79c23 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 16:10:15 +0200 Subject: core: rename MemoryLimitByPhysicalMemory transient property to MemoryLimitScale That way, we can neatly keep this in line with the new TasksMaxScale= option. Note that we didn't release a version with MemoryLimitByPhysicalMemory= yet, hence this change should be unproblematic without breaking API. --- src/core/dbus-cgroup.c | 12 +++++++----- src/shared/bus-unit-util.c | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index b3e2830c11..85b0c86a2f 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -856,7 +856,7 @@ int bus_cgroup_set_property( return 1; - } else if (STR_IN_SET(name, "MemoryLowByPhysicalMemory", "MemoryHighByPhysicalMemory", "MemoryMaxByPhysicalMemory")) { + } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale")) { uint32_t raw; uint64_t v; @@ -872,7 +872,7 @@ int bus_cgroup_set_property( const char *e; /* Chop off suffix */ - assert_se(e = endswith(name, "ByPhysicalMemory")); + assert_se(e = endswith(name, "Scale")); name = strndupa(name, e - name); if (streq(name, "MemoryLow")) @@ -883,7 +883,8 @@ int bus_cgroup_set_property( c->memory_max = v; unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); - unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, + (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); } return 1; @@ -909,7 +910,7 @@ int bus_cgroup_set_property( return 1; - } else if (streq(name, "MemoryLimitByPhysicalMemory")) { + } else if (streq(name, "MemoryLimitScale")) { uint64_t limit; uint32_t raw; @@ -924,7 +925,8 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->memory_limit = limit; unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); - unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", + (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); } return 1; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index e63e9195f1..ea020b517b 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -132,10 +132,10 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen char *n; /* When this is a percentage we'll convert this into a relative value in the range - * 0…UINT32_MAX and pass it in the MemoryLowByPhysicalMemory property (and related + * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related * ones). This way the physical memory size can be determined server-side */ - n = strjoina(field, "ByPhysicalMemory"); + n = strjoina(field, "Scale"); r = sd_bus_message_append(m, "sv", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); goto finish; -- cgit v1.2.3-54-g00ecf From 84af7821b65ad11417ac2984717cf42a3655fcd7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 17:00:36 +0200 Subject: main: simplify things a bit by moving container check into fixup_environment() --- src/core/main.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index fc04fb8051..4c767a3c9d 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1298,6 +1298,11 @@ static int fixup_environment(void) { _cleanup_free_ char *term = NULL; int r; + /* We expect the environment to be set correctly + * if run inside a container. */ + if (detect_container() > 0) + return 0; + /* When started as PID1, the kernel uses /dev/console * for our stdios and uses TERM=linux whatever the * backend device used by the console. We try to make @@ -1314,7 +1319,7 @@ static int fixup_environment(void) { if (r == 0) { term = strdup(default_term_for_tty("/dev/console") + 5); if (!term) - return -errno; + return -ENOMEM; } if (setenv("TERM", term, 1) < 0) @@ -1508,13 +1513,10 @@ int main(int argc, char *argv[]) { } if (arg_system) { - /* We expect the environment to be set correctly - * if run inside a container. */ - if (detect_container() <= 0) - if (fixup_environment() < 0) { - error_message = "Failed to fix up PID1 environment"; - goto finish; - } + if (fixup_environment() < 0) { + error_message = "Failed to fix up PID1 environment"; + goto finish; + } /* Try to figure out if we can use colors with the console. No * need to do that for user instances since they never log -- cgit v1.2.3-54-g00ecf From c06eec15d5816236c11e35b35e444f62f37b6ef6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 17:19:58 +0200 Subject: logind: change TasksMax= value for user logins to 33% Let's change from a fixed value of 12288 tasks per user to a relative value of 33%, which with the kernel's default of 32768 translates to 10813. This is a slight decrease of the limit, for no other reason than "33%" sounding like a nice round number that is close enough to 12288 (which would translate to 37.5%). (Well, it also has the nice effect of still leaving a bit of room in the PID space if there are 3 cooperating evil users that try to consume all PIDs... Also, I like my bikesheds blue). Since the new value is taken relative, and machined's TasksMax= setting defaults to 16384, 33% inside of containers is usually equivalent to 5406, which should still be ample space. To summarize: | on the host | in the container old default | 12288 | 12288 new default | 10813 | 5406 --- man/logind.conf.xml | 9 ++++----- src/login/logind-gperf.gperf | 2 +- src/login/logind-user.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/login/logind.c | 2 +- src/login/logind.conf.in | 2 +- src/login/logind.h | 1 + 6 files changed, 53 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index fe92277a1f..adba5a4131 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -315,12 +315,11 @@ UserTasksMax= - Sets the maximum number of OS tasks each user - may run concurrently. This controls the - TasksMax= setting of the per-user slice - unit, see + Sets the maximum number of OS tasks each user may run concurrently. This controls the + TasksMax= setting of the per-user slice unit, see systemd.resource-control5 - for details. Defaults to 12288 (12K). + for details. Defaults to 33%, which equals 10813 with the kernel's defaults on the host, but might be smaller + in OS containers. diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 6bd08adc05..0b6a5f3cf4 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -36,4 +36,4 @@ Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manag Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) -Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) +Login.UserTasksMax, config_parse_user_tasks_max,0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index de44d369cf..f7d83909a0 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -870,3 +870,48 @@ int config_parse_tmpfs_size( return 0; } + +int config_parse_user_tasks_max( + 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) { + + uint64_t *m = data; + uint64_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* First, try to parse as percentage */ + r = parse_percent(rvalue); + if (r > 0 && r < 100) + k = system_tasks_max_scale(r, 100U); + else { + + /* If the passed argument was not a percentage, or out of range, parse as byte size */ + + r = safe_atou64(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse tasks maximum, ignoring: %s", rvalue); + return 0; + } + } + + if (k <= 0 || k >= UINT64_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Tasks maximum out of range, ignoring: %s", rvalue); + return 0; + } + + *m = k; + return 0; +} diff --git a/src/login/logind.c b/src/login/logind.c index d01dd110ea..5ce36d28c7 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -62,7 +62,7 @@ static void manager_reset_config(Manager *m) { m->idle_action = HANDLE_IGNORE; m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */ - m->user_tasks_max = 12288; + m->user_tasks_max = system_tasks_max_scale(33U, 100U); /* 33% */ m->sessions_max = 8192; m->inhibitors_max = 8192; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 32c0844cb6..6f720b7708 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -34,4 +34,4 @@ #RemoveIPC=yes #InhibitorsMax=8192 #SessionsMax=8192 -#UserTasksMax=12288 +#UserTasksMax=33% diff --git a/src/login/logind.h b/src/login/logind.h index 90431eb4b0..086fa1eeb5 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -187,6 +187,7 @@ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned lengt int manager_set_lid_switch_ignore(Manager *m, usec_t until); int config_parse_tmpfs_size(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_user_tasks_max(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 manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret); int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret); -- cgit v1.2.3-54-g00ecf From 79baeeb96d58676853521e10a358e85d83dac7f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 17:29:00 +0200 Subject: core: change TasksMax= default for system services to 15% As it turns out 512 is max number of tasks per service is hit by too many applications, hence let's bump it a bit, and make it relative to the system's maximum number of PIDs. With this change the new default is 15%. At the kernel's default pids_max value of 32768 this translates to 4915. At machined's default TasksMax= setting of 16384 this translates to 2457. Why 15%? Because it sounds like a round number and is close enough to 4096 which I was going for, i.e. an eight-fold increase over the old 512 Summary: | on the host | in a container old default | 512 | 512 new default | 4915 | 2457 --- man/systemd-system.conf.xml | 9 ++++----- src/core/main.c | 4 +++- src/core/manager.c | 2 +- src/core/system.conf | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 8833e73c72..1bb40fd234 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -325,12 +325,11 @@ DefaultTasksMax= - Configure the default value for the per-unit - TasksMax= setting. See + Configure the default value for the per-unit TasksMax= setting. See systemd.resource-control5 - for details. This setting applies to all unit types that - support resource control settings, with the exception of slice - units. Defaults to 512. + for details. This setting applies to all unit types that support resource control settings, with the exception + of slice units. Defaults to 15%, which equals 4915 with the kernel's defaults on the host, but might be smaller + in OS containers. diff --git a/src/core/main.c b/src/core/main.c index 4c767a3c9d..c59228ad53 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -127,7 +127,7 @@ static bool arg_default_io_accounting = false; static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = true; -static uint64_t arg_default_tasks_max = UINT64_C(512); +static uint64_t arg_default_tasks_max = UINT64_MAX; static sd_id128_t arg_machine_id = {}; noreturn static void freeze_or_reboot(void) { @@ -1558,6 +1558,8 @@ int main(int argc, char *argv[]) { (void) reset_all_signal_handlers(); (void) ignore_signals(SIGNALS_IGNORE, -1); + arg_default_tasks_max = system_tasks_max_scale(15U, 100U); /* 15% the system PIDs equals 4915 by default. */ + if (parse_config_file() < 0) { error_message = "Failed to parse config file"; goto finish; diff --git a/src/core/manager.c b/src/core/manager.c index a0181e2138..4d84a0b37e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -569,7 +569,7 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { m->exit_code = _MANAGER_EXIT_CODE_INVALID; m->default_timer_accuracy_usec = USEC_PER_MINUTE; m->default_tasks_accounting = true; - m->default_tasks_max = UINT64_C(512); + m->default_tasks_max = UINT64_MAX; #ifdef ENABLE_EFI if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) diff --git a/src/core/system.conf b/src/core/system.conf index db8b7acd78..c6bb050aac 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -42,7 +42,7 @@ #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no #DefaultTasksAccounting=yes -#DefaultTasksMax=512 +#DefaultTasksMax=15% #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= -- cgit v1.2.3-54-g00ecf From 2424b6bd716f0c1c3bf3406b1fd1a16ba1b6a556 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 22 Jul 2016 15:33:13 +0200 Subject: macros.systemd.in: add %systemd_ordering (#3776) To remove the hard dependency on systemd, for packages, which function without a running systemd the %systemd_ordering macro can be used to ensure ordering in the rpm transaction. %systemd_ordering makes sure, the systemd rpm is installed prior to the package, so the %pre/%post scripts can execute the systemd parts. Installing systemd afterwards though, does not result in the same outcome. --- src/core/macros.systemd.in | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in index 028db1cc4a..6e8a3b3e3d 100644 --- a/src/core/macros.systemd.in +++ b/src/core/macros.systemd.in @@ -38,6 +38,12 @@ Requires(preun): systemd \ Requires(postun): systemd \ %{nil} +%systemd_ordering \ +OrderWithRequires(post): systemd \ +OrderWithRequires(preun): systemd \ +OrderWithRequires(postun): systemd \ +%{nil} + %systemd_post() \ if [ $1 -eq 1 ] ; then \ # Initial installation \ -- cgit v1.2.3-54-g00ecf From b3785cd5e6a0ac4d465713db221e1a150aabd5f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 15:30:23 +0200 Subject: core: check for overflow when handling scaled MemoryLimit= settings Just in case... --- src/core/load-fragment.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cd7bf9c707..ae306de4ae 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2823,8 +2823,8 @@ int config_parse_memory_limit( } else bytes = physical_memory_scale(r, 100U); - if (bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue); + if (bytes <= 0 || bytes >= UINT64_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue); return 0; } } -- cgit v1.2.3-54-g00ecf From b3d1d51603408e7aea7971fabf41b38c9e12fd69 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 22 Jul 2016 15:59:14 +0200 Subject: namespace: ensure to return a valid inaccessible nodes (#3778) Because /run/systemd/inaccessible/{chr,blk} are devices with major=0 and minor=0 it might be possible that these devices cannot be created so we use /run/systemd/inaccessible/sock instead to map them. --- src/basic/mount-util.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 63dff3dd5c..b91f0f9e0e 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -534,15 +534,22 @@ int repeat_unmount(const char *path, int flags) { } const char* mode_to_inaccessible_node(mode_t mode) { + /* This function maps a node type to the correspondent inaccessible node type. + * Character and block inaccessible devices may not be created (because major=0 and minor=0), + * in such case we map character and block devices to the inaccessible node type socket. */ switch(mode & S_IFMT) { case S_IFREG: return "/run/systemd/inaccessible/reg"; case S_IFDIR: return "/run/systemd/inaccessible/dir"; case S_IFCHR: - return "/run/systemd/inaccessible/chr"; + if (access("/run/systemd/inaccessible/chr", F_OK) == 0) + return "/run/systemd/inaccessible/chr"; + return "/run/systemd/inaccessible/sock"; case S_IFBLK: - return "/run/systemd/inaccessible/blk"; + if (access("/run/systemd/inaccessible/blk", F_OK) == 0) + return "/run/systemd/inaccessible/blk"; + return "/run/systemd/inaccessible/sock"; case S_IFIFO: return "/run/systemd/inaccessible/fifo"; case S_IFSOCK: -- cgit v1.2.3-54-g00ecf From 54cd6556b32217b337d44c5072d2c2a1ccffd9a4 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 22 Jul 2016 11:58:03 +0200 Subject: nspawn: set DevicesPolicy closed and clean up duplicated devices --- src/nspawn/nspawn-register.c | 17 +++-------------- units/systemd-nspawn@.service.in | 11 +---------- 2 files changed, 4 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 7fd711b8a4..e5b76a0c5d 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -104,7 +104,7 @@ int register_machine( return bus_log_create_error(r); } - r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict"); + r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed"); if (r < 0) return bus_log_create_error(r); @@ -112,31 +112,20 @@ int register_machine( * systemd-nspawn@.service, to keep the device * policies in sync regardless if we are run with or * without the --keep-unit switch. */ - r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 11, + r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2, /* Allow the container to * access and create the API * device nodes, so that * PrivateDevices= in the * container can work * fine */ - "/dev/null", "rwm", - "/dev/zero", "rwm", - "/dev/full", "rwm", - "/dev/random", "rwm", - "/dev/urandom", "rwm", - "/dev/tty", "rwm", "/dev/net/tun", "rwm", /* Allow the container * access to ptys. However, * do not permit the * container to ever create * these device nodes. */ - "/dev/pts/ptmx", "rw", - "char-pts", "rw", - /* Allow /run/systemd/inaccessible/{chr,blk} - * devices inside the container */ - "/run/systemd/inaccessible/chr", "rwm", - "/run/systemd/inaccessible/blk", "rwm"); + "char-pts", "rw"); if (r < 0) return bus_log_create_error(r); diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index 8f9cf9acfe..c8141639b6 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -25,18 +25,9 @@ TasksMax=16384 # Enforce a strict device policy, similar to the one nspawn configures # when it allocates its own scope unit. Make sure to keep these # policies in sync if you change them! -DevicePolicy=strict -DeviceAllow=/dev/null rwm -DeviceAllow=/dev/zero rwm -DeviceAllow=/dev/full rwm -DeviceAllow=/dev/random rwm -DeviceAllow=/dev/urandom rwm -DeviceAllow=/dev/tty rwm +DevicePolicy=closed DeviceAllow=/dev/net/tun rwm -DeviceAllow=/dev/pts/ptmx rw DeviceAllow=char-pts rw -DeviceAllow=/run/systemd/inaccessible/chr rwm -DeviceAllow=/run/systemd/inaccessible/blk rwm # nspawn itself needs access to /dev/loop-control and /dev/loop, to # implement the --image= option. Add these here, too. -- cgit v1.2.3-54-g00ecf From 0d9e799102674c50e0755686a6b93f933d9f49a3 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 22 Jul 2016 12:00:49 +0200 Subject: cgroup: whitelist inaccessible devices for "auto" and "closed" DevicePolicy. https://github.com/systemd/systemd/pull/3685 introduced /run/systemd/inaccessible/{chr,blk} to map inacessible devices, this patch allows systemd running inside a nspawn container to create /run/systemd/inaccessible/{chr,blk}. --- src/core/cgroup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 8b0f11ed50..c19e43f571 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -800,7 +800,10 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { "/dev/random\0" "rwm\0" "/dev/urandom\0" "rwm\0" "/dev/tty\0" "rwm\0" - "/dev/pts/ptmx\0" "rw\0"; /* /dev/pts/ptmx may not be duplicated, but accessed */ + "/dev/pts/ptmx\0" "rw\0" /* /dev/pts/ptmx may not be duplicated, but accessed */ + /* Allow /run/systemd/inaccessible/{chr,blk} devices for mapping InaccessiblePaths */ + "/run/systemd/inaccessible/chr\0" "rwm\0" + "/run/systemd/inaccessible/blk\0" "rwm\0"; const char *x, *y; -- cgit v1.2.3-54-g00ecf From e08ab37902bbd6e46ad1365f8ffa87fd700683e2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 17:39:21 +0200 Subject: systemctl: never check inhibitors if -H or -M are used (#3781) Don't check inhibitors when operating remotely. The interactivity inhibitors imply can#t be provided anyway, and the current code checks for local sessions directly, via various sd_session_xyz() APIs, hence bypass it entirely if we operate on remote systems. Fixes: #3476 --- src/systemctl/systemctl.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d3f437411a..1dbe35997a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3033,6 +3033,9 @@ static int logind_check_inhibitors(enum action a) { if (!on_tty()) return 0; + if (arg_transport != BUS_TRANSPORT_LOCAL) + return 0; + r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From fec603eb6cbba4ea03ef01e3ad48fa85a4812a9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 17:39:47 +0200 Subject: coredump: truncate overly long coredump metadata fields (#3780) Fixes: #3573 Replaces: #3588 --- src/coredump/coredump.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 82a54968e7..998b047c29 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -852,12 +852,42 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) return log_error_errno(errno, "Failed to connect to coredump service: %m"); for (i = 0; i < n_iovec; i++) { - ssize_t n; - assert(iovec[i].iov_len > 0); + struct msghdr mh = { + .msg_iov = (struct iovec*) iovec + i, + .msg_iovlen = 1, + }; + struct iovec copy[2]; + + for (;;) { + if (sendmsg(fd, &mh, MSG_NOSIGNAL) >= 0) + break; + + if (errno == EMSGSIZE && mh.msg_iov[0].iov_len > 0) { + /* This field didn't fit? That's a pity. Given that this is just metadata, + * let's truncate the field at half, and try again. We append three dots, in + * order to show that this is truncated. */ + + if (mh.msg_iov != copy) { + /* We don't want to modify the caller's iovec, hence let's create our + * own array, consisting of two new iovecs, where the first is a + * (truncated) copy of what we want to send, and the second one + * contains the trailing dots. */ + copy[0] = iovec[i]; + copy[1] = (struct iovec) { + .iov_base = (char[]) { '.', '.', '.' }, + .iov_len = 3, + }; + + mh.msg_iov = copy; + mh.msg_iovlen = 2; + } + + copy[0].iov_len /= 2; /* halve it, and try again */ + continue; + } - n = send(fd, iovec[i].iov_base, iovec[i].iov_len, MSG_NOSIGNAL); - if (n < 0) return log_error_errno(errno, "Failed to send coredump datagram: %m"); + } } r = send_one_fd(fd, input_fd, 0); -- cgit v1.2.3-54-g00ecf From 78f043f77b17299d3039e492e3661f4ca6d7f74e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 16:45:43 +0200 Subject: coredump: make sure to handle crashes of PID 1 and journald special Fixes: #3285 --- src/coredump/coredump.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 998b047c29..a75f364d2d 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -756,7 +756,6 @@ static int process_socket(int fd) { iovec[n_iovec].iov_len = l; iovec[n_iovec].iov_base = malloc(l + 1); - if (!iovec[n_iovec].iov_base) { r = log_oom(); goto finish; @@ -897,7 +896,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) return 0; } -static int process_journald_crash(const char *context[], int input_fd) { +static int process_special_crash(const char *context[], int input_fd) { _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1; _cleanup_free_ char *filename = NULL; uint64_t coredump_size; @@ -906,7 +905,7 @@ static int process_journald_crash(const char *context[], int input_fd) { assert(context); assert(input_fd >= 0); - /* If we are journald, we cut things short, don't write to the journal, but still create a coredump. */ + /* If we are pid1 or journald, we cut things short, don't write to the journal, but still create a coredump. */ if (arg_storage != COREDUMP_STORAGE_NONE) arg_storage = COREDUMP_STORAGE_EXTERNAL; @@ -919,7 +918,8 @@ static int process_journald_crash(const char *context[], int input_fd) { if (r < 0) return r; - log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); + log_notice("Detected coredump of the journal daemon or PID 1, diverted to %s.", filename); + return 0; } @@ -979,9 +979,11 @@ static int process_kernel(int argc, char* argv[]) { if (cg_pid_get_unit(pid, &t) >= 0) { - if (streq(t, SPECIAL_JOURNALD_SERVICE)) { + /* Let's avoid dead-locks when processing journald and init crashes, as socket activation and logging + * are unlikely to work then. */ + if (STR_IN_SET(t, SPECIAL_JOURNALD_SERVICE, SPECIAL_INIT_SCOPE)) { free(t); - return process_journald_crash(context, STDIN_FILENO); + return process_special_crash(context, STDIN_FILENO); } core_unit = strjoina("COREDUMP_UNIT=", t); -- cgit v1.2.3-54-g00ecf From 5157879b757bffce3da0a68ca207753569e8627d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 18:01:50 +0200 Subject: coredump: turn off coredump collection entirely after journald or PID 1 crashed Safe is safe, let's turn off the whole logic if we can, after all it is unlikely we'll be able to process further crashes in a reasonable way. --- src/coredump/coredump.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index a75f364d2d..e5719e67c3 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -920,6 +920,9 @@ static int process_special_crash(const char *context[], int input_fd) { log_notice("Detected coredump of the journal daemon or PID 1, diverted to %s.", filename); + log_notice("Due to the special circumstances, coredump collection will now be turned off."); + (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + return 0; } -- cgit v1.2.3-54-g00ecf From d710aaf7a5d74afb3135f2f79080bd4715790c59 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 22 Jul 2016 20:27:45 -0400 Subject: Use "return log_error_errno" in more places" --- src/coredump/coredump.c | 6 ++---- src/fstab-generator/fstab-generator.c | 26 ++++++++++++-------------- src/gpt-auto-generator/gpt-auto-generator.c | 6 ++---- src/login/logind-user.c | 3 +-- src/nspawn/nspawn-seccomp.c | 6 ++---- src/nspawn/nspawn-setuid.c | 7 ++----- src/shared/conf-parser.c | 3 +-- src/systemctl/systemctl.c | 6 ++---- src/tmpfiles/tmpfiles.c | 5 ++--- 9 files changed, 26 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index e5719e67c3..043d785dd4 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -157,10 +157,8 @@ static int fix_acl(int fd, uid_t uid) { if (acl_create_entry(&acl, &entry) < 0 || acl_set_tag_type(entry, ACL_USER) < 0 || - acl_set_qualifier(entry, &uid) < 0) { - log_error_errno(errno, "Failed to patch ACL: %m"); - return -errno; - } + acl_set_qualifier(entry, &uid) < 0) + return log_error_errno(errno, "Failed to patch ACL: %m"); if (acl_get_permset(entry, &permset) < 0 || acl_add_perm(permset, ACL_READ) < 0) diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 5aeca7e2d5..33af553d0d 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -85,13 +85,12 @@ static int add_swap( return log_oom(); f = fopen(unit, "wxe"); - if (!f) { - if (errno == EEXIST) - log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); - else - log_error_errno(errno, "Failed to create unit file %s: %m", unit); - return -errno; - } + if (!f) + return log_error_errno(errno, + errno == EEXIST ? + "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" : + "Failed to create unit file %s: %m", + unit); fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" @@ -281,13 +280,12 @@ static int add_mount( return log_oom(); f = fopen(unit, "wxe"); - if (!f) { - if (errno == EEXIST) - log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); - else - log_error_errno(errno, "Failed to create unit file %s: %m", unit); - return -errno; - } + if (!f) + return log_error_errno(errno, + errno == EEXIST ? + "Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?" : + "Failed to create unit file %s: %m", + unit); fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index a4938a7c3a..39355de953 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -489,10 +489,8 @@ static int add_boot(const char *what) { return 0; } - if (r < 0) { - log_error_errno(r, "Failed to read ESP partition UUID: %m"); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to read ESP partition UUID: %m"); errno = 0; b = blkid_new_probe_from_filename(what); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index f7d83909a0..348e396292 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -311,8 +311,7 @@ int user_load(User *u) { if (r == -ENOENT) return 0; - log_error_errno(r, "Failed to read %s: %m", u->state_file); - return r; + return log_error_errno(r, "Failed to read %s: %m", u->state_file); } if (display) diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 54db1b47f8..3ab7160ebe 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -119,10 +119,8 @@ static int seccomp_add_default_syscall_filter(scmp_filter_ctx ctx, r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0); if (r == -EFAULT) continue; /* unknown syscall */ - if (r < 0) { - log_error_errno(r, "Failed to block syscall: %m"); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to block syscall: %m"); } return 0; diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c index ee15a47e93..b8e8e091c8 100644 --- a/src/nspawn/nspawn-setuid.c +++ b/src/nspawn/nspawn-setuid.c @@ -124,14 +124,12 @@ int change_uid_gid(const char *user, char **_home) { fd = -1; if (!fgets(line, sizeof(line), f)) { - if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } - log_error_errno(errno, "Failed to read from getent: %m"); - return -errno; + return log_error_errno(errno, "Failed to read from getent: %m"); } truncate_nl(line); @@ -214,8 +212,7 @@ int change_uid_gid(const char *user, char **_home) { return -ESRCH; } - log_error_errno(errno, "Failed to read from getent: %m"); - return -errno; + return log_error_errno(errno, "Failed to read from getent: %m"); } truncate_nl(line); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index d85ab5441e..7cf222e4d2 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -323,8 +323,7 @@ int config_parse(const char *unit, if (feof(f)) break; - log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); - return -errno; + return log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); } l = buf; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 92ba6aa4e4..5298fcfb9c 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5537,10 +5537,8 @@ static int enable_sysv_units(const char *verb, char **args) { } j = wait_for_terminate(pid, &status); - if (j < 0) { - log_error_errno(j, "Failed to wait for child: %m"); - return j; - } + if (j < 0) + return log_error_errno(j, "Failed to wait for child: %m"); if (status.si_code == CLD_EXITED) { if (streq(verb, "is-enabled")) { diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index bfb6293b3d..954f4aa985 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1575,13 +1575,12 @@ static int clean_item_instance(Item *i, const char* instance) { d = opendir_nomod(instance); if (!d) { - if (errno == ENOENT || errno == ENOTDIR) { + if (IN_SET(errno, ENOENT, ENOTDIR)) { log_debug_errno(errno, "Directory \"%s\": %m", instance); return 0; } - log_error_errno(errno, "Failed to open directory %s: %m", instance); - return -errno; + return log_error_errno(errno, "Failed to open directory %s: %m", instance); } if (fstat(dirfd(d), &s) < 0) -- cgit v1.2.3-54-g00ecf From 92dfd88bc919e30d5b0c1c761ed87a63fcf94e79 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 22 Jul 2016 20:28:30 -0400 Subject: import: don't log "fake" errno values --- src/import/import.c | 4 ++-- src/import/pull.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/import/import.c b/src/import/import.c index 4e442ee84a..2b6ca24af8 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -90,7 +90,7 @@ static int import_tar(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); else if (r > 0) { - log_error_errno(EEXIST, "Image '%s' already exists.", local); + log_error("Image '%s' already exists.", local); return -EEXIST; } } @@ -185,7 +185,7 @@ static int import_raw(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); else if (r > 0) { - log_error_errno(EEXIST, "Image '%s' already exists.", local); + log_error("Image '%s' already exists.", local); return -EEXIST; } } diff --git a/src/import/pull.c b/src/import/pull.c index 72604a6a74..53b1211965 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -97,7 +97,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); else if (r > 0) { - log_error_errno(EEXIST, "Image '%s' already exists.", local); + log_error("Image '%s' already exists.", local); return -EEXIST; } } @@ -183,7 +183,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); else if (r > 0) { - log_error_errno(EEXIST, "Image '%s' already exists.", local); + log_error("Image '%s' already exists.", local); return -EEXIST; } } -- cgit v1.2.3-54-g00ecf From 476b8254d95488d09eebdbd175494aaafac23a3e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 22 Jul 2016 20:28:57 -0400 Subject: nspawn: don't skip cleanup on locking error --- src/nspawn/nspawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index da8bee3244..b1c012a9e4 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3553,7 +3553,7 @@ int main(int argc, char *argv[]) { } if (r < 0) { log_error_errno(r, "Failed to lock %s: %m", arg_directory); - return r; + goto finish; } if (arg_template) { -- cgit v1.2.3-54-g00ecf From 3990961df02a255cb75cc80445535d153fc7f165 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 15:10:15 +0200 Subject: man: update systemctl man page for unit file commands, in particular "systemctl enable" Clarify that "systemctl enable" can operate either on unit names or on unit file paths (also, adjust the --help text to clarify this). Say that "systemctl enable" on unit file paths also links the unit into the search path. Many other fixes. This should improve the documentation to avoid further confusion around #3706. --- man/systemctl.xml | 187 +++++++++++++++++++++------------------------- src/systemctl/systemctl.c | 2 +- 2 files changed, 88 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 742da81cfe..c7b830b7fb 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -973,70 +973,62 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service list-unit-files PATTERN... - List unit files installed in the file system and their enablement state - (as reported by is-enabled). If one or more - PATTERNs are specified, only units whose filename - (just the last component of the path) matches one of them are shown. + List unit files installed on the system, in combination with their enablement state (as reported by + is-enabled). If one or more PATTERNs are specified, only unit + files whose name matches one of them are shown (patterns matching unit file system paths are not + supported). enable NAME... + enable PATH... - Enable one or more unit files or unit file instances, - as specified on the command line. This will create a number - of symlinks as encoded in the [Install] - sections of the unit files. After the symlinks have been - created, the systemd configuration is reloaded (in a way that - is equivalent to daemon-reload) to ensure - the changes are taken into account immediately. Note that - this does not have the effect of also - starting any of the units being enabled. If this - is desired, either should be used - together with this command, or an additional start - command must be invoked for the unit. Also note that, in case of - instance enablement, symlinks named the same as instances - are created in the install location, however they all point to the - same template unit file. - - This command will print the actions executed. This - output may be suppressed by passing . + Enable one or more units or unit instances. This will create a set of symlinks, as encoded in the + [Install] sections of the indicated unit files. After the symlinks have been created, + the system manager configuration is reloaded (in a way equivalent to daemon-reload), in + order to ensure the changes are taken into account immediately. Note that this does + not have the effect of also starting any of the units being enabled. If this is + desired, combine this command with the switch, or invoke start + with appropriate arguments later. Note that in case of unit instance enablement (i.e. enablement of units of + the form foo@bar.service), symlinks named the same as instances are created in the + unit configuration diectory, however they point to the single template unit file they are instantiated + from. + + This command expects either valid unit names (in which case appropriate unit files for these names + are automatically searched in the various unit file directories), or absolute paths to unit files (in which + case these files are read directly). If a specified unit file is located outside of the unit file + directories searched automatically, an additional symlink is created, linking it into the unit + configuration path, thus ensuring it is automatically found when requested by commands such as + start. + + This command will print the file system operations executed. This output may be suppressed by passing + . - Note that this operation creates only the suggested - symlinks for the units. While this command is the - recommended way to manipulate the unit configuration - directory, the administrator is free to make additional - changes manually by placing or removing symlinks in the - directory. This is particularly useful to create - configurations that deviate from the suggested default - installation. In this case, the administrator must make sure - to invoke daemon-reload manually as - necessary to ensure the changes are taken into account. + Note that this operation creates only the symlinks suggested in the [Install] + section of the unit files. While this command is the recommended way to manipulate the unit configuration + directory, the administrator is free to make additional changes manually by placing or removing symlinks + below this directory. This is particularly useful to create configurations that deviate from the suggested + default installation. In this case, the administrator must make sure to invoke + daemon-reload manually as necessary, in order to ensure the changes are taken into + account. - Enabling units should not be confused with starting - (activating) units, as done by the start - command. Enabling and starting units is orthogonal: units - may be enabled without being started and started without - being enabled. Enabling simply hooks the unit into various - suggested places (for example, so that the unit is - automatically started on boot or when a particular kind of - hardware is plugged in). Starting actually spawns the daemon - process (in case of service units), or binds the socket (in - case of socket units), and so on. - - Depending on whether , - , , - or is specified, this enables the unit - for the system, for the calling user only, for only this boot of - the system, or for all future logins of all users, or only this - boot. Note that in the last case, no systemd daemon - configuration is reloaded. - - Using enable on masked units - results in an error. + Enabling units should not be confused with starting (activating) units, as done by the + start command. Enabling and starting units is orthogonal: units may be enabled without + being started and started without being enabled. Enabling simply hooks the unit into various suggested + places (for example, so that the unit is automatically started on boot or when a particular kind of + hardware is plugged in). Starting actually spawns the daemon process (in case of service units), or binds + the socket (in case of socket units), and so on. + + Depending on whether , , , + or is specified, this enables the unit for the system, for the calling user only, + for only this boot of the system, or for all future logins of all users, or only this boot. Note that in + the last case, no systemd daemon configuration is reloaded. + + Using enable on masked units is not supported and results in an error. @@ -1044,28 +1036,31 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service disable NAME... - Disables one or more units. This removes all symlinks - to the specified unit files from the unit configuration - directory, and hence undoes the changes made by - enable. Note however that this removes - all symlinks to the unit files (i.e. including manual - additions), not just those actually created by - enable. This call implicitly reloads the - systemd daemon configuration after completing the disabling - of the units. Note that this command does not implicitly - stop the units that are being disabled. If this is desired, either - should be used together with this command, or - an additional stop command should be executed - afterwards. - - This command will print the actions executed. This - output may be suppressed by passing . + Disables one or more units. This removes all symlinks to the unit files backing the specified units + from the unit configuration directory, and hence undoes any changes made by enable or + link. Note that this removes all symlinks to matching unit files, + including manually created symlinks, and not just those actually created by enable or + link. Note that while disable undoes the effect of + enable, the two commands are otherwise not symmetric, as disable may + remove more symlinks than a prior enable invocation of the same unit created. + + This command expects valid unit names only, it does not accept paths to unit files. + + In addition to the units specified as arguments, all units are disabled that are listed in the + Also= setting contained in the [Install] section of any of the unit + files being operated on. + + This command implicitly reloads the system manager configuration after completing the operation. Note + that this command does not implicitly stop the units that are being disabled. If this is desired, either + combine this command with the switch, or invoke the stop command + with appropriate arguments later. + + This command will print information about the file system operations (symlink removals) + executed. This output may be suppressed by passing . - This command honors , - , and - in a similar way as - enable. + This command honors , , + and in a similar way as enable. @@ -1073,12 +1068,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service reenable NAME... - Reenable one or more unit files, as specified on the - command line. This is a combination of - disable and enable and - is useful to reset the symlinks a unit is enabled with to - the defaults configured in the [Install] - section of the unit file. + Reenable one or more units, as specified on the command line. This is a combination of + disable and enable and is useful to reset the symlinks a unit file is + enabled with to the defaults configured in its [Install] section. This commands expects + a unit uname only, it does not accept paths to unit files. @@ -1209,16 +1202,13 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service mask NAME... - Mask one or more unit files, as specified on the - command line. This will link these units to - /dev/null, making it impossible to - start them. This is a stronger version of - disable, since it prohibits all kinds of - activation of the unit, including enablement and manual - activation. Use this option with care. This honors the - option to only mask temporarily - until the next reboot of the system. The - option can be used to ensure that the units are also stopped. + Mask one or more units, as specified on the command line. This will link these unit files to + /dev/null, making it impossible to start them. This is a stronger version of + disable, since it prohibits all kinds of activation of the unit, including enablement + and manual activation. Use this option with care. This honors the option to only + mask temporarily until the next reboot of the system. The option may be used to + ensure that the units are also stopped. This command expects valid unit names only, it does not accept unit + file paths. @@ -1226,23 +1216,20 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service unmask NAME... - Unmask one or more unit files, as specified on the - command line. This will undo the effect of - mask. + Unmask one or more unit files, as specified on the command line. This will undo the effect of + mask. This command expects valid unit names only, it does not accept unit file + paths. - link FILENAME... + link PATH... - Link a unit file that is not in the unit file search - paths into the unit file search path. This requires an - absolute path to a unit file. The effect of this can be - undone with disable. The effect of this - command is that a unit file is available for - start and other commands although it - is not installed directly in the unit search path. + Link a unit file that is not in the unit file search paths into the unit file search path. This + command expects an absolute path to a unit file. The effect of this may be undone with + disable. The effect of this command is that a unit file is made available for commands + such as start, even though it is not installed directly in the unit search path. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 5298fcfb9c..bfd770e4df 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6533,7 +6533,7 @@ static void systemctl_help(void) { " unit is required or wanted\n\n" "Unit File Commands:\n" " list-unit-files [PATTERN...] List installed unit files\n" - " enable NAME... Enable one or more unit files\n" + " enable [NAME...|PATH...] Enable one or more unit files\n" " disable NAME... Disable one or more unit files\n" " reenable NAME... Reenable one or more unit files\n" " preset NAME... Enable/disable one or more unit files\n" -- cgit v1.2.3-54-g00ecf From 98df8089bea1b2407c46495b6c2eb76dda46c658 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Mon, 25 Jul 2016 15:39:46 +0200 Subject: namespace: don't fail on masked mounts (#3794) Before this patch, a service file with ReadWriteDirectories=/file... could fail if the file exists but is not a mountpoint, despite being listed in /proc/self/mountinfo. It could happen with masked mounts. Fixes https://github.com/systemd/systemd/issues/3793 --- src/basic/mount-util.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index b91f0f9e0e..28dc778969 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -448,21 +448,21 @@ int bind_remount_recursive(const char *prefix, bool ro) { if (r < 0) return r; - /* Try to reuse the original flag set, but - * don't care for errors, in case of - * obstructed mounts */ + /* Deal with mount points that are obstructed by a + * later mount */ + r = path_is_mount_point(x, 0); + if (r == -ENOENT || r == 0) + continue; + if (r < 0) + return r; + + /* Try to reuse the original flag set */ 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 */ - - if (errno != ENOENT) - return -errno; - } + if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) + return -errno; } } -- cgit v1.2.3-54-g00ecf From f777b4345e8c57e739bda746f78757d0fb136ac7 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 10:20:16 -0400 Subject: shared/install: allow "enable" on linked unit files (#3790) User expectations are broken when "systemctl enable /some/path/service.service" behaves differently to "systemctl link ..." followed by "systemctl enable". From user's POV, "enable" with the full path just combines the two steps into one. Fixes #3010. --- src/shared/install.c | 2 +- src/test/test-install-root.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 23cab96c50..7b49e1ece9 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2215,7 +2215,7 @@ int unit_file_enable( config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(f, files) { - r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i); + r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; r = install_info_may_process(i, &paths, changes, n_changes); diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 4b9a74fca4..db1c928660 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -301,7 +301,12 @@ static void test_linked_units(const char *root) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(startswith(changes[0].path, root)); + assert_se(endswith(changes[0].path, "linked3.service")); + assert_se(streq(changes[0].source, "/opt/linked3.service")); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; } -- cgit v1.2.3-54-g00ecf From 43eb109aa9b8952dbcbfc0ae564d91c180f5d93a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 16:53:33 +0200 Subject: core: change ExecStart=! syntax to ExecStart=+ (#3797) As suggested by @mbiebl we already use the "!" special char in unit file assignments for negation, hence we should not use it in a different context for privileged execution. Let's use "+" instead. --- NEWS | 2 +- man/systemd.exec.xml | 20 ++++++++++---------- man/systemd.service.xml | 20 ++++++++------------ src/core/load-fragment.c | 2 +- 4 files changed, 20 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index 36fb84b26f..0ffe025400 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ CHANGES WITH 231: * In service units the various ExecXYZ= settings have been extended with an additional special character as first argument of the - assigned value: if the character '!' is used the specified command + assigned value: if the character '+' is used the specified command line it will be run with full privileges, regardless of User=, Group=, CapabilityBoundingSet= and similar options. The effect is similar to the existing PermissionsStartOnly= option, but allows diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 49fea98a95..41ae6e76de 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -146,7 +146,7 @@ Sets the Unix user or group that the processes are executed as, respectively. Takes a single user or group name or ID as argument. If no group is set, the default group - of the user is chosen. These do not affect commands prefixed with !. + of the user is chosen. These do not affect commands prefixed with +. @@ -161,7 +161,7 @@ this one will have no effect. In any way, this option does not override, but extends the list of supplementary groups configured in the system group database for the - user. This does not affect commands prefixed with !. + user. This does not affect commands prefixed with +. @@ -796,7 +796,7 @@ empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior settings have no effect. If set to ~ (without any further argument), the bounding set is reset to the full set of available capabilities, also undoing any previous settings. This does not affect - commands prefixed with !. + commands prefixed with +. @@ -826,7 +826,7 @@ Note that in this case option keep-caps is automatically added to SecureBits= to retain the capabilities over the user change. AmbientCapabilities= does not affect - commands prefixed with !. + commands prefixed with +. @@ -842,7 +842,7 @@ . This option may appear more than once, in which case the secure bits are ORed. If the empty string is assigned to this option, - the bits are reset to 0. This does not affect commands prefixed with !. + the bits are reset to 0. This does not affect commands prefixed with +. See capabilities7 for details. @@ -1101,7 +1101,7 @@ domain transition. However, the policy still needs to authorize the transition. This directive is ignored if SELinux is disabled. If prefixed by -, all errors - will be ignored. This does not affect commands prefixed with !. + will be ignored. This does not affect commands prefixed with +. See setexeccon3 for details. @@ -1114,7 +1114,7 @@ Profiles must already be loaded in the kernel, or the unit will fail. This result in a non operation if AppArmor is not enabled. If prefixed by -, all errors will - be ignored. This does not affect commands prefixed with !. + be ignored. This does not affect commands prefixed with +. @@ -1134,7 +1134,7 @@ The value may be prefixed by -, in which case all errors will be ignored. An empty value may be specified to unset previous assignments. This does not affect - commands prefixed with !. + commands prefixed with +. @@ -1185,7 +1185,7 @@ listed explicitly. This option may be specified more than once, in which case the filter masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will - have no effect. This does not affect commands prefixed with !. + have no effect. This does not affect commands prefixed with +. If you specify both types of this option (i.e. whitelisting and blacklisting), the first encountered will @@ -1354,7 +1354,7 @@ family should be included in the configured whitelist as it is frequently used for local communication, including for syslog2 - logging. This does not affect commands prefixed with !. + logging. This does not affect commands prefixed with +. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 70f12b2d32..875d368fcf 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -288,18 +288,14 @@ ExecStart= is specified, then the service must have RemainAfterExit=yes set. - For each of the specified commands, the first argument - must be an absolute path to an executable. Optionally, if this - file name is prefixed with @, the second - token will be passed as argv[0] to the - executed process, followed by the further arguments specified. - If the absolute filename is prefixed with - -, an exit code of the command normally - considered a failure (i.e. non-zero exit status or abnormal - exit due to signal) is ignored and considered success. - If the absolute path is prefixed with ! then - it is executed with full privileges. -, @, and ! - may be used together and they can appear in any order. + For each of the specified commands, the first argument must be an absolute path to an + executable. Optionally, if this file name is prefixed with @, the second token will be + passed as argv[0] to the executed process, followed by the further arguments specified. If + the absolute filename is prefixed with -, an exit code of the command normally considered a + failure (i.e. non-zero exit status or abnormal exit due to signal) is ignored and considered success. If the + absolute path is prefixed with + then it is executed with full + privileges. -, @, and + may be used together and they + can appear in any order. If more than one command is specified, the commands are invoked sequentially in the order they appear in the unit diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index ae306de4ae..a36953f766 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -620,7 +620,7 @@ int config_parse_exec( ignore = true; else if (*f == '@' && !separate_argv0) separate_argv0 = true; - else if (*f == '!' && !privileged) + else if (*f == '+' && !privileged) privileged = true; else break; -- cgit v1.2.3-54-g00ecf From b1ed76ae19bbbe9b836f3dae700cf610ce5dd869 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 11:20:58 -0400 Subject: systemctl: style tweaks for the new condition code --- src/systemctl/systemctl.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 84278e9bdb..d53450471e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3457,12 +3457,12 @@ static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) { typedef struct UnitCondition { char *name; + char *param; bool trigger; bool negate; - char *param; int tristate; - LIST_FIELDS(struct UnitCondition, condition); + LIST_FIELDS(struct UnitCondition, conditions); } UnitCondition; static void unit_condition_free(UnitCondition *c) { @@ -3519,7 +3519,7 @@ typedef struct UnitStatusInfo { usec_t condition_timestamp; bool condition_result; - LIST_HEAD(UnitCondition, condition); + LIST_HEAD(UnitCondition, conditions); usec_t assert_timestamp; bool assert_result; @@ -3689,22 +3689,18 @@ static void print_status_info( ansi_highlight_yellow(), ansi_normal(), s2, s1 ? "; " : "", strempty(s1)); - LIST_FOREACH(condition, c, i->condition) { + LIST_FOREACH(conditions, c, i->conditions) if (c->tristate < 0) n++; - } - - LIST_FOREACH(condition, c, i->condition) { - if (c->tristate >= 0) - continue; - printf(" %s %s=%s%s%s was not met\n", - --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT), - c->name, - c->trigger ? "|" : "", - c->negate ? "!" : "", - c->param); - } + LIST_FOREACH(conditions, c, i->conditions) + if (c->tristate < 0) + printf(" %s %s=%s%s%s was not met\n", + --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT), + c->name, + c->trigger ? "|" : "", + c->negate ? "!" : "", + c->param); } if (!i->assert_result && i->assert_timestamp > 0) { @@ -4199,7 +4195,7 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &state)) > 0) { UnitCondition *c; - log_debug("%s %d %d %s %d", cond, trigger, negate, param, state); + log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state); c = new0(UnitCondition, 1); if (!c) @@ -4222,7 +4218,7 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * c->negate = negate; c->tristate = state; - LIST_PREPEND(condition, i->condition, c); + LIST_PREPEND(conditions, i->conditions, c); } if (r < 0) return bus_log_parse_error(r); @@ -4749,8 +4745,8 @@ static int show_one( strv_free(info.dropin_paths); strv_free(info.listen); - while ((c = info.condition)) { - LIST_REMOVE(condition, info.condition, c); + while ((c = info.conditions)) { + LIST_REMOVE(conditions, info.conditions, c); unit_condition_free(c); } -- cgit v1.2.3-54-g00ecf From a733551846bcb2c7f46cc68bbc2e5741e653fbef Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 11:53:14 -0400 Subject: systemctl: use cleanup function for UnitStatusInfo There is no functional change, but clarity of the code is increased by splitting out the cleanup part and putting it next to the structure definition. --- src/systemctl/systemctl.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 7df2fa5421..e1bcef2d95 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3561,6 +3561,25 @@ typedef struct UnitStatusInfo { LIST_HEAD(ExecStatusInfo, exec); } UnitStatusInfo; +static void unit_status_info_free(UnitStatusInfo *info) { + ExecStatusInfo *p; + UnitCondition *c; + + strv_free(info->documentation); + strv_free(info->dropin_paths); + strv_free(info->listen); + + while ((c = info->conditions)) { + LIST_REMOVE(conditions, info->conditions, c); + unit_condition_free(c); + } + + while ((p = info->exec)) { + LIST_REMOVE(exec, info->exec, p); + exec_status_info_free(p); + } +} + static void print_status_info( sd_bus *bus, UnitStatusInfo *i, @@ -4621,7 +4640,7 @@ static int show_one( _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_set_free_ Set *found_properties = NULL; - UnitStatusInfo info = { + _cleanup_(unit_status_info_free) UnitStatusInfo info = { .memory_current = (uint64_t) -1, .memory_high = CGROUP_LIMIT_MAX, .memory_max = CGROUP_LIMIT_MAX, @@ -4630,8 +4649,6 @@ static int show_one( .tasks_current = (uint64_t) -1, .tasks_max = (uint64_t) -1, }; - ExecStatusInfo *p; - UnitCondition *c; int r; assert(path); @@ -4725,16 +4742,15 @@ static int show_one( return bus_log_parse_error(r); r = 0; - if (show_properties) { char **pp; - STRV_FOREACH(pp, arg_properties) { + STRV_FOREACH(pp, arg_properties) if (!set_contains(found_properties, *pp)) { log_warning("Property %s does not exist.", *pp); r = -ENXIO; } - } + } else if (streq(verb, "help")) show_unit_help(&info); else if (streq(verb, "status")) { @@ -4746,20 +4762,6 @@ static int show_one( r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; } - strv_free(info.documentation); - strv_free(info.dropin_paths); - strv_free(info.listen); - - while ((c = info.conditions)) { - LIST_REMOVE(conditions, info.conditions, c); - unit_condition_free(c); - } - - while ((p = info.exec)) { - LIST_REMOVE(exec, info.exec, p); - exec_status_info_free(p); - } - return r; } -- cgit v1.2.3-54-g00ecf From 662bea6729d4147dfdd1501f81335adf5a2a6012 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 12:15:57 -0400 Subject: systemctl: avoid "leaking" some strings in UnitStatusInfo % valgrind --leak-check=full systemctl status multipathd.service --no-pager -n0 ... ==431== 16 bytes in 2 blocks are definitely lost in loss record 1 of 2 ==431== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) ==431== by 0x534AF19: strdup (in /usr/lib64/libc-2.23.so) ==431== by 0x4E81AEE: free_and_strdup (string-util.c:794) ==431== by 0x4EF66C1: map_basic (bus-util.c:1030) ==431== by 0x4EF6A8E: bus_message_map_all_properties (bus-util.c:1153) ==431== by 0x120487: show_one (systemctl.c:4672) ==431== by 0x1218F3: show (systemctl.c:4990) ==431== by 0x4EC359E: dispatch_verb (verbs.c:92) ==431== by 0x12A3AE: systemctl_main (systemctl.c:7742) ==431== by 0x12B1A8: main (systemctl.c:8011) ==431== ==431== LEAK SUMMARY: ==431== definitely lost: 16 bytes in 2 blocks This happens because map_basic() strdups the strings. Other code in systemctl assigns strings to UnitStatusInfo without copying them, relying on the fact that the message is longer lived than UnitStatusInfo. Add a helper function that is similar to map_basic, but only accepts strings and does not copy them. The alternative of continuing to use map_basic() but adding proper cleanup to free fields in UnitStatusInfo seems less attractive because it'd require changing a lot of code and doing a lot of more allocations for little gain. (I put "leaking" in quotes, because systemctl is short lived anyway.) --- src/systemctl/systemctl.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e1bcef2d95..d4ec1da290 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -224,6 +224,21 @@ static void release_busses(void) { busses[w] = sd_bus_flush_close_unref(busses[w]); } +static int map_string_no_copy(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char *s; + const char **p = userdata; + int r; + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &s); + if (r < 0) + return r; + + if (!isempty(s)) + *p = s; + + return 0; +} + static void ask_password_agent_open_if_enabled(void) { /* Open the password agent as a child process if necessary */ @@ -4632,8 +4647,8 @@ static int show_one( bool *ellipsized) { static const struct bus_properties_map property_map[] = { - { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, - { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) }, + { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) }, + { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) }, {} }; @@ -5664,8 +5679,8 @@ static int unit_exists(const char *unit) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *path = NULL; static const struct bus_properties_map property_map[] = { - { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, - { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state)}, + { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) }, + { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)}, {}, }; UnitStatusInfo info = {}; -- cgit v1.2.3-54-g00ecf From c8091d92d5258afee017506ebac086da2f99ee91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 19:03:43 +0200 Subject: coredump: turn off coredump collection only when PID 1 crashes, not when journald crashes (#3799) As suggested: https://github.com/systemd/systemd/pull/3783/files/5157879b757bffce3da0a68ca207753569e8627d#r71906971 --- src/coredump/coredump.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 043d785dd4..dcc09fcc6d 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -918,9 +918,6 @@ static int process_special_crash(const char *context[], int input_fd) { log_notice("Detected coredump of the journal daemon or PID 1, diverted to %s.", filename); - log_notice("Due to the special circumstances, coredump collection will now be turned off."); - (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); - return 0; } @@ -980,6 +977,12 @@ static int process_kernel(int argc, char* argv[]) { if (cg_pid_get_unit(pid, &t) >= 0) { + /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */ + if (streq(t, SPECIAL_INIT_SCOPE)) { + log_notice("Due to PID 1 having crashed coredump collection will now be turned off."); + (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + } + /* Let's avoid dead-locks when processing journald and init crashes, as socket activation and logging * are unlikely to work then. */ if (STR_IN_SET(t, SPECIAL_JOURNALD_SERVICE, SPECIAL_INIT_SCOPE)) { -- cgit v1.2.3-54-g00ecf From f8654baa084e8888bc5ba11e8ef3d9784f955cff Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 12:21:50 -0400 Subject: systemctl: simplify machine_info_clear It is only used with info allocated on the stack, so the pointer cannot be NULL. --- src/systemctl/systemctl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d4ec1da290..44a3708a62 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1835,12 +1835,12 @@ static const struct bus_properties_map machine_info_property_map[] = { }; static void machine_info_clear(struct machine_info *info) { - if (info) { - free(info->name); - free(info->state); - free(info->control_group); - zero(*info); - } + assert(info); + + free(info->name); + free(info->state); + free(info->control_group); + zero(*info); } static void free_machines_list(struct machine_info *machine_infos, int n) { -- cgit v1.2.3-54-g00ecf From 9bb7194019ab62b85f76df2be207d3dac58ed726 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 12:29:20 -0400 Subject: systemctl: use _cleanup_ for UnitCondition --- src/systemctl/systemctl.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 44a3708a62..6a0ed79a53 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3484,13 +3484,16 @@ typedef struct UnitCondition { } UnitCondition; static void unit_condition_free(UnitCondition *c) { - assert(c); + if (!c) + return; free(c->name); free(c->param); free(c); } +DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free); + typedef struct UnitStatusInfo { const char *id; const char *load_state; @@ -4232,7 +4235,7 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &state)) > 0) { - UnitCondition *c; + _cleanup_(unit_condition_freep) UnitCondition *c = NULL; log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state); @@ -4241,23 +4244,16 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * return log_oom(); c->name = strdup(cond); - if (!c->name) { - free(c); - return log_oom(); - } - c->param = strdup(param); - if (!c->param) { - free(c->name); - free(c); + if (!c->name || !c->param) return log_oom(); - } c->trigger = trigger; c->negate = negate; c->tristate = state; LIST_PREPEND(conditions, i->conditions, c); + c = NULL; } if (r < 0) return bus_log_parse_error(r); -- cgit v1.2.3-54-g00ecf From 2de0b9e913823d6e564ea82d80d014451c238f20 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 25 Jul 2016 20:02:55 +0200 Subject: transaction: don't cancel jobs for units with IgnoreOnIsolate=true (#3671) This is important if a job was queued for a unit but not yet started. Without this, the job will be canceled and is never executed even though IgnoreOnIsolate it set to 'true'. --- src/core/transaction.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/core/transaction.c b/src/core/transaction.c index af539171fd..8370b864fb 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -591,6 +591,9 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { HASHMAP_FOREACH(j, m->jobs, i) { assert(j->installed); + if (j->unit->ignore_on_isolate) + continue; + if (hashmap_get(tr->jobs, j->unit)) continue; -- cgit v1.2.3-54-g00ecf From 87d41d6244f1eaf441769f7f6216a606c52b8e89 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 25 Jul 2016 20:04:02 +0200 Subject: automount: don't cancel mount/umount request on reload/reexec (#3670) All pending tokens are already serialized correctly and will be handled when the mount unit is done. Without this a 'daemon-reload' cancels all pending tokens. Any process waiting for the mount will continue with EHOSTDOWN. This can happen when the mount unit waits for it's dependencies, e.g. network, devices, fsck, etc. --- src/core/automount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index 85803a9c4a..4e9891569c 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -98,9 +98,6 @@ static void unmount_autofs(Automount *a) { if (a->pipe_fd < 0) return; - automount_send_ready(a, a->tokens, -EHOSTDOWN); - automount_send_ready(a, a->expire_tokens, -EHOSTDOWN); - a->pipe_event_source = sd_event_source_unref(a->pipe_event_source); a->pipe_fd = safe_close(a->pipe_fd); @@ -109,6 +106,9 @@ static void unmount_autofs(Automount *a) { if (a->where && (UNIT(a)->manager->exit_code != MANAGER_RELOAD && UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) { + automount_send_ready(a, a->tokens, -EHOSTDOWN); + automount_send_ready(a, a->expire_tokens, -EHOSTDOWN); + r = repeat_unmount(a->where, MNT_DETACH); if (r < 0) log_error_errno(r, "Failed to unmount: %m"); -- cgit v1.2.3-54-g00ecf From 87410f166eb5e0f06703bd82fdec2fb47afb58ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 20:35:04 +0200 Subject: fileio: imply /tmp as directory if passed as NULL to open_tmpfile_unlinkable() We can make this smarter one day, to honour $TMPDIR and friends, but for now, let's just use /tmp. --- src/basic/fileio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 47ccfc39d8..f183de4999 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1259,7 +1259,8 @@ int open_tmpfile_unlinkable(const char *directory, int flags) { char *p; int fd; - assert(directory); + if (!directory) + directory = "/tmp"; /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ -- cgit v1.2.3-54-g00ecf From 65548c58dddf721d03d8a5f5c96b196510f158fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 20:50:24 +0200 Subject: sd-id128: be more liberal when reading files with 128bit IDs Accept both files with and without trailing newlines. Apparently some rkt releases generated them incorrectly, missing the trailing newlines, and we shouldn't break that. --- src/libsystemd/sd-id128/id128-util.c | 30 +++++++++++----- src/test/test-id128.c | 69 +++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c index aaac838b59..c3f527d657 100644 --- a/src/libsystemd/sd-id128/id128-util.c +++ b/src/libsystemd/sd-id128/id128-util.c @@ -100,33 +100,45 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { assert(f < _ID128_FORMAT_MAX); /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both - * followed by a newline and nothing else. */ + * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they + * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you + * accept". */ - l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 33 or 37 chars */ + l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */ if (l < 0) return (int) l; if (l == 0) /* empty? */ return -ENOMEDIUM; - if (l == 33) { - if (f == ID128_UUID) - return -EINVAL; + switch (l) { + case 33: /* plain UUID with trailing newline */ if (buffer[32] != '\n') return -EINVAL; + /* fall through */ + case 32: /* plain UUID without trailing newline */ + if (f == ID128_UUID) + return -EINVAL; + buffer[32] = 0; + break; - } else if (l == 37) { - if (f == ID128_PLAIN) + case 37: /* RFC UUID with trailing newline */ + if (buffer[36] != '\n') return -EINVAL; - if (buffer[36] != '\n') + /* fall through */ + case 36: /* RFC UUID without trailing newline */ + if (f == ID128_PLAIN) return -EINVAL; buffer[36] = 0; - } else + break; + + default: return -EINVAL; + } return sd_id128_from_string(buffer, ret); } diff --git a/src/test/test-id128.c b/src/test/test-id128.c index 324c7a2019..f01fbdd6b2 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -23,10 +23,12 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "id128-util.h" #include "macro.h" #include "string-util.h" #include "util.h" -#include "id128-util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" @@ -36,6 +38,7 @@ int main(int argc, char *argv[]) { sd_id128_t id, id2; char t[33], q[37]; _cleanup_free_ char *b = NULL; + _cleanup_close_ int fd = -1; assert_se(sd_id128_randomize(&id) == 0); printf("random: %s\n", sd_id128_to_string(id, t)); @@ -86,5 +89,69 @@ int main(int argc, char *argv[]) { assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10")); assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10")); + fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + /* First, write as UUID */ + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(id128_write_fd(fd, ID128_UUID, id, false) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Second, write as plain */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(id128_write_fd(fd, ID128_PLAIN, id, false) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Third, write plain without trailing newline */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Third, write UUID without trailing newline */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(write(fd, id128_to_uuid_string(id, t), 36) == 36); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + return 0; } -- cgit v1.2.3-54-g00ecf From 69a361b7021f508d342cd408b9070b2cbf148dfa Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:23:40 -0400 Subject: FSDG: os-release: Default to PRETTY_NAME "GNU/Linux" instead of "Linux". --- man/kernel-install.xml | 2 +- man/os-release.xml | 2 +- src/analyze/analyze.c | 2 +- src/core/main.c | 4 ++-- src/firstboot/firstboot.c | 2 +- src/kernel-install/90-loaderentry.install | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/kernel-install.xml b/man/kernel-install.xml index d7e27de758..eb519188a6 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -106,7 +106,7 @@ PRETTY_NAME parameter specified in /etc/os-release or /usr/lib/os-release (if the former is - missing), or "Linux + missing), or "GNU/Linux KERNEL-VERSION", if unset. If the file initrd is found next to the linux file, the initrd will be added to diff --git a/man/os-release.xml b/man/os-release.xml index 99bbb61004..27d18749dc 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -210,7 +210,7 @@ suitable for presentation to the user. May or may not contain a release code name or OS version of some kind, as suitable. If not set, defaults to - PRETTY_NAME="Linux". Example: + PRETTY_NAME="GNU/Linux". Example: PRETTY_NAME="Fedora 17 (Beefy Miracle)". diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index cbf9354a7a..66830695f3 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -653,7 +653,7 @@ static int analyze_plot(sd_bus *bus) { svg("\n"); svg("%s", pretty_times); svg("%s %s (%s %s %s) %s %s", - isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, + isempty(host->os_pretty_name) ? "GNU/Linux" : host->os_pretty_name, strempty(host->hostname), strempty(host->kernel_name), strempty(host->kernel_release), diff --git a/src/core/main.c b/src/core/main.c index f2adca7d2b..719bc49475 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1240,11 +1240,11 @@ static int status_welcome(void) { return status_printf(NULL, false, false, "\nWelcome to \x1B[%sm%s\x1B[0m!\n", isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); else return status_printf(NULL, false, false, "\nWelcome to %s!\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); } static int write_container_id(void) { diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index c9e8e54ee3..83a21eaf0e 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -96,7 +96,7 @@ static void print_welcome(void) { log_warning_errno(r, "Failed to read os-release file: %m"); printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); press_any_key(); diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index a0bca05c9a..af9f0f9ccd 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -38,7 +38,7 @@ elif [[ -f /usr/lib/os-release ]]; then fi if ! [[ $PRETTY_NAME ]]; then - PRETTY_NAME="Linux $KERNEL_VERSION" + PRETTY_NAME="GNU/Linux $KERNEL_VERSION" fi declare -a BOOT_OPTIONS -- cgit v1.2.3-54-g00ecf From 148d8a99607e4d7d55dc5556640635425a88ff2c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:24:56 -0400 Subject: FSDG: os-release: Default to NAME "GNU/Linux" instead of "Linux". --- man/os-release.xml | 2 +- src/journal-remote/journal-gatewayd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/man/os-release.xml b/man/os-release.xml index 27d18749dc..a88d16b171 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -121,7 +121,7 @@ A string identifying the operating system, without a version component, and suitable for presentation to the user. If not set, defaults to - NAME=Linux. Example: + NAME=GNU/Linux. Example: NAME=Fedora or NAME="Debian GNU/Linux". diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4ad9184993..e265027a04 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -801,7 +801,7 @@ static int request_handler_machine( SD_ID128_FORMAT_VAL(mid), SD_ID128_FORMAT_VAL(bid), hostname_cleanup(hostname), - os_name ? os_name : "Linux", + os_name ? os_name : "GNU/Linux", v ? v : "bare", usage, cutoff_from, -- cgit v1.2.3-54-g00ecf From befb351349342b699e90ec5d04e0ddb34e095211 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:31:20 -0400 Subject: FSDG: systemd-resolved: Default to hostname "gnu-linux" instead of "linux" --- src/resolve/resolved-manager.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 92ade820ac..9bb623c321 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -430,12 +430,12 @@ static int manager_watch_hostname(Manager *m) { r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { - log_info("Defaulting to hostname 'linux'."); - m->llmnr_hostname = strdup("linux"); + log_info("Defaulting to hostname 'gnu-linux'."); + m->llmnr_hostname = strdup("gnu-linux"); if (!m->llmnr_hostname) return log_oom(); - m->mdns_hostname = strdup("linux.local"); + m->mdns_hostname = strdup("gnu-linux.local"); if (!m->mdns_hostname) return log_oom(); } else -- cgit v1.2.3-54-g00ecf From ae8150ecbd54765622aadf288100440d71a10ccd Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 13 Sep 2016 20:39:40 -0400 Subject: # Rename "Linux Boot Manager" -> "Systemd Boot Manager" sed -i 's|Linux Boot Manager|Systemd Boot Manager|' src/boot/bootctl.c --- src/boot/bootctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 37fa049ecf..056a0790bd 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -763,13 +763,13 @@ static int install_variables(const char *esp_path, "Failed to determine current boot order: %m"); if (first || r == false) { - r = efi_add_boot_option(slot, "Linux Boot Manager", + r = efi_add_boot_option(slot, "Systemd Boot Manager", part, pstart, psize, uuid, path); if (r < 0) return log_error_errno(r, "Failed to create EFI Boot variable entry: %m"); - log_info("Created EFI boot entry \"Linux Boot Manager\"."); + log_info("Created EFI boot entry \"Systemd Boot Manager\"."); } return insert_into_order(slot, first); -- cgit v1.2.3-54-g00ecf