diff options
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | udevcontrol.c | 107 | ||||
-rw-r--r-- | udevd.c | 167 | ||||
-rw-r--r-- | udevd.h | 23 | ||||
-rw-r--r-- | udevsend.c | 9 |
5 files changed, 230 insertions, 88 deletions
@@ -44,6 +44,7 @@ V=false ROOT = udev DAEMON = udevd SENDER = udevsend +CONTROL = udevcontrol INFO = udevinfo TESTER = udevtest STARTER = udevstart @@ -205,7 +206,7 @@ endif # config files automatically generated GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf -all: $(ROOT) $(SENDER) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) +all: $(ROOT) $(SENDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ $(MAKE) prefix=$(prefix) \ @@ -271,6 +272,7 @@ $(TESTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(INFO).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(DAEMON).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(SENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(CONTROL).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(STARTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(ROOT): $(KLCC) $(ROOT).o $(OBJS) $(HEADERS) $(GEN_MANPAGES) @@ -293,6 +295,10 @@ $(SENDER): $(KLCC) $(SENDER).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(SENDER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ +$(CONTROL): $(KLCC) $(CONTROL).o $(OBJS) udevd.h + $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CONTROL).o $(OBJS) $(LIB_OBJS) + $(QUIET) $(STRIPCMD) $@ + $(STARTER): $(KLCC) $(STARTER).o $(OBJS) $(QUIET) $(LD) $(LDFLAGS) -o $@ $(STARTER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ @@ -304,7 +310,7 @@ clean: -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | xargs rm -f -rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(GEN_MANPAGES) $(INFO) $(DAEMON) \ - $(SENDER) $(TESTER) $(STARTER) + $(SENDER) $(CONTROL) $(TESTER) $(STARTER) -rm -f ccdv $(MAKE) -C klibc SUBDIRS=klibc clean @extras="$(EXTRAS)" ; for target in $$extras ; do \ @@ -364,6 +370,7 @@ install: install-config install-man install-dev.d all $(INSTALL_PROGRAM) -D $(ROOT) $(DESTDIR)$(sbindir)/$(ROOT) $(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON) $(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER) + $(INSTALL_PROGRAM) -D $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL) $(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO) $(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER) $(INSTALL_PROGRAM) -D $(STARTER) $(DESTDIR)$(sbindir)/$(STARTER) @@ -387,6 +394,7 @@ uninstall: uninstall-man uninstall-dev.d - rm $(sbindir)/$(ROOT) - rm $(sbindir)/$(DAEMON) - rm $(sbindir)/$(SENDER) + - rm $(sbindir)/$(CONTROL) - rm $(sbindir)/$(STARTER) - rm $(usrbindir)/$(INFO) - rm $(usrbindir)/$(TESTER) diff --git a/udevcontrol.c b/udevcontrol.c new file mode 100644 index 0000000000..6a278a04c1 --- /dev/null +++ b/udevcontrol.c @@ -0,0 +1,107 @@ +/* + * udevcontrol.c + * + * Userspace devfs + * + * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <time.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <linux/stddef.h> + +#include "udev.h" +#include "udev_version.h" +#include "udevd.h" +#include "logging.h" + +/* global variables */ +static int sock = -1; + +#ifdef USE_LOG +void log_message (int level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsyslog(level, format, args); + va_end(args); +} +#endif + + +int main(int argc, char *argv[], char *envp[]) +{ + static struct udevd_msg usend_msg; + struct sockaddr_un saddr; + socklen_t addrlen; + int retval = 1; + + logging_init("udevcontrol"); + dbg("version %s", UDEV_VERSION); + + if (argc != 2) { + info("usage: udevcontrol <cmd>\n"); + goto exit; + } + + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); + strcpy(usend_msg.magic, UDEV_MAGIC); + + if (strstr(argv[1], "stop_exec_queue")) + usend_msg.type = UDEVD_STOP_EXEC_QUEUE; + else if (strstr(argv[1], "start_exec_queue")) + usend_msg.type = UDEVD_START_EXEC_QUEUE; + else { + info("unknown command\n"); + goto exit; + } + + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sock == -1) { + info("error getting socket"); + goto exit; + } + + memset(&saddr, 0x00, sizeof(struct sockaddr_un)); + 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; + + + retval = sendto(sock, &usend_msg, sizeof(usend_msg), 0, (struct sockaddr *)&saddr, addrlen); + if (retval == -1) + info("error sending message (%s)", strerror(errno)); + + close(sock); + +exit: + logging_close(); + + return retval; +} @@ -49,17 +49,18 @@ #include "logging.h" /* global variables*/ -static int udevsendsock; -static int ueventsock; +static int udevd_sock; +static int uevent_nl_sock; static pid_t sid; static int pipefds[2]; static long startup_time; -static unsigned long long expected_seqnum = 0; +static unsigned long long expected_seqnum; static volatile int sigchilds_waiting; static volatile int run_msg_q; static volatile int sig_flag; static int run_exec_q; +static int stop_exec_q; static LIST_HEAD(msg_list); static LIST_HEAD(exec_list); @@ -88,23 +89,23 @@ void log_message (int priority, const char *format, ...) static void msg_dump_queue(void) { #ifdef DEBUG - struct hotplug_msg *msg; + struct uevent_msg *msg; list_for_each_entry(msg, &msg_list, node) dbg("sequence %llu in queue", msg->seqnum); #endif } -static void run_queue_delete(struct hotplug_msg *msg) +static void run_queue_delete(struct uevent_msg *msg) { list_del(&msg->node); free(msg); } /* orders the message in the queue by sequence number */ -static void msg_queue_insert(struct hotplug_msg *msg) +static void msg_queue_insert(struct uevent_msg *msg) { - struct hotplug_msg *loop_msg; + struct uevent_msg *loop_msg; struct sysinfo info; if (msg->seqnum == 0) { @@ -148,7 +149,7 @@ static void msg_queue_insert(struct hotplug_msg *msg) } /* forks event and removes event from run queue when finished */ -static void execute_udev(struct hotplug_msg *msg) +static void execute_udev(struct uevent_msg *msg) { char *const argv[] = { "udev", msg->subsystem, NULL }; pid_t pid; @@ -157,9 +158,9 @@ static void execute_udev(struct hotplug_msg *msg) switch (pid) { case 0: /* child */ - if (ueventsock != -1) - close(ueventsock); - close(udevsendsock); + if (uevent_nl_sock != -1) + close(uevent_nl_sock); + close(udevd_sock); logging_close(); setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); @@ -298,9 +299,9 @@ static int compare_devpath(const char *running, const char *waiting) } /* returns still running task for the same device, its parent or its physical device */ -static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg) +static struct uevent_msg *running_with_devpath(struct uevent_msg *msg) { - struct hotplug_msg *loop_msg; + struct uevent_msg *loop_msg; if (msg->devpath == NULL) return NULL; @@ -329,9 +330,9 @@ static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg) /* exec queue management routine executes the events and serializes events in the same sequence */ static void exec_queue_manager(void) { - struct hotplug_msg *loop_msg; - struct hotplug_msg *tmp_msg; - struct hotplug_msg *msg; + struct uevent_msg *loop_msg; + struct uevent_msg *tmp_msg; + struct uevent_msg *msg; int running; running = running_processes(); @@ -364,7 +365,7 @@ static void exec_queue_manager(void) } } -static void msg_move_exec(struct hotplug_msg *msg) +static void msg_move_exec(struct uevent_msg *msg) { list_move_tail(&msg->node, &exec_list); run_exec_q = 1; @@ -376,8 +377,8 @@ static void msg_move_exec(struct hotplug_msg *msg) /* msg queue management routine handles the timeouts and dispatches the events */ static void msg_queue_manager(void) { - struct hotplug_msg *loop_msg; - struct hotplug_msg *tmp_msg; + struct uevent_msg *loop_msg; + struct uevent_msg *tmp_msg; struct sysinfo info; long msg_age = 0; static int timeout = EVENT_INIT_TIMEOUT_SEC; @@ -421,21 +422,21 @@ recheck: } } -static struct hotplug_msg *get_msg_from_envbuf(const char *buf, int buf_size) +static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size) { int bufpos; int i; - struct hotplug_msg *msg; + struct uevent_msg *msg; - msg = malloc(sizeof(struct hotplug_msg) + buf_size); + msg = malloc(sizeof(struct uevent_msg) + buf_size); if (msg == NULL) return NULL; - memset(msg, 0x00, sizeof(struct hotplug_msg) + buf_size); + memset(msg, 0x00, sizeof(struct uevent_msg) + buf_size); /* copy environment buffer and reconstruct envp */ memcpy(msg->envbuf, buf, buf_size); bufpos = 0; - for (i = 0; (bufpos < buf_size) && (i < HOTPLUG_NUM_ENVP-2); i++) { + for (i = 0; (bufpos < buf_size) && (i < UEVENT_NUM_ENVP-2); i++) { int keylen; char *key; @@ -470,11 +471,11 @@ static struct hotplug_msg *get_msg_from_envbuf(const char *buf, int buf_size) return msg; } -/* receive the udevsend message and do some sanity checks */ -static struct hotplug_msg *get_udevsend_msg(void) +/* receive the udevd message from userspace */ +static struct uevent_msg *get_udevd_msg(void) { - static struct udevsend_msg usend_msg; - struct hotplug_msg *msg; + static struct udevd_msg usend_msg; + struct uevent_msg *msg; ssize_t size; struct msghdr smsg; struct cmsghdr *cmsg; @@ -483,9 +484,9 @@ static struct hotplug_msg *get_udevsend_msg(void) char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; int envbuf_size; - memset(&usend_msg, 0x00, sizeof(struct udevsend_msg)); + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); iov.iov_base = &usend_msg; - iov.iov_len = sizeof(struct udevsend_msg); + iov.iov_len = sizeof(struct udevd_msg); memset(&smsg, 0x00, sizeof(struct msghdr)); smsg.msg_iov = &iov; @@ -493,10 +494,10 @@ static struct hotplug_msg *get_udevsend_msg(void) smsg.msg_control = cred_msg; smsg.msg_controllen = sizeof(cred_msg); - size = recvmsg(udevsendsock, &smsg, 0); + size = recvmsg(udevd_sock, &smsg, 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevsend message"); + dbg("unable to receive udevd message"); return NULL; } cmsg = CMSG_FIRSTHDR(&smsg); @@ -517,28 +518,43 @@ static struct hotplug_msg *get_udevsend_msg(void) return NULL; } - envbuf_size = size - offsetof(struct udevsend_msg, envbuf); - dbg("envbuf_size=%i", envbuf_size); - msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); - if (msg == NULL) - return NULL; - - return msg; +switch (usend_msg.type) { + case UDEVD_UEVENT: + dbg("udevd message (UEVENT) received"); + envbuf_size = size - offsetof(struct udevd_msg, envbuf); + dbg("envbuf_size=%i", envbuf_size); + msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); + if (msg == NULL) + return NULL; + return msg; + case UDEVD_STOP_EXEC_QUEUE: + dbg("udevd message (STOP_EXEC_QUEUE) received"); + stop_exec_q = 1; + break; + case UDEVD_START_EXEC_QUEUE: + dbg("udevd message (START_EXEC_QUEUE) received"); + stop_exec_q = 0; + exec_queue_manager(); + break; + default: + dbg("unknown message type"); + } + return NULL; } /* receive the kernel user event message and do some sanity checks */ -static struct hotplug_msg *get_uevent_msg(void) +static struct uevent_msg *get_uevent_msg(void) { - struct hotplug_msg *msg; + struct uevent_msg *msg; int bufpos; ssize_t size; - static char buffer[HOTPLUG_BUFFER_SIZE + 512]; + static char buffer[UEVENT_BUFFER_SIZE + 512]; char *pos; - size = recv(ueventsock, &buffer, sizeof(buffer), 0); + size = recv(uevent_nl_sock, &buffer, sizeof(buffer), 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevsend message"); + dbg("unable to receive udevd message"); return NULL; } @@ -612,7 +628,7 @@ do_write: static void udev_done(int pid) { /* find msg associated with pid and delete it */ - struct hotplug_msg *msg; + struct uevent_msg *msg; list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { @@ -655,7 +671,7 @@ static void user_sighandler(void) } } -static int init_udevsend_socket(void) +static int init_udevd_socket(void) { struct sockaddr_un saddr; socklen_t addrlen; @@ -668,27 +684,27 @@ static int init_udevsend_socket(void) 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) { + udevd_sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (udevd_sock == -1) { err("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); + retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen); if (retval < 0) { err("bind failed, %s", strerror(errno)); - close(udevsendsock); + close(udevd_sock); return -1; } /* enable receiving of the sender credentials */ - setsockopt(udevsendsock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); + setsockopt(udevd_sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); return 0; } -static int init_uevent_socket(void) +static int init_uevent_nl_sock(void) { struct sockaddr_nl snl; int retval; @@ -698,18 +714,18 @@ static int init_uevent_socket(void) snl.nl_pid = getpid(); snl.nl_groups = 0xffffffff; - ueventsock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (ueventsock == -1) { + uevent_nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (uevent_nl_sock == -1) { dbg("error getting socket, %s", strerror(errno)); return -1; } - retval = bind(ueventsock, (struct sockaddr *) &snl, + retval = bind(uevent_nl_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl)); if (retval < 0) { dbg("bind failed, %s", strerror(errno)); - close(ueventsock); - ueventsock = -1; + close(uevent_nl_sock); + uevent_nl_sock = -1; return -1; } @@ -725,7 +741,7 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *udevd_expected_seqnum; - int uevent_active = 0; + int uevent_nl_active = 0; logging_init("udevd"); udev_init_config(); @@ -811,15 +827,15 @@ int main(int argc, char *argv[], char *envp[]) sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); - if (init_uevent_socket() < 0) { + if (init_uevent_nl_sock() < 0) { dbg("uevent socket not available"); } - if (init_udevsend_socket() < 0) { + if (init_udevd_socket() < 0) { if (errno == EADDRINUSE) dbg("another udevd running, exit"); else - dbg("error initialising udevsend socket: %s", strerror(errno)); + dbg("error initialising udevd socket: %s", strerror(errno)); goto exit; } @@ -843,13 +859,13 @@ int main(int argc, char *argv[], char *envp[]) startup_time = info.uptime; FD_ZERO(&readfds); - FD_SET(udevsendsock, &readfds); - if (ueventsock != -1) - FD_SET(ueventsock, &readfds); + FD_SET(udevd_sock, &readfds); + if (uevent_nl_sock != -1) + FD_SET(uevent_nl_sock, &readfds); FD_SET(pipefds[0], &readfds); - maxsockplus = udevsendsock+1; + maxsockplus = udevd_sock+1; while (1) { - struct hotplug_msg *msg; + struct uevent_msg *msg; fd_set workreadfds = readfds; retval = select(maxsockplus, &workreadfds, NULL, NULL, NULL); @@ -860,12 +876,12 @@ int main(int argc, char *argv[], char *envp[]) continue; } - if (FD_ISSET(udevsendsock, &workreadfds)) { - msg = get_udevsend_msg(); + if (FD_ISSET(udevd_sock, &workreadfds)) { + msg = get_udevd_msg(); if (msg) { /* discard kernel messages if netlink is active */ - if (uevent_active && msg->seqnum != 0) { - dbg("skip kernel udevsend message, netlink is active"); + if (uevent_nl_active && msg->seqnum != 0) { + dbg("skip uevent_helper message, netlink is active"); free(msg); continue; } @@ -873,14 +889,14 @@ int main(int argc, char *argv[], char *envp[]) } } - if (FD_ISSET(ueventsock, &workreadfds)) { + if (FD_ISSET(uevent_nl_sock, &workreadfds)) { msg = get_uevent_msg(); if (msg) { msg_queue_insert(msg); /* disable udevsend with first netlink message */ - if (!uevent_active) { - info("netlink message received, disable kernel udevsend messages"); - uevent_active = 1; + if (!uevent_nl_active) { + info("uevent_nl message received, disable uevent_helper messages"); + uevent_nl_active = 1; } } } @@ -906,7 +922,8 @@ int main(int argc, char *argv[], char *envp[]) } run_exec_q = 0; - exec_queue_manager(); + if (!stop_exec_q) + exec_queue_manager(); } } @@ -43,15 +43,24 @@ #define THROTTLE_MAX_RUNNING_CHILDS 10 /* environment buffer, should match the kernel's size in lib/kobject_uevent.h */ -#define HOTPLUG_BUFFER_SIZE 1024 -#define HOTPLUG_NUM_ENVP 32 +#define UEVENT_BUFFER_SIZE 1024 +#define UEVENT_NUM_ENVP 32 -struct udevsend_msg { - char magic[20]; - char envbuf[HOTPLUG_BUFFER_SIZE+256]; +enum udevd_msg_type { + UDEVD_UNKNOWN, + UDEVD_UEVENT, + UDEVD_STOP_EXEC_QUEUE, + UDEVD_START_EXEC_QUEUE, }; -struct hotplug_msg { + +struct udevd_msg { + char magic[32]; + enum udevd_msg_type type; + char envbuf[UEVENT_BUFFER_SIZE+512]; +}; + +struct uevent_msg { struct list_head node; pid_t pid; long queue_time; @@ -61,6 +70,6 @@ struct hotplug_msg { unsigned long long seqnum; char *physdevpath; unsigned int timeout; - char *envp[HOTPLUG_NUM_ENVP+1]; + char *envp[UEVENT_NUM_ENVP+1]; char envbuf[]; }; diff --git a/udevsend.c b/udevsend.c index 8915edacc8..2b92e659e2 100644 --- a/udevsend.c +++ b/udevsend.c @@ -115,7 +115,7 @@ static void run_udev(const char *subsystem) int main(int argc, char *argv[], char *envp[]) { - static struct udevsend_msg usend_msg; + static struct udevd_msg usend_msg; int usend_msg_len; int i; int loop; @@ -144,8 +144,9 @@ int main(int argc, char *argv[], char *envp[]) strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH); addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1; - memset(&usend_msg, 0x00, sizeof(struct udevsend_msg)); + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); + usend_msg.type = UDEVD_UEVENT; /* copy all keys to send buffer */ for (i = 0; envp[i]; i++) { @@ -161,7 +162,7 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } - if (bufpos + keylen >= HOTPLUG_BUFFER_SIZE-1) { + if (bufpos + keylen >= UEVENT_BUFFER_SIZE-1) { err("environment buffer too small, probably not called by the kernel"); continue; } @@ -180,7 +181,7 @@ int main(int argc, char *argv[], char *envp[]) dbg("add 'SUBSYSTEM=%s' to env[%i] buffer from argv", argv[1], i); } - usend_msg_len = offsetof(struct udevsend_msg, envbuf) + bufpos; + usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos; dbg("usend_msg_len=%i", usend_msg_len); /* If we can't send, try to start daemon and resend message */ |