summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/socket-util.c17
-rw-r--r--src/test/test-socket-util.c62
-rw-r--r--src/udev/udev-rules.c2
3 files changed, 78 insertions, 3 deletions
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 904bafb76f..e787d53d8f 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -1225,9 +1225,22 @@ int flush_accept(int fd) {
.fd = fd,
.events = POLLIN,
};
- int r;
+ int r, b;
+ socklen_t l = sizeof(b);
+
+ /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately
+ * closing them. */
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0)
+ return -errno;
- /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
+ assert(l == sizeof(b));
+ if (!b) /* Let's check if this is a socket accepting connections before calling accept(). That's
+ * because accept4() can return EOPNOTSUPP in the fd we are called on is not a listening
+ * socket, or in case the incoming TCP connection transiently triggered that (see accept(2)
+ * man page for details). The latter case is a transient error we should continue looping
+ * on. The former case however is fatal. */
+ return -ENOTTY;
for (;;) {
int cfd;
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 057840d76f..4e9a0bddf4 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -810,6 +810,67 @@ static void test_send_emptydata(void) {
assert_se(fd == -999);
}
+static void test_flush_accept(void) {
+ _cleanup_close_ int listen_stream = -1, listen_dgram = -1, listen_seqpacket = 1, connect_stream = -1, connect_dgram = -1, connect_seqpacket = -1;
+ static const union sockaddr_union sa = { .un.sun_family = AF_UNIX };
+ union sockaddr_union lsa;
+ socklen_t l;
+
+ listen_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_stream >= 0);
+
+ listen_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_dgram >= 0);
+
+ listen_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_seqpacket >= 0);
+
+ assert_se(flush_accept(listen_stream) < 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) < 0);
+
+ assert_se(bind(listen_stream, &sa.sa, sizeof(sa_family_t)) >= 0);
+ assert_se(bind(listen_dgram, &sa.sa, sizeof(sa_family_t)) >= 0);
+ assert_se(bind(listen_seqpacket, &sa.sa, sizeof(sa_family_t)) >= 0);
+
+ assert_se(flush_accept(listen_stream) < 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) < 0);
+
+ assert_se(listen(listen_stream, SOMAXCONN) >= 0);
+ assert_se(listen(listen_dgram, SOMAXCONN) < 0);
+ assert_se(listen(listen_seqpacket, SOMAXCONN) >= 0);
+
+ assert_se(flush_accept(listen_stream) >= 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) >= 0);
+
+ connect_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_stream >= 0);
+
+ connect_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_dgram >= 0);
+
+ connect_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_seqpacket >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_stream, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_stream, &lsa.sa, l) >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_dgram, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_dgram, &lsa.sa, l) >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_seqpacket, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_seqpacket, &lsa.sa, l) >= 0);
+
+ assert_se(flush_accept(listen_stream) >= 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) >= 0);
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@@ -843,6 +904,7 @@ int main(int argc, char *argv[]) {
test_receive_nopassfd();
test_send_nodata_nofd();
test_send_emptydata();
+ test_flush_accept();
return 0;
}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 63a967633b..96840b272c 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -2442,7 +2442,7 @@ int udev_rules_apply_to_event(
case TK_A_RUN_BUILTIN:
case TK_A_RUN_PROGRAM: {
_cleanup_free_ char *cmd = NULL;
-
+
if (event->run_final)
break;
if (cur->key.op == OP_ASSIGN_FINAL)