chiark / gitweb /
send monitor events back to netlink socket
authorKay Sievers <kay.sievers@vrfy.org>
Sun, 29 Mar 2009 02:24:39 +0000 (04:24 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Sun, 29 Mar 2009 02:24:39 +0000 (04:24 +0200)
Instead of of our own private monitor socket, we send the
processed event back to our netlink socket, to the multicast
group 2 -- so any number of users can listen to udev events,
just like they can listen to kernel emitted events on group 1.

configure.ac
rules/rules.d/95-udev-late.rules
udev/lib/libudev-monitor.c
udev/lib/libudev.h
udev/udevadm-monitor.c
udev/udevd.c

index 001f338..3fd51ce 100644 (file)
@@ -15,9 +15,9 @@ AC_PREFIX_DEFAULT([/usr])
 test "$prefix" = NONE && test "$exec_prefix" = NONE && exec_prefix=
 
 dnl /* libudev version */
 test "$prefix" = NONE && test "$exec_prefix" = NONE && exec_prefix=
 
 dnl /* libudev version */
-LIBUDEV_LT_CURRENT=1
-LIBUDEV_LT_REVISION=1
-LIBUDEV_LT_AGE=1
+LIBUDEV_LT_CURRENT=2
+LIBUDEV_LT_REVISION=0
+LIBUDEV_LT_AGE=2
 AC_SUBST(LIBUDEV_LT_CURRENT)
 AC_SUBST(LIBUDEV_LT_REVISION)
 AC_SUBST(LIBUDEV_LT_AGE)
 AC_SUBST(LIBUDEV_LT_CURRENT)
 AC_SUBST(LIBUDEV_LT_REVISION)
 AC_SUBST(LIBUDEV_LT_AGE)
index 7207081..eca0faa 100644 (file)
@@ -2,7 +2,3 @@
 
 # run a command on remove events
 ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
 
 # run a command on remove events
 ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
-
-# event to be catched by udevmonitor
-RUN+="socket:@/org/kernel/udev/monitor"
-
index c0aa99c..b2f76c3 100644 (file)
@@ -29,6 +29,7 @@ struct udev_monitor {
        int refcount;
        int sock;
        struct sockaddr_nl snl;
        int refcount;
        int sock;
        struct sockaddr_nl snl;
+       struct sockaddr_nl snl_peer;
        struct sockaddr_un sun;
        socklen_t addrlen;
 };
        struct sockaddr_un sun;
        socklen_t addrlen;
 };
@@ -90,7 +91,7 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char
        return udev_monitor;
 }
 
        return udev_monitor;
 }
 
-struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev)
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, unsigned int group)
 {
        struct udev_monitor *udev_monitor;
 
 {
        struct udev_monitor *udev_monitor;
 
@@ -110,10 +111,11 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev)
        }
 
        udev_monitor->snl.nl_family = AF_NETLINK;
        }
 
        udev_monitor->snl.nl_family = AF_NETLINK;
-       udev_monitor->snl.nl_pid = getpid();
-       udev_monitor->snl.nl_groups = 1;
+       udev_monitor->snl.nl_groups = group;
+       udev_monitor->snl_peer.nl_family = AF_NETLINK;
+       udev_monitor->snl_peer.nl_groups = UDEV_MONITOR_UDEV;
 
 
-       dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT\n", udev_monitor);
+       dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
        return udev_monitor;
 }
 
        return udev_monitor;
 }
 
@@ -123,14 +125,16 @@ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
        const int on = 1;
 
        if (udev_monitor->snl.nl_family != 0) {
        const int on = 1;
 
        if (udev_monitor->snl.nl_family != 0) {
-               err = bind(udev_monitor->sock, (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
+               err = bind(udev_monitor->sock,
+                          (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
                if (err < 0) {
                        err(udev_monitor->udev, "bind failed: %m\n");
                        return err;
                }
                dbg(udev_monitor->udev, "monitor %p listening on netlink\n", udev_monitor);
        } else if (udev_monitor->sun.sun_family != 0) {
                if (err < 0) {
                        err(udev_monitor->udev, "bind failed: %m\n");
                        return err;
                }
                dbg(udev_monitor->udev, "monitor %p listening on netlink\n", udev_monitor);
        } else if (udev_monitor->sun.sun_family != 0) {
-               err = bind(udev_monitor->sock, (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
+               err = bind(udev_monitor->sock,
+                          (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
                if (err < 0) {
                        err(udev_monitor->udev, "bind failed: %m\n");
                        return err;
                if (err < 0) {
                        err(udev_monitor->udev, "bind failed: %m\n");
                        return err;
@@ -381,9 +385,18 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_devi
        len = udev_device_get_properties_monitor_buf(udev_device, &buf);
        if (len < 32)
                return -1;
        len = udev_device_get_properties_monitor_buf(udev_device, &buf);
        if (len < 32)
                return -1;
-       count = sendto(udev_monitor->sock,
-                      buf, len, 0,
-                      (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
+       if (udev_monitor->sun.sun_family != 0) {
+               count = sendto(udev_monitor->sock,
+                              buf, len, 0,
+                              (struct sockaddr *)&udev_monitor->sun,
+                              udev_monitor->addrlen);
+       } else {
+               /* no destination besides the muticast group, we will always get -1 ECONNREFUSED */
+               count = sendto(udev_monitor->sock,
+                              buf, len, 0,
+                              (struct sockaddr *)&udev_monitor->snl_peer,
+                              sizeof(struct sockaddr_nl));
+       }
        info(udev_monitor->udev, "passed %zi bytes to monitor %p, \n", count, udev_monitor);
        return count;
 }
        info(udev_monitor->udev, "passed %zi bytes to monitor %p, \n", count, udev_monitor);
        return count;
 }
index a5d2c22..be09ddb 100644 (file)
@@ -76,8 +76,12 @@ extern const char *udev_device_get_sysattr_value(struct udev_device *udev_device
 
 /* udev and kernel device events */
 struct udev_monitor;
 
 /* udev and kernel device events */
 struct udev_monitor;
+enum udev_monitor_netlink_group {
+       UDEV_MONITOR_KERNEL     = 1,
+       UDEV_MONITOR_UDEV       = 2,
+};
 extern struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
 extern struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
-extern struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev);
+extern struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, enum udev_monitor_netlink_group group);
 extern int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
 extern struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
 extern void udev_monitor_unref(struct udev_monitor *udev_monitor);
 extern int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
 extern struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
 extern void udev_monitor_unref(struct udev_monitor *udev_monitor);
index 9be02da..43c1cc1 100644 (file)
@@ -115,11 +115,6 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
                print_udev =1;
        }
 
                print_udev =1;
        }
 
-       if (getuid() != 0 && print_kernel) {
-               fprintf(stderr, "root privileges needed to subscribe to kernel events\n");
-               goto out;
-       }
-
        /* set signal handlers */
        memset(&act, 0x00, sizeof(struct sigaction));
        act.sa_handler = (void (*)(int)) sig_handler;
        /* set signal handlers */
        memset(&act, 0x00, sizeof(struct sigaction));
        act.sa_handler = (void (*)(int)) sig_handler;
@@ -130,7 +125,7 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 
        printf("monitor will print the received events for:\n");
        if (print_udev) {
 
        printf("monitor will print the received events for:\n");
        if (print_udev) {
-               udev_monitor = udev_monitor_new_from_socket(udev, "@/org/kernel/udev/monitor");
+               udev_monitor = udev_monitor_new_from_netlink(udev, UDEV_MONITOR_UDEV);
                if (udev_monitor == NULL) {
                        rc = 1;
                        goto out;
                if (udev_monitor == NULL) {
                        rc = 1;
                        goto out;
@@ -142,8 +137,9 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
                printf("UDEV - the event which udev sends out after rule processing\n");
        }
        if (print_kernel) {
                printf("UDEV - the event which udev sends out after rule processing\n");
        }
        if (print_kernel) {
-               kernel_monitor = udev_monitor_new_from_netlink(udev);
+               kernel_monitor = udev_monitor_new_from_netlink(udev, UDEV_MONITOR_KERNEL);
                if (kernel_monitor == NULL) {
                if (kernel_monitor == NULL) {
+                       fprintf(stderr, "unable to subscribe to kernel events\n");
                        rc = 3;
                        goto out;
                }
                        rc = 3;
                        goto out;
                }
index 291655e..d9de26e 100644 (file)
@@ -195,7 +195,6 @@ static void event_fork(struct udev_event *event)
        switch (pid) {
        case 0:
                /* child */
        switch (pid) {
        case 0:
                /* child */
-               udev_monitor_unref(kernel_monitor);
                udev_ctrl_unref(udev_ctrl);
                logging_close();
                logging_init("udevd-event");
                udev_ctrl_unref(udev_ctrl);
                logging_close();
                logging_init("udevd-event");
@@ -235,6 +234,9 @@ static void event_fork(struct udev_event *event)
                        udev_device_update_db(event->dev);
                }
 
                        udev_device_update_db(event->dev);
                }
 
+               /* send processed event back to the kernel netlink socket */
+               udev_monitor_send_device(kernel_monitor, event->dev);
+
                info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err);
                logging_close();
                if (err != 0)
                info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err);
                logging_close();
                if (err != 0)
@@ -811,7 +813,7 @@ int main(int argc, char *argv[])
                goto exit;
        }
 
                goto exit;
        }
 
-       kernel_monitor = udev_monitor_new_from_netlink(udev);
+       kernel_monitor = udev_monitor_new_from_netlink(udev, UDEV_MONITOR_KERNEL);
        if (kernel_monitor == NULL || udev_monitor_enable_receiving(kernel_monitor) < 0) {
                fprintf(stderr, "error initializing netlink socket\n");
                err(udev, "error initializing netlink socket\n");
        if (kernel_monitor == NULL || udev_monitor_enable_receiving(kernel_monitor) < 0) {
                fprintf(stderr, "error initializing netlink socket\n");
                err(udev, "error initializing netlink socket\n");