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