From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hannes Reinecke Date: Fri, 14 Jan 2005 11:22:36 +0000 Subject: Re: [PATCH] use uevents in udevd Message-Id: <41E7AB7C.1080509@suse.de> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------090608060909090906050004" List-Id: References: <41E79D7A.2060607@suse.de> In-Reply-To: <41E79D7A.2060607@suse.de> To: linux-hotplug@vger.kernel.org This is a multi-part message in MIME format. --------------090608060909090906050004 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Kay Sievers wrote: > On Fri, 2005-01-14 at 11:22 +0100, Hannes Reinecke wrote: >=20 >>Hi all, >> >>this patch adds the capabilities to read uevents directly from the=20 >>kernel socket (CONFIG_KOBJECT_UEVENT=3Dy). >=20 >=20 > Heh, I just split up the message handling in udevd last week to possibl= y > plug in a second source of events. Nice work! >=20 > Shouldn't we ignore events with a SEQNUM from udevsend, if we get the > first one from the uevent? >=20 Indeed we should. I fixed the patch accordingly. (Hopefully correct; the list is scanned backwards, right?) >=20 >>The old behaviour is left in place, as with this we can still send=20 >>events manually. >=20 >=20 > ./drivers/input/input.c > ./drivers/pnp/pnpbios/core.c > ./drivers/s390/crypto/z90main.c >=20 > are still "broken" from that view. They bypass the driver core and don'= t > send any uevent. >=20 Oh s**t. Still? Time to lean on Vojtech to fix the input layer. Martin promised that z90main will be fixed, so no worries about that=20 one. Will have to check pnpbios. >=20 >>And I've added a command-line option '-d' to start udevd as a daemon. >=20 >=20 > It is already running, right? We should read /sys/kernel/hotplug_seqnum > and initialize the next expected event number too, if the self-daemoniz= e > is needed. >=20 Well, no. At least not necessarily. And doesn't matter anyway as it will exit if another daemon is already=20 running. -> There can be only one <- How does this expected event number thingie work? If we're presetting the expected number, what will happen to events=20 which might be fed from udevsend after startup of udevd? Especially interesting if the udevinitd approach is used ... >=20 >>Now we can do >>/sbin/udevd -p >=20 >=20 > -p? :) >=20 :-) -ENOCOFFEE Cheers, Hannes --=20 Dr. Hannes Reinecke hare@suse.de SuSE Linux AG S390 & zSeries Maxfeldstra=C3=9Fe 5 +49 911 74053 688 90409 N=C3=BCrnberg http://www.suse.de --------------090608060909090906050004 Content-Type: text/x-patch; name="udevd-uevent.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="udevd-uevent.patch" ===== udevd.c 1.59 vs edited ===== --- 1.59/udevd.c 2005-01-04 21:37:50 +01:00 +++ edited/udevd.c 2005-01-14 12:21:25 +01:00 @@ -35,6 +35,7 @@ #include #include #include +#include #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; @@ -110,6 +117,11 @@ /* sort message by sequence number into list */ list_for_each_entry_reverse(loop_msg, &msg_list, list) + if (loop_msg->seqnum == msg->seqnum) { + dbg("duplicate message seq %llu, ignoring", + msg->seqnum); + return; + } if (loop_msg->seqnum < msg->seqnum) break; @@ -376,6 +388,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 +542,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[] = { "UDEVD_DAEMON=1", 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 +715,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 +741,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 +759,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); } --------------090608060909090906050004-- ------------------------------------------------------- The SF.Net email is sponsored by: Beat the post-holiday blues Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek. It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel