From 7459bcdc8d12fdb217efd4a27a509f9f87ec7b1e Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 14 Apr 2011 23:46:44 +0200 Subject: [PATCH] udevd: get netlink socket from systemd --- init/udev.service.in | 1 + init/udev.socket | 1 + libudev/libudev-ctrl.c | 34 +++++++------- libudev/libudev-monitor.c | 99 +++++++++++++++++++++++---------------- libudev/libudev-private.h | 3 +- udev/udevd.c | 98 +++++++++++++++++++++++++++++++------- 6 files changed, 162 insertions(+), 74 deletions(-) diff --git a/init/udev.service.in b/init/udev.service.in index 345aa3f25b..117f5c8fd5 100644 --- a/init/udev.service.in +++ b/init/udev.service.in @@ -8,4 +8,5 @@ DefaultDependencies=no [Service] Type=notify OOMScoreAdjust=-1000 +Restart=on-failure ExecStart=@sbindir@/udevd diff --git a/init/udev.socket b/init/udev.socket index 81296306ac..12557be307 100644 --- a/init/udev.socket +++ b/init/udev.socket @@ -4,3 +4,4 @@ DefaultDependencies=no [Socket] ListenSequentialPacket=@/org/kernel/udev/udevd +ListenNetlink=kobject-uevent 1 diff --git a/libudev/libudev-ctrl.c b/libudev/libudev-ctrl.c index 2d2dd3a0be..7fa2d1d535 100644 --- a/libudev/libudev-ctrl.c +++ b/libudev/libudev-ctrl.c @@ -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; } diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c index c97f6faa65..5d9e155722 100644 --- a/libudev/libudev-monitor.c +++ b/libudev/libudev-monitor.c @@ -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; diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index e82ca1d753..63eb0704d6 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -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); diff --git a/udev/udevd.c b/udev/udevd.c index dbb1e16004..b30a27bf71 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -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");