===== 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); }