From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hannes Reinecke Date: Fri, 14 Jan 2005 10:22:50 +0000 Subject: [PATCH] use uevents in udevd Message-Id: <41E79D7A.2060607@suse.de> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------090908020408020304070305" List-Id: To: linux-hotplug@vger.kernel.org This is a multi-part message in MIME format. --------------090908020408020304070305 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: quoted-printable Hi all, this patch adds the capabilities to read uevents directly from the=20 kernel socket (CONFIG_KOBJECT_UEVENT=3Dy). The old behaviour is left in place, as with this we can still send=20 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 --=20 Dr. Hannes Reinecke hare@suse.de SuSE Linux AG S390 & zSeries Maxfeldstra=DFe 5 +49 911 74053 688 90409 N=FCrnberg http://www.suse.de --------------090908020408020304070305 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 11:13:51 +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; @@ -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); } --------------090908020408020304070305-- ------------------------------------------------------- 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