chiark / gitweb /
udevd: get netlink socket from systemd
authorKay Sievers <kay.sievers@vrfy.org>
Thu, 14 Apr 2011 21:46:44 +0000 (23:46 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Thu, 14 Apr 2011 21:46:44 +0000 (23:46 +0200)
init/udev.service.in
init/udev.socket
libudev/libudev-ctrl.c
libudev/libudev-monitor.c
libudev/libudev-private.h
udev/udevd.c

index 345aa3f..117f5c8 100644 (file)
@@ -8,4 +8,5 @@ DefaultDependencies=no
 [Service]
 Type=notify
 OOMScoreAdjust=-1000
+Restart=on-failure
 ExecStart=@sbindir@/udevd
index 8129630..12557be 100644 (file)
@@ -4,3 +4,4 @@ DefaultDependencies=no
 
 [Socket]
 ListenSequentialPacket=@/org/kernel/udev/udevd
+ListenNetlink=kobject-uevent 1
index 2d2dd3a..7fa2d1d 100644 (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;
 }
index c97f6fa..5d9e155 100644 (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,32 +156,7 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char
        return udev_monitor;
 }
 
-/**
- * udev_monitor_new_from_netlink:
- * @udev: udev library context
- * @name: name of event source
- *
- * Create new udev monitor and connect to a specified event
- * source. Valid sources identifiers are "udev" and "kernel".
- *
- * Applications should usually not connect directly to the
- * "kernel" events, because the devices might not be useable
- * at that time, before udev has configured them, and created
- * device nodes.
- *
- * Accessing devices at the same time as udev, might result
- * in unpredictable behavior.
- *
- * The "udev" events are sent out after udev has finished its
- * event processing, all rules have been processed, and needed
- * device nodes are created.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev monitor.
- *
- * Returns: a new udev monitor, or #NULL, in case of an error
- **/
-struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
+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;
@@ -201,11 +177,16 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char
        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;
+       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;
@@ -219,6 +200,36 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char
        return udev_monitor;
 }
 
+/**
+ * udev_monitor_new_from_netlink:
+ * @udev: udev library context
+ * @name: name of event source
+ *
+ * Create new udev monitor and connect to a specified event
+ * source. Valid sources identifiers are "udev" and "kernel".
+ *
+ * Applications should usually not connect directly to the
+ * "kernel" events, because the devices might not be useable
+ * at that time, before udev has configured them, and created
+ * device nodes.
+ *
+ * Accessing devices at the same time as udev, might result
+ * in unpredictable behavior.
+ *
+ * The "udev" events are sent out after udev has finished its
+ * event processing, all rules have been processed, and needed
+ * device nodes are created.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev monitor.
+ *
+ * Returns: a new udev monitor, or #NULL, in case of an error
+ **/
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
+{
+       return udev_monitor_new_from_netlink_fd(udev, name, -1);
+}
+
 static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
                            unsigned short code, unsigned int data)
 {
@@ -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;
index e82ca1d..63eb070 100644 (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);
index dbb1e16..b30a27b 100644 (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");