udevd: get netlink socket from systemd

This commit is contained in:
Kay Sievers
2011-04-14 23:46:44 +02:00
parent 7f2d3a3fc8
commit 7459bcdc8d
6 changed files with 162 additions and 74 deletions
+1
View File
@@ -8,4 +8,5 @@ DefaultDependencies=no
[Service]
Type=notify
OOMScoreAdjust=-1000
Restart=on-failure
ExecStart=@sbindir@/udevd
+1
View File
@@ -4,3 +4,4 @@ DefaultDependencies=no
[Socket]
ListenSequentialPacket=@/org/kernel/udev/udevd
ListenNetlink=kobject-uevent 1
+18 -16
View File
@@ -60,6 +60,7 @@ struct udev_ctrl {
int sock;
struct sockaddr_un saddr;
socklen_t addrlen;
bool bound;
bool connected;
};
@@ -81,7 +82,7 @@ static struct udev_ctrl *udev_ctrl_new(struct udev *udev)
return uctrl;
}
struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path)
struct udev_ctrl *udev_ctrl_new_from_socket_fd(struct udev *udev, const char *socket_path, int fd)
{
struct udev_ctrl *uctrl;
@@ -89,11 +90,16 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke
if (uctrl == NULL)
return NULL;
uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
if (uctrl->sock < 0) {
err(udev, "error getting socket: %m\n");
udev_ctrl_unref(uctrl);
return NULL;
if (fd < 0) {
uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
if (uctrl->sock < 0) {
err(udev, "error getting socket: %m\n");
udev_ctrl_unref(uctrl);
return NULL;
}
} else {
uctrl->bound = true;
uctrl->sock = fd;
}
uctrl->saddr.sun_family = AF_LOCAL;
@@ -105,35 +111,31 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke
return uctrl;
}
struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)
struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path)
{
struct udev_ctrl *uctrl;
uctrl = udev_ctrl_new(udev);
if (uctrl == NULL)
return NULL;
uctrl->sock = fd;
return uctrl;
return udev_ctrl_new_from_socket_fd(udev, socket_path, -1);
}
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
{
int err;
if (uctrl->addrlen > 0) {
if (!uctrl->bound) {
err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
if (err < 0) {
err = -errno;
err(uctrl->udev, "bind failed: %m\n");
return err;
}
err = listen(uctrl->sock, 0);
if (err < 0) {
err = -errno;
err(uctrl->udev, "listen failed: %m\n");
return err;
}
uctrl->bound = true;
}
return 0;
}
+59 -40
View File
@@ -50,6 +50,7 @@ struct udev_monitor {
socklen_t addrlen;
struct udev_list_node filter_subsystem_list;
struct udev_list_node filter_tag_list;
bool bound;
};
enum udev_monitor_netlink_group {
@@ -155,6 +156,50 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char
return udev_monitor;
}
struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
{
struct udev_monitor *udev_monitor;
unsigned int group;
if (udev == NULL)
return NULL;
if (name == NULL)
group = UDEV_MONITOR_NONE;
else if (strcmp(name, "udev") == 0)
group = UDEV_MONITOR_UDEV;
else if (strcmp(name, "kernel") == 0)
group = UDEV_MONITOR_KERNEL;
else
return NULL;
udev_monitor = udev_monitor_new(udev);
if (udev_monitor == NULL)
return NULL;
if (fd < 0) {
udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (udev_monitor->sock == -1) {
err(udev, "error getting socket: %m\n");
free(udev_monitor);
return NULL;
}
} else {
udev_monitor->bound = true;
udev_monitor->sock = fd;
}
udev_monitor->snl.nl_family = AF_NETLINK;
udev_monitor->snl.nl_groups = group;
/* default destination for sending */
udev_monitor->snl_destination.nl_family = AF_NETLINK;
udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
return udev_monitor;
}
/**
* udev_monitor_new_from_netlink:
* @udev: udev library context
@@ -182,41 +227,7 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char
**/
struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
{
struct udev_monitor *udev_monitor;
unsigned int group;
if (udev == NULL)
return NULL;
if (name == NULL)
group = UDEV_MONITOR_NONE;
else if (strcmp(name, "udev") == 0)
group = UDEV_MONITOR_UDEV;
else if (strcmp(name, "kernel") == 0)
group = UDEV_MONITOR_KERNEL;
else
return NULL;
udev_monitor = udev_monitor_new(udev);
if (udev_monitor == NULL)
return NULL;
udev_monitor->sock = socket(PF_NETLINK, SOCK_DGRAM|SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (udev_monitor->sock == -1) {
err(udev, "error getting socket: %m\n");
free(udev_monitor);
return NULL;
}
udev_monitor->snl.nl_family = AF_NETLINK;
udev_monitor->snl.nl_groups = group;
/* default destination for sending */
udev_monitor->snl_destination.nl_family = AF_NETLINK;
udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
return udev_monitor;
return udev_monitor_new_from_netlink_fd(udev, name, -1);
}
static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
@@ -364,16 +375,24 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct
*/
int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
{
int err;
int err = 0;
const int on = 1;
if (udev_monitor->sun.sun_family != 0) {
err = bind(udev_monitor->sock,
(struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
if (!udev_monitor->bound) {
err = bind(udev_monitor->sock,
(struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
if (err == 0)
udev_monitor->bound = true;
}
} else if (udev_monitor->snl.nl_family != 0) {
udev_monitor_filter_update(udev_monitor);
err = bind(udev_monitor->sock,
(struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
if (!udev_monitor->bound) {
err = bind(udev_monitor->sock,
(struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
if (err == 0)
udev_monitor->bound = true;
}
if (err == 0) {
struct sockaddr_nl snl;
socklen_t addrlen;
+2 -1
View File
@@ -122,11 +122,12 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender);
int udev_monitor_send_device(struct udev_monitor *udev_monitor,
struct udev_monitor *destination, struct udev_device *udev_device);
struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd);
/* libudev-ctrl.c - daemon runtime setup */
struct udev_ctrl;
struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path);
struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd);
struct udev_ctrl *udev_ctrl_new_from_socket_fd(struct udev *udev, const char *socket_path, int fd);
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
+81 -17
View File
@@ -1099,6 +1099,42 @@ static int convert_db(struct udev *udev)
return 0;
}
static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink)
{
int ctrl = -1, netlink = -1;
int fd, n;
n = sd_listen_fds(true);
if (n <= 0)
return -1;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
if (ctrl >= 0)
return -1;
ctrl = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
if (netlink >= 0)
return -1;
netlink = fd;
continue;
}
return -1;
}
if (ctrl < 0 || netlink < 0)
return -1;
info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink);
*rctrl = ctrl;
*rnetlink = netlink;
return 0;
}
int main(int argc, char *argv[])
{
struct udev *udev;
@@ -1277,34 +1313,57 @@ int main(int argc, char *argv[])
}
}
/* udevadm control socket */
if (sd_listen_fds(true) == 1 && sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_SEQPACKET, -1))
udev_ctrl = udev_ctrl_new_from_fd(udev, SD_LISTEN_FDS_START);
else
if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
/* get control and netlink socket from from systemd */
udev_ctrl = udev_ctrl_new_from_socket_fd(udev, UDEV_CTRL_SOCK_PATH, fd_ctrl);
if (udev_ctrl == NULL) {
err(udev, "error taking over udev control socket");
rc = 1;
goto exit;
}
monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
if (monitor == NULL) {
err(udev, "error taking over netlink socket\n");
rc = 3;
goto exit;
}
} else {
/* open control and netlink socket */
udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH);
if (udev_ctrl == NULL) {
fprintf(stderr, "error initializing udev control socket");
err(udev, "error initializing udev control socket");
rc = 1;
if (udev_ctrl == NULL) {
fprintf(stderr, "error initializing udev control socket");
err(udev, "error initializing udev control socket");
rc = 1;
goto exit;
}
fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
monitor = udev_monitor_new_from_netlink(udev, "kernel");
if (monitor == NULL) {
fprintf(stderr, "error initializing netlink socket\n");
err(udev, "error initializing netlink socket\n");
rc = 3;
goto exit;
}
fd_netlink = udev_monitor_get_fd(monitor);
}
if (udev_monitor_enable_receiving(monitor) < 0) {
fprintf(stderr, "error binding netlink socket\n");
err(udev, "error binding netlink socket\n");
rc = 3;
goto exit;
}
if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
fprintf(stderr, "error binding udev control socket\n");
err(udev, "error binding udev control socket\n");
rc = 1;
goto exit;
}
fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
monitor = udev_monitor_new_from_netlink(udev, "kernel");
if (monitor == NULL || udev_monitor_enable_receiving(monitor) < 0) {
fprintf(stderr, "error initializing netlink socket\n");
err(udev, "error initializing netlink socket\n");
rc = 3;
goto exit;
}
udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
fd_netlink = udev_monitor_get_fd(monitor);
if (daemonize) {
pid_t pid;
@@ -1428,18 +1487,23 @@ int main(int argc, char *argv[])
memset(&ep_ctrl, 0, sizeof(struct epoll_event));
ep_ctrl.events = EPOLLIN;
ep_ctrl.data.fd = fd_ctrl;
memset(&ep_inotify, 0, sizeof(struct epoll_event));
ep_inotify.events = EPOLLIN;
ep_inotify.data.fd = fd_inotify;
memset(&ep_signal, 0, sizeof(struct epoll_event));
ep_signal.events = EPOLLIN;
ep_signal.data.fd = fd_signal;
memset(&ep_netlink, 0, sizeof(struct epoll_event));
ep_netlink.events = EPOLLIN;
ep_netlink.data.fd = fd_netlink;
memset(&ep_worker, 0, sizeof(struct epoll_event));
ep_worker.events = EPOLLIN;
ep_worker.data.fd = fd_worker;
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
err(udev, "error creating epoll fd: %m\n");