summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/socket-util.c34
-rw-r--r--src/basic/socket-util.h2
-rw-r--r--src/core/main.c1
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c23
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c9
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c13
-rw-r--r--src/libsystemd-network/sd-ndisc.c13
-rw-r--r--src/resolve/resolved-manager.c10
-rw-r--r--src/shared/bus-util.c31
-rw-r--r--src/shared/bus-util.h2
-rw-r--r--src/systemctl/systemctl.c5
11 files changed, 82 insertions, 61 deletions
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 49e5f5b125..58512686e3 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -936,3 +936,37 @@ int receive_one_fd(int transport_fd, int flags) {
return *(int*) CMSG_DATA(found);
}
+
+ssize_t next_datagram_size_fd(int fd) {
+ ssize_t l;
+ int k;
+
+ /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
+ * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't
+ * do. This difference is actually of major importance as we need to be sure that the size returned here
+ * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
+ * the wrong size. */
+
+ l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
+ if (l < 0) {
+ if (errno == EOPNOTSUPP)
+ goto fallback;
+
+ return -errno;
+ }
+ if (l == 0)
+ goto fallback;
+
+ return l;
+
+fallback:
+ k = 0;
+
+ /* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
+ * for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
+
+ if (ioctl(fd, FIONREAD, &k) < 0)
+ return -errno;
+
+ return (ssize_t) k;
+}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 92edc1dc22..d17a2f35f8 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -133,5 +133,7 @@ int send_one_fd_sa(int transport_fd,
#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags)
int receive_one_fd(int transport_fd, int flags);
+ssize_t next_datagram_size_fd(int fd);
+
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
diff --git a/src/core/main.c b/src/core/main.c
index e2088574c0..c725a686f1 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1313,7 +1313,6 @@ int main(int argc, char *argv[]) {
/* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
- errno = -ENOENT;
execv(SYSTEMCTL_BINARY_PATH, argv);
log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
return 1;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 5fd59f7dd3..62099dd3f4 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1525,20 +1525,17 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
uint32_t revents, void *userdata) {
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPMessage *message = NULL;
- int buflen = 0, len, r;
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
const struct ether_addr *expected_chaddr = NULL;
uint8_t expected_hlen = 0;
+ ssize_t len, buflen;
assert(s);
assert(client);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* this can't be right */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc0(buflen);
if (!message)
@@ -1616,17 +1613,15 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
};
struct cmsghdr *cmsg;
bool checksum = true;
- int buflen = 0, len, r;
+ ssize_t buflen, len;
+ int r;
assert(s);
assert(client);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* this can't be right */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
packet = malloc0(buflen);
if (!packet)
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index ad3a37b722..54ff1a3f28 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -955,14 +955,13 @@ static int server_receive_message(sd_event_source *s, int fd,
.msg_controllen = sizeof(cmsgbuf),
};
struct cmsghdr *cmsg;
- int buflen = 0, len;
+ ssize_t buflen, len;
assert(server);
- if (ioctl(fd, FIONREAD, &buflen) < 0)
- return -errno;
- else if (buflen < 0)
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc(buflen);
if (!message)
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 5b6b9cbcac..7d56d4cc60 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -33,6 +33,7 @@
#include "in-addr-util.h"
#include "network-internal.h"
#include "random-util.h"
+#include "socket-util.h"
#include "string-table.h"
#include "util.h"
@@ -891,18 +892,16 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
_cleanup_free_ DHCP6Message *message = NULL;
- int r, buflen, len;
+ ssize_t buflen, len;
+ int r = 0;
assert(s);
assert(client);
assert(client->event);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* This really should not happen */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc(buflen);
if (!message)
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index 519d2aa36b..bae6a49fe6 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -491,19 +491,16 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
struct cmsghdr *cmsg;
struct in6_addr *gw;
unsigned lifetime;
- ssize_t len;
- int r, pref, stateful, buflen = 0;
+ ssize_t len, buflen;
+ int r, pref, stateful;
assert(s);
assert(nd);
assert(nd->event);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* This really should not happen */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
iov.iov_len = buflen;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 44aafd0515..b3ff46b5da 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -617,18 +617,16 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
struct msghdr mh = {};
struct cmsghdr *cmsg;
struct iovec iov;
- int ms = 0, r;
- ssize_t l;
+ ssize_t ms, l;
+ int r;
assert(m);
assert(fd >= 0);
assert(ret);
- r = ioctl(fd, FIONREAD, &ms);
- if (r < 0)
- return -errno;
+ ms = next_datagram_size_fd(fd);
if (ms < 0)
- return -EIO;
+ return ms;
r = dns_packet_new(&p, protocol, ms);
if (r < 0)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 1fcf3f6a7f..c87eaf63d8 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -2028,8 +2028,8 @@ static const struct {
{ "start-limit", "start of the service was attempted too often" }
};
-static void log_job_error_with_service_result(const char* service, const char *result, const char** extra_args) {
- _cleanup_free_ char *service_shell_quoted = NULL, *_systemctl, *_journalctl;
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+ _cleanup_free_ char *service_shell_quoted = NULL;
const char *systemctl = "systemctl", *journalctl = "journalct";
assert(service);
@@ -2037,13 +2037,11 @@ static void log_job_error_with_service_result(const char* service, const char *r
service_shell_quoted = shell_maybe_quote(service);
if (extra_args && extra_args[1]) {
- assert(extra_args[0] == NULL);
+ _cleanup_free_ char *t;
- extra_args[0] = "systemctl";
- systemctl = _systemctl = strv_join((char**) extra_args, " ");
-
- extra_args[0] = "journalctl";
- journalctl = _journalctl = strv_join((char**) extra_args, " ");
+ t = strv_join((char**) extra_args, " ");
+ systemctl = strjoina("systemctl ", t ?: "<args>", NULL);
+ journalctl = strjoina("journalctl ", t ?: "<args>", NULL);
}
if (!isempty(result)) {
@@ -2058,29 +2056,30 @@ static void log_job_error_with_service_result(const char* service, const char *r
"See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
explanations[i].explanation,
- systemctl ?: "systemctl <args>",
+ systemctl,
service_shell_quoted ?: "<service>",
- journalctl ?: "journalctl <args>");
+ journalctl);
goto finish;
}
}
- log_error("Job for %s failed. See \"%s status %s\" and \"%s -xe\" for details.\n",
+ log_error("Job for %s failed.\n"
+ "See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
- systemctl ?: "systemctl <args>",
+ systemctl,
service_shell_quoted ?: "<service>",
- journalctl ?: "journalctl <args>");
+ journalctl);
finish:
/* For some results maybe additional explanation is required */
if (streq_ptr(result, "start-limit"))
log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
"followed by \"%1$s start %2$s\" again.",
- systemctl ?: "systemctl <args>",
+ systemctl,
service_shell_quoted ?: "<service>");
}
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char** extra_args) {
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d->result);
@@ -2131,7 +2130,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char** extra
return r;
}
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char** extra_args) {
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d);
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index 26d338beec..fcda1b2c6c 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -180,7 +180,7 @@ typedef struct BusWaitForJobs BusWaitForJobs;
int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
void bus_wait_for_jobs_free(BusWaitForJobs *d);
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char** extra_args);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 44c13cf4d7..c75d12c136 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2778,10 +2778,9 @@ static int start_unit(int argc, char *argv[], void *userdata) {
}
if (!arg_no_block) {
- int q, arg_count = 1;
- const char* extra_args[5] = {NULL};
+ int q, arg_count = 0;
+ const char* extra_args[4] = {};
- /* leave first empty for the actual command name*/
if (arg_scope != UNIT_FILE_SYSTEM)
extra_args[arg_count++] = "--user";