/* NB: these set SO_REUSEADDR before bind */
int create_and_bind_stream_or_die(const char *bindaddr, int port) FAST_FUNC;
int create_and_bind_dgram_or_die(const char *bindaddr, int port) FAST_FUNC;
+int create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf) FAST_FUNC;
/* Create client TCP socket connected to peer:port. Peer cannot be NULL.
* Peer can be numeric IP ("N.N.N.N"), numeric IPv6 address or hostname,
* and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT").
#include <netinet/in.h>
#include <net/if.h>
#include <sys/un.h>
+#if ENABLE_IFPLUGD || ENABLE_FEATURE_MDEV_DAEMON || ENABLE_UEVENT
+# include <linux/netlink.h>
+#endif
#include "libbb.h"
int FAST_FUNC setsockopt_int(int fd, int level, int optname, int optval)
}
+#if ENABLE_IFPLUGD || ENABLE_FEATURE_MDEV_DAEMON || ENABLE_UEVENT
+int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf)
+{
+ struct sockaddr_nl sa;
+ int fd;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_pid = getpid();
+ sa.nl_groups = grp;
+ fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto);
+ xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
+ close_on_exec_on(fd);
+
+ if (rcvbuf != 0) {
+ // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl
+ setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf);
+ setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf);
+# if 0
+ {
+ int z;
+ socklen_t zl = sizeof(z);
+ getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl);
+ bb_error_msg("SO_RCVBUF:%d", z);
+ }
+# endif
+ }
+
+ return fd;
+}
+#endif
+
int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port)
{
int fd;
xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd);
if (opts & FLAG_MONITOR) {
- struct sockaddr_nl addr;
- int fd = xsocket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
-
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_groups = RTMGRP_LINK;
- addr.nl_pid = getpid();
-
- xbind(fd, (struct sockaddr*)&addr, sizeof(addr));
+ int fd = create_and_bind_to_netlink(NETLINK_ROUTE, RTMGRP_LINK, 0);
xmove_fd(fd, netlink_fd);
}
/*
* Daemon mode listening on uevent netlink socket.
*/
- struct sockaddr_nl sa;
int fd;
-//TODO: reuse same code in uevent
- // Subscribe for UEVENT kernel messages
- sa.nl_family = AF_NETLINK;
- sa.nl_pad = 0;
- sa.nl_pid = getpid();
- sa.nl_groups = 1 << 0;
- fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
- close_on_exec_on(fd);
-
- // Without a sufficiently big RCVBUF, a ton of simultaneous events
- // can trigger ENOBUFS on read, which is unrecoverable.
- // Reproducer:
- // mdev -d
- // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
- //
- // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl
- setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF);
- setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF);
+ /* Subscribe for UEVENT kernel messages */
+ /* Without a sufficiently big RCVBUF, a ton of simultaneous events
+ * can trigger ENOBUFS on read, which is unrecoverable.
+ * Reproducer:
+ * mdev -d
+ * find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
+ */
+ fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, 1 << 0, RCVBUF);
/*
* Make inital scan after the uevent socket is alive and
int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int uevent_main(int argc UNUSED_PARAM, char **argv)
{
- struct sockaddr_nl sa;
int fd;
INIT_G();
argv++;
- // Subscribe for UEVENT kernel messages
- sa.nl_family = AF_NETLINK;
- sa.nl_pad = 0;
- sa.nl_pid = getpid();
- sa.nl_groups = 1 << 0;
- fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
- close_on_exec_on(fd);
-
+ // Subscribe for UEVENT kernel messages.
// Without a sufficiently big RCVBUF, a ton of simultaneous events
// can trigger ENOBUFS on read, which is unrecoverable.
// Reproducer:
// uevent mdev &
// find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
- //
- // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl
- setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF);
- setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF);
- if (0) {
- int z;
- socklen_t zl = sizeof(z);
- getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl);
- bb_error_msg("SO_RCVBUF:%d", z);
- }
+ fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, RCVBUF);
for (;;) {
char *netbuf;
}
env[idx] = NULL;
- idx = 0;
- while (env[idx])
- putenv(env[idx++]);
- if (argv[0])
+ if (argv[0]) {
+ idx = 0;
+ while (env[idx])
+ putenv(env[idx++]);
spawn_and_wait(argv);
- idx = 0;
- while (env[idx])
- bb_unsetenv(env[idx++]);
+ idx = 0;
+ while (env[idx])
+ bb_unsetenv(env[idx++]);
+ }
munmap(netbuf, BUFFER_SIZE);
}