linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] use uevents in udevd
@ 2005-01-14 10:22 Hannes Reinecke
  2005-01-14 10:40 ` Marco d'Itri
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Hannes Reinecke @ 2005-01-14 10:22 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 636 bytes --]

Hi all,

this patch adds the capabilities to read uevents directly from the 
kernel socket (CONFIG_KOBJECT_UEVENT=y).
The old behaviour is left in place, as with this we can still send 
events manually.

And I've added a command-line option '-d' to start udevd as a daemon.
Now we can do

/sbin/udevd -p
echo -n "" > /proc/sys/kernel/hotplug

no need for udevsend anymore.
Plus we can finally do a load-limit for hotplug events.

Comments welcome.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke			hare@suse.de
SuSE Linux AG				S390 & zSeries
Maxfeldstraße 5				+49 911 74053 688
90409 Nürnberg				http://www.suse.de

[-- Attachment #2: udevd-uevent.patch --]
[-- Type: text/x-patch, Size: 6743 bytes --]

===== udevd.c 1.59 vs edited =====
--- 1.59/udevd.c	2005-01-04 21:37:50 +01:00
+++ edited/udevd.c	2005-01-14 11:13:51 +01:00
@@ -35,6 +35,7 @@
 #include <fcntl.h>
 #include <sys/sysinfo.h>
 #include <sys/stat.h>
+#include <linux/netlink.h>
 
 #include "list.h"
 #include "udev.h"
@@ -43,8 +44,14 @@
 #include "udevd.h"
 #include "logging.h"
 
+/* Older header files do not define this */
+#ifndef NETLINK_KOBJECT_UEVENT
+#define NETLINK_KOBJECT_UEVENT 15
+#endif
+
 /* global variables*/
 static int udevsendsock;
+static int ueventsock;
 
 static int pipefds[2];
 static long startup_time;
@@ -376,6 +383,83 @@
 	return msg;
 }
 
+#define UEVENT_BUFFER_SIZE		1024
+#define OBJECT_SIZE			512
+
+/* receive the kernel user event message and do some sanity checks */
+static struct hotplug_msg *get_uevent_msg(void)
+{
+	struct hotplug_msg *msg;
+	int bufpos;
+	int i;
+	ssize_t size;
+	char *pos;
+	static char buffer[UEVENT_BUFFER_SIZE + OBJECT_SIZE];
+
+	size = recv(ueventsock, &buffer, sizeof(buffer),0);
+	if (size <  0) {
+		if (errno != EINTR)
+			dbg("unable to receive udevsend message");
+		return NULL;
+	}
+
+	if ((size_t)size > sizeof(buffer)-1)
+	    size = sizeof(buffer)-1;
+	
+	buffer[size] = '\0';
+
+	dbg("uevent_size=%i", size);
+	msg = malloc(sizeof(struct hotplug_msg) + size);
+	if (msg == NULL)
+		return NULL;
+
+	memset(msg, 0x00, sizeof(struct hotplug_msg) + size);
+
+	/* copy environment buffer and reconstruct envp */
+	memcpy(msg->envbuf, buffer, size);
+
+	/* save start of payload */
+	bufpos = strlen(buffer) + 1;
+
+	/* action string */
+	msg->action = msg->envbuf;
+	pos = strchr(msg->envbuf, '@');
+	if (!pos) {
+		free(msg);
+		return NULL;
+	}
+	pos[0] = '\0';
+
+	/* sysfs path */
+	msg->devpath = &pos[1];
+
+
+	for (i = 0; (bufpos < size) && (i < HOTPLUG_NUM_ENVP-2); i++) {
+		int keylen;
+		char *key;
+
+		key = &msg->envbuf[bufpos];
+		keylen = strlen(key);
+		msg->envp[i] = key;
+		bufpos += keylen + 1;
+		dbg("add '%s' to msg.envp[%i]", msg->envp[i], i);
+
+		/* remember some keys for further processing */
+		if (strncmp(key, "SUBSYSTEM=", 10) == 0)
+			msg->subsystem = &key[10];
+
+		if (strncmp(key, "SEQNUM=", 7) == 0)
+			msg->seqnum = strtoull(&key[7], NULL, 10);
+
+		if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+			msg->physdevpath = &key[12];
+	}
+	msg->envp[i++] = "UDEVD_EVENT=1";
+	msg->envp[i] = NULL;
+
+	return msg;
+}
+
 static void asmlinkage sig_handler(int signum)
 {
 	int rc;
@@ -453,17 +537,114 @@
 	}
 }
 
+static int init_udevsend_socket(void)
+{
+	struct sockaddr_un saddr;
+	socklen_t addrlen;
+	const int feature_on = 1;
+	int retval;
+
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sun_family = AF_LOCAL;
+	/* use abstract namespace for socket path */
+	strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
+	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+
+	udevsendsock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (udevsendsock == -1) {
+		dbg("error getting socket, %s", strerror(errno));
+		return -1;
+	}
+
+	/* the bind takes care of ensuring only one copy running */
+	retval = bind(udevsendsock, (struct sockaddr *) &saddr, addrlen);
+	if (retval < 0) {
+		dbg("bind failed, %s", strerror(errno));
+		close(udevsendsock);
+		return -1;
+	}
+
+	/* enable receiving of the sender credentials */
+	setsockopt(udevsendsock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
+
+	return 0;
+}
+
+static int init_uevent_socket(void)
+{
+	struct sockaddr_nl snl;
+	int retval;
+
+	memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+	snl.nl_family = AF_NETLINK;
+	snl.nl_pid = getpid();
+	snl.nl_groups = 0xffffffff;
+
+	ueventsock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+	if (ueventsock == -1) {
+		dbg("error getting socket, %s", strerror(errno));
+		return -1;
+	}
+
+	retval = bind(ueventsock, (struct sockaddr *) &snl,
+		      sizeof(struct sockaddr_nl));
+	if (retval < 0) {
+		dbg("bind failed, %s", strerror(errno));
+		close(ueventsock);
+		ueventsock = -1;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int start_daemon(char *pathname)
+{
+	pid_t pid;
+	pid_t child_pid;
+	char *const argv[] = { "udevd", NULL };
+	char *const envp[] = { NULL };
+
+	pid = fork();
+	switch (pid) {
+	case 0:
+		/* helper child */
+		child_pid = fork();
+		switch (child_pid) {
+		case 0:
+			/* daemon with empty environment */
+			execve(pathname, argv, envp);
+			dbg("exec of daemon failed");
+			_exit(1);
+		case -1:
+			dbg("fork of daemon failed");
+			return -1;
+		default:
+			exit(0);
+		}
+		break;
+	case -1:
+		dbg("fork of helper failed");
+		return -1;
+	default:
+		waitpid(pid, NULL, 0);
+	}
+	return 0;
+}
+
 int main(int argc, char *argv[], char *envp[])
 {
 	struct sysinfo info;
 	int maxsockplus;
-	struct sockaddr_un saddr;
-	socklen_t addrlen;
 	int retval, fd;
-	const int feature_on = 1;
 	struct sigaction act;
 	fd_set readfds;
 
+	if (argc > 1 && strncmp(argv[1],"-d",2)) {
+		retval = start_daemon(argv[0]);
+		return retval;
+	}
+
 	logging_init("udevd");
 	dbg("version %s", UDEV_VERSION);
 
@@ -529,29 +710,19 @@
 	sigaction(SIGALRM, &act, NULL);
 	sigaction(SIGCHLD, &act, NULL);
 
-	memset(&saddr, 0x00, sizeof(saddr));
-	saddr.sun_family = AF_LOCAL;
-	/* use abstract namespace for socket path */
-	strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
-	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
-
-	udevsendsock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-	if (udevsendsock == -1) {
-		dbg("error getting socket, exit");
-		goto exit;
+	if (init_uevent_socket() < 0) {
+		dbg("uevent socket not available");
 	}
 
-	/* the bind takes care of ensuring only one copy running */
-	retval = bind(udevsendsock, (struct sockaddr *) &saddr, addrlen);
-	if (retval < 0) {
-		dbg("bind failed, exit");
-		close(udevsendsock);
+	if (init_udevsend_socket() < 0) {
+		if (errno == EADDRINUSE)
+			dbg("another udevd is running, exit");
+		else
+			dbg("error initialising udevsend socket: %s",
+			    strerror(errno));
 		goto exit;
 	}
 
-	/* enable receiving of the sender credentials */
-	setsockopt(udevsendsock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
-
 	/* possible override of udev binary, used for testing */
 	udev_bin = getenv("UDEV_BIN");
 	if (udev_bin != NULL)
@@ -565,6 +736,8 @@
 
 	FD_ZERO(&readfds);
 	FD_SET(udevsendsock, &readfds);
+	if (ueventsock != -1)
+		FD_SET(ueventsock, &readfds);
 	FD_SET(pipefds[0], &readfds);
 	maxsockplus = udevsendsock+1;
 	while (1) {
@@ -581,6 +754,12 @@
 
 		if (FD_ISSET(udevsendsock, &workreadfds)) {
 			msg = get_udevsend_msg();
+			if (msg)
+				msg_queue_insert(msg);
+		}
+
+		if (FD_ISSET(ueventsock, &workreadfds)) {
+			msg = get_uevent_msg();
 			if (msg)
 				msg_queue_insert(msg);
 		}

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2005-01-16 16:27 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-14 10:22 [PATCH] use uevents in udevd Hannes Reinecke
2005-01-14 10:40 ` Marco d'Itri
2005-01-14 10:55 ` Hannes Reinecke
2005-01-14 10:55 ` Kay Sievers
2005-01-14 11:00 ` Marco d'Itri
2005-01-14 11:22 ` Hannes Reinecke
2005-01-14 11:26 ` Hannes Reinecke
2005-01-14 11:37 ` Marco d'Itri
2005-01-14 12:11 ` Kay Sievers
2005-01-14 12:43 ` Kay Sievers
2005-01-14 13:01 ` Arnd Bergmann
2005-01-14 13:01 ` Hannes Reinecke
2005-01-14 13:08 ` Kay Sievers
2005-01-14 13:11 ` Arnd Bergmann
2005-01-14 13:12 ` Kay Sievers
2005-01-14 13:23 ` Hannes Reinecke
2005-01-14 13:35 ` Kay Sievers
2005-01-14 16:08 ` Hannes Reinecke
2005-01-16 16:27 ` Kay Sievers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).