listen to udev event via a socket
Pozsar Balazs
pozsy at uhulinux.hu
Tue Nov 22 09:21:21 PST 2005
Hi all,
Is (something like) the following patch planned to be merged?
I got it from mandriva, and it works well for me. Basically, the idea is
to listen to event arriving from udev via a socket, and not to spawn a
process every time an event occurs. The line
RUN+="/usr/libexec/hal.hotplug"
in the udev rules file should/can be replaced by:
RUN+="socket:/org/freedesktop/hal/udev_event"
after this patch.
Index: hald/linux2/osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/osspec.c,v
retrieving revision 1.28
diff -u -p -r1.28 osspec.c
--- hald/linux2/osspec.c 29 Jul 2005 20:32:57 -0000 1.28
+++ hald/linux2/osspec.c 1 Aug 2005 05:48:18 -0000
@@ -103,6 +103,143 @@ get_hal_proc_path (void)
}
static gboolean
+hald_udev_data (GIOChannel *source, GIOCondition condition, gpointer user_data)
+{
+ int fd;
+ int retval;
+ struct msghdr smsg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ struct ucred *cred;
+ char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+
+ char buf[2048];
+ size_t bufpos = 0;
+ const char *devpath = NULL;
+ const char *physdevpath = NULL;
+ const char *action = NULL;
+ const char *subsystem = NULL;
+ const char *devname = NULL;
+ int ifindex = -1;
+ unsigned long long seqnum = 0;
+
+ fd = g_io_channel_unix_get_fd (source);
+
+ iov.iov_base = &buf;
+ iov.iov_len = sizeof (buf);
+
+ memset(&smsg, 0x00, sizeof (struct msghdr));
+ smsg.msg_iov = &iov;
+ smsg.msg_iovlen = 1;
+ smsg.msg_control = cred_msg;
+ smsg.msg_controllen = sizeof (cred_msg);
+
+ retval = recvmsg (fd, &smsg, 0);
+ if (retval < 0) {
+ if (errno != EINTR)
+ HAL_INFO (("Unable to receive message, errno=%d", errno));
+ goto out;
+ }
+ cmsg = CMSG_FIRSTHDR (&smsg);
+ cred = (struct ucred *) CMSG_DATA (cmsg);
+
+ if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+ HAL_INFO (("No sender credentials received, message ignored"));
+ goto out;
+ }
+
+ if (cred->uid != 0) {
+ HAL_INFO (("Sender uid=%i, message ignored", cred->uid));
+ goto out;
+ }
+
+ if (!strstr(buf, "@/")) {
+ HAL_INFO (("invalid message format"));
+ goto out;
+ }
+
+ while (bufpos < sizeof (buf)) {
+ size_t keylen;
+ char *key;
+
+ key = &buf[bufpos];
+ keylen = strlen(key);
+ if (keylen == 0)
+ break;
+ bufpos += keylen + 1;
+
+ if (strncmp(key, "ACTION=", 7) == 0)
+ action = &key[7];
+ else if (strncmp(key, "DEVPATH=", 8) == 0)
+ devpath = &key[8];
+ else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
+ subsystem = &key[10];
+ else if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+ physdevpath = &key[12];
+ else if (strncmp(key, "DEVNAME=", 8) == 0)
+ devname = &key[8];
+ else if (strncmp(key, "SEQNUM=", 7) == 0)
+ seqnum = strtoull(&key[7], NULL, 10);
+ else if (strncmp(key, "IFINDEX=", 8) == 0)
+ ifindex = strtoul(&key[8], NULL, 10);
+ }
+
+ if (!devpath) {
+ HAL_INFO (("missing DEVPATH"));
+ goto out;
+ }
+ if (!action) {
+ HAL_INFO (("missing ACTION"));
+ goto out;
+ }
+ if (!subsystem) {
+ HAL_INFO (("missing SUSBSYSTEM"));
+ goto out;
+ }
+ if (!devname)
+ devname = "";
+
+ HAL_INFO (("SEQNUM=%lld, ACTION=%s, SUBSYS=%s, SYSFSPATH=%s, DEVNAME=%s, IFINDEX=%d",
+ seqnum, action, subsystem, devpath, devname, ifindex));
+
+ if (strcmp (action, "add") == 0) {
+ HotplugEvent *hotplug_event;
+
+ hotplug_event = g_new0 (HotplugEvent, 1);
+ hotplug_event->action = HOTPLUG_ACTION_ADD;
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+ g_strlcpy (hotplug_event->sysfs.subsystem, subsystem, sizeof (hotplug_event->sysfs.subsystem));
+ g_snprintf (hotplug_event->sysfs.sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path), "%s%s",
+ hal_sysfs_path, devpath);
+ g_strlcpy (hotplug_event->sysfs.device_file, devname, sizeof (hotplug_event->sysfs.device_file));
+ hotplug_event->sysfs.net_ifindex = ifindex;
+
+ /* queue up and process */
+ hotplug_event_enqueue (hotplug_event);
+ hotplug_event_process_queue ();
+
+ } else if (strcmp (action, "remove") == 0) {
+ HotplugEvent *hotplug_event;
+
+ hotplug_event = g_new0 (HotplugEvent, 1);
+ hotplug_event->action = HOTPLUG_ACTION_REMOVE;
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+ g_strlcpy (hotplug_event->sysfs.subsystem, subsystem, sizeof (hotplug_event->sysfs.subsystem));
+ g_snprintf (hotplug_event->sysfs.sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path), "%s%s",
+ hal_sysfs_path, devpath);
+ g_strlcpy (hotplug_event->sysfs.device_file, devname, sizeof (hotplug_event->sysfs.device_file));
+ hotplug_event->sysfs.net_ifindex = ifindex;
+
+ /* queue up and process */
+ hotplug_event_enqueue (hotplug_event);
+ hotplug_event_process_queue ();
+ }
+
+out:
+ return TRUE;
+}
+
+static gboolean
hald_helper_data (GIOChannel *source, GIOCondition condition, gpointer user_data)
{
struct hald_helper_msg msg;
@@ -188,7 +325,6 @@ hald_helper_data (GIOChannel *source, GI
hotplug_event_process_queue ();
}
-
out:
return TRUE;
}
@@ -311,39 +447,70 @@ hal_util_get_fs_mnt_path (const gchar *f
void
osspec_init (void)
{
- int socketfd;
+ int udev_socket;
+ int helper_socket;
struct sockaddr_un saddr;
socklen_t addrlen;
- GIOChannel *channel;
+ GIOChannel *udev_channel;
+ GIOChannel *helper_channel;
const int on = 1;
static int netlink_fd = -1;
struct sockaddr_nl netlink_addr;
GIOChannel *netlink_channel;
- /* setup socket for listening from datagrams from the hal.hotplug helper */
+ /*
+ * setup socket for listening from messages from udev
+ */
+ memset(&saddr, 0x00, sizeof(saddr));
+ saddr.sun_family = AF_LOCAL;
+ /* use abstract namespace for socket path */
+ strcpy(&saddr.sun_path[1], "/org/freedesktop/hal/udev_event");
+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+
+ udev_socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (udev_socket == -1) {
+ DIE (("Couldn't open socket"));
+ }
+
+ if (bind(udev_socket, (struct sockaddr *) &saddr, addrlen) < 0) {
+ fprintf (stderr, "Error binding udev_event socket: %s\n", strerror(errno));
+ exit (1);
+ }
+ /* enable receiving of the sender credentials */
+ setsockopt(udev_socket, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
+
+ udev_channel = g_io_channel_unix_new (udev_socket);
+ g_io_add_watch (udev_channel, G_IO_IN, hald_udev_data, NULL);
+ g_io_channel_unref (udev_channel);
+
+ /*
+ * setup socket for listening from datagrams from the hal.hotplug helper
+ */
memset(&saddr, 0x00, sizeof(saddr));
saddr.sun_family = AF_LOCAL;
/* use abstract namespace for socket path */
strcpy(&saddr.sun_path[1], HALD_HELPER_SOCKET_PATH);
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
- socketfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
- if (socketfd == -1) {
+ helper_socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (helper_socket == -1) {
DIE (("Couldn't open socket"));
}
- if (bind(socketfd, (struct sockaddr *) &saddr, addrlen) < 0) {
+ if (bind(helper_socket, (struct sockaddr *) &saddr, addrlen) < 0) {
fprintf (stderr, "Error binding to %s: %s\n", HALD_HELPER_SOCKET_PATH, strerror(errno));
exit (1);
}
/* enable receiving of the sender credentials */
- setsockopt(socketfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
+ setsockopt(helper_socket, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- channel = g_io_channel_unix_new (socketfd);
- g_io_add_watch (channel, G_IO_IN, hald_helper_data, NULL);
- g_io_channel_unref (channel);
+ helper_channel = g_io_channel_unix_new (helper_socket);
+ g_io_add_watch (helper_channel, G_IO_IN, hald_helper_data, NULL);
+ g_io_channel_unref (helper_channel);
- /* Get mount points for /proc and /sys */
+ /*
+ * get mount points for /proc and /sys
+ */
if (!hal_util_get_fs_mnt_path ("sysfs", hal_sysfs_path, sizeof (hal_sysfs_path))) {
HAL_ERROR (("Could not get sysfs mount point"));
goto error;
@@ -355,7 +522,8 @@ osspec_init (void)
}
HAL_INFO (("proc mount point is '%s'", hal_proc_path));
- /* hook up to netlink socket to receive events from the Kernel Events
+ /*
+ * hook up to netlink socket to receive events from the Kernel Events
* Layer (available since 2.6.10) - TODO: Don't use the constant 15 but
* rather the NETLINK_KOBJECT_UEVENT symbol
*/
@@ -379,7 +547,9 @@ osspec_init (void)
g_io_add_watch (netlink_channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL,
netlink_detection_data_ready, NULL);
- /* Load various hardware id databases */
+ /*
+ *Load various hardware id databases
+ */
ids_init ();
error:
More information about the hal
mailing list