diff options
-rw-r--r-- | test/udevd_test.sh | 49 | ||||
-rw-r--r-- | udevd.c | 129 | ||||
-rw-r--r-- | udevd.h | 6 | ||||
-rw-r--r-- | udevsend.c | 71 |
4 files changed, 133 insertions, 122 deletions
diff --git a/test/udevd_test.sh b/test/udevd_test.sh index 013cdb9d6c..0c7bd431be 100644 --- a/test/udevd_test.sh +++ b/test/udevd_test.sh @@ -1,47 +1,52 @@ #!/bin/bash -# reset udevd, expected sequence number and empty queue -killall -HUP udevd +# kill daemon, first event will start it again +killall udevd -export ACTION=add -export DEVPATH=/block/sda +# connect(123) - disconnect(456) - connect(789) sequence of sda/sdb/sdc export SEQNUM=1 +export ACTION=add +export DEVPATH=/block/sda ./udevsend block export SEQNUM=2 -./udevsend block - -export SEQNUM=3 -./udevsend block - -export SEQNUM=5 +export ACTION=add +export DEVPATH=/block/sdb ./udevsend block export SEQNUM=4 +export ACTION=remove +export DEVPATH=/block/sda ./udevsend block -export SEQNUM=6 +export SEQNUM=3 +export ACTION=add +export DEVPATH=/block/sdc ./udevsend block -export SEQNUM=7 +export SEQNUM=6 +export ACTION=remove +export DEVPATH=/block/sdc ./udevsend block -export SEQNUM=10 +export SEQNUM=5 +export ACTION=remove +export DEVPATH=/block/sdb ./udevsend block -export SEQNUM=9 -#./udevsend block - -export SEQNUM=8 +export SEQNUM=7 +export ACTION=add +export DEVPATH=/block/sda #./udevsend block -export SEQNUM=13 -./udevsend block - -export SEQNUM=12 +export SEQNUM=9 +export ACTION=add +export DEVPATH=/block/sdc ./udevsend block -export SEQNUM=11 +export SEQNUM=8 +export ACTION=add +export DEVPATH=/block/sdb ./udevsend block @@ -37,49 +37,20 @@ #include "udevd.h" #include "logging.h" -#define BUFFER_SIZE 1024 -#define TIMEOUT_SECONDS 10 - -static void reset_timer(void); -static void reset_queue(void); +#define BUFFER_SIZE 1024 +#define EVENT_TIMEOUT_SECONDS 10 +#define DAEMON_TIMEOUT_SECONDS 30 static int expect_seqnum = 0; -static int timeout_value = TIMEOUT_SECONDS; -static int timeout = 0; static struct hotplug_msg *head = NULL; -static char exec_program[100]; - - -static void sig_handler(int signum) -{ - dbg("caught signal %d", signum); - switch (signum) { - case SIGHUP: - dbg("reset requested, all waiting events killed"); - reset_timer(); - reset_queue(); - timeout = 0; - expect_seqnum = 0; - break; - - case SIGINT: - case SIGTERM: - case SIGKILL: - exit(20 + signum); - break; - default: - dbg("unhandled signal"); - } -} static void sig_alarmhandler(int signum) { dbg("caught signal %d", signum); switch (signum) { case SIGALRM: - timeout = 1; dbg("event timeout reached"); break; @@ -94,9 +65,9 @@ static void dump_queue(void) p = head; dbg("next expected sequence is %d", expect_seqnum); - while(p) { + while(p != NULL) { dbg("sequence %d in queue", p->seqnum); - p=p->next; + p = p->next; } } @@ -110,59 +81,37 @@ static int dispatch_msg(struct hotplug_msg *pmsg) { pid_t pid; char *argv[3]; - int retval; extern char **environ; dump_msg(pmsg); - dbg("exec '%s'", exec_program); setenv("ACTION", pmsg->action, 1); setenv("DEVPATH", pmsg->devpath, 1); - - argv[0] = exec_program; + argv[0] = DEFAULT_UDEV_EXEC; argv[1] = pmsg->subsystem; argv[2] = NULL; pid = fork(); switch (pid) { case 0: - retval = execve(argv[0], argv, environ); - if (retval != 0) { - dbg("child execve failed"); - exit(1); - } + /* child */ + execve(argv[0], argv, environ); + dbg("exec of child failed"); + exit(1); break; case -1: - dbg("fork failed"); + dbg("fork of child failed"); return -1; default: wait(0); - break; } return 0; } -static void reset_timer(void) -{ - alarm(0); -} - -static void set_timer(void) +static void set_timer(int seconds) { signal(SIGALRM, sig_alarmhandler); - alarm(timeout_value); -} - -static void reset_queue(void) -{ - struct hotplug_msg *p; - p = head; - - while(head) { - p = head; - head = head->next; - free(p); - } + alarm(seconds); } static void check_queue(void) @@ -171,7 +120,7 @@ static void check_queue(void) p = head; dump_queue(); - while(head && head->seqnum == expect_seqnum) { + while(head != NULL && head->seqnum == expect_seqnum) { dispatch_msg(head); expect_seqnum++; p = head; @@ -179,9 +128,9 @@ static void check_queue(void) free(p); } if (head != NULL) - set_timer(); + set_timer(EVENT_TIMEOUT_SECONDS); else - reset_timer(); + set_timer(DAEMON_TIMEOUT_SECONDS); } static void add_queue(struct hotplug_msg *pmsg) @@ -195,7 +144,7 @@ static void add_queue(struct hotplug_msg *pmsg) pnewmsg = malloc(sizeof(struct hotplug_msg)); *pnewmsg = *pmsg; pnewmsg->next = NULL; - while(p && pmsg->seqnum > p->seqnum) { + while(p != NULL && pmsg->seqnum > p->seqnum) { p1 = p; p = p->next; } @@ -216,12 +165,12 @@ static int process_queue(void) char buf[BUFFER_SIZE]; int ret; - key = ftok(DEFAULT_EXEC_PROGRAM, IPC_KEY_ID); + key = ftok(DEFAULT_UDEVD_EXEC, IPC_KEY_ID); pmsg = (struct hotplug_msg *) buf; msgid = msgget(key, IPC_CREAT); if (msgid == -1) { dbg("open message queue error"); - goto exit; + return -1; } while (1) { ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0); @@ -236,7 +185,7 @@ static int process_queue(void) if (pmsg->seqnum > expect_seqnum) { add_queue(pmsg); - set_timer(); + set_timer(EVENT_TIMEOUT_SECONDS); } else { if (pmsg->seqnum == expect_seqnum) { dispatch_msg(pmsg); @@ -246,37 +195,49 @@ static int process_queue(void) dbg("timeout event for unexpected sequence number %d", pmsg->seqnum); } } - } else + } else { if (errno == EINTR) { if (head != NULL) { - /* timeout, skip all missing, proceed with next queued event */ - dbg("timeout reached, skip events %d - %d", expect_seqnum, head->seqnum-1); + /* event timeout, skip all missing, proceed with next queued event */ + info("timeout reached, skip events %d - %d", expect_seqnum, head->seqnum-1); expect_seqnum = head->seqnum; + } else { + info("we have nothing to do, so daemon exits..."); + exit(0); } check_queue(); - timeout = 0; } else { dbg("ipc message receive error '%s'", strerror(errno)); } + } } return 0; -exit: - return -1; } -int main(int argc, char *argv[]) +static void sig_handler(int signum) { - /* get program to exec on events */ - if (argc == 2) - strncpy(exec_program, argv[1], sizeof(exec_program)); - else - strcpy(exec_program, DEFAULT_EXEC_PROGRAM); + dbg("caught signal %d", signum); + switch (signum) { + case SIGINT: + case SIGTERM: + case SIGKILL: + exit(20 + signum); + break; + + default: + dbg("unhandled signal"); + } +} +int main(int argc, char *argv[]) +{ /* set up signal handler */ signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGKILL, sig_handler); - signal(SIGHUP, sig_handler); + + /* we exit if we have nothing to do, next event will start us again */ + set_timer(DAEMON_TIMEOUT_SECONDS); /* main loop */ process_queue(); @@ -21,9 +21,11 @@ * */ -#define HOTPLUGMSGTYPE 44 -#define DEFAULT_EXEC_PROGRAM "/sbin/udev" +#define DEFAULT_UDEV_EXEC "./udev" +#define DEFAULT_UDEVD_EXEC "./udevd" + #define IPC_KEY_ID 0 +#define HOTPLUGMSGTYPE 44 struct hotplug_msg { diff --git a/udevsend.c b/udevsend.c index 748c8f2217..d3e5378285 100644 --- a/udevsend.c +++ b/udevsend.c @@ -29,6 +29,9 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <time.h> +#include <wait.h> #include "udev.h" #include "udevd.h" @@ -78,6 +81,39 @@ static void free_hotplugmsg(struct hotplug_msg *pmsg) free(pmsg); } +static int start_daemon(void) +{ + pid_t pid; + pid_t child_pid; + + pid = fork(); + switch (pid) { + case 0: + /* helper child */ + child_pid = fork(); + switch (child_pid) { + case 0: + /* daemon */ + execl(DEFAULT_UDEVD_EXEC, NULL); + 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: + wait(0); + } + return 0; +} + + int main(int argc, char* argv[]) { int msgid; @@ -91,6 +127,8 @@ int main(int argc, char* argv[]) int seq; int retval = -EINVAL; int size; + int loop; + struct timespec tspec; subsystem = argv[1]; if (subsystem == NULL) { @@ -118,7 +156,7 @@ int main(int argc, char* argv[]) seq = atoi(seqnum); /* create ipc message queue or get id of our existing one */ - key = ftok(DEFAULT_EXEC_PROGRAM, IPC_KEY_ID); + key = ftok(DEFAULT_UDEVD_EXEC, IPC_KEY_ID); size = build_hotplugmsg( (struct hotplug_msg**) &pmsg, action, devpath, subsystem, seq); msgid = msgget(key, IPC_CREAT); if (msgid == -1) { @@ -126,15 +164,6 @@ int main(int argc, char* argv[]) goto exit; } - /* get state of ipc queue */ - retval = msgctl(msgid, IPC_STAT, &msg_queue); - if (retval == -1) { - dbg("error getting info on ipc queue"); - goto exit; - } - if (msg_queue.msg_qnum > 0) - dbg("%li messages already in the ipc queue", msg_queue.msg_qnum); - /* send ipc message to the daemon */ retval = msgsnd(msgid, pmsg, size, 0); free_hotplugmsg( (struct hotplug_msg*) pmsg); @@ -142,11 +171,25 @@ int main(int argc, char* argv[]) dbg("error sending ipc message"); goto exit; } - return 0; -exit: - if (retval > 0) - retval = 0; + /* get state of ipc queue */ + tspec.tv_sec = 0; + tspec.tv_nsec = 10000000; /* 10 millisec */ + loop = 20; + while (loop--) { + retval = msgctl(msgid, IPC_STAT, &msg_queue); + if (retval == -1) { + dbg("error getting info on ipc queue"); + goto exit; + } + if (msg_queue.msg_qnum == 0) + goto exit; + nanosleep(&tspec, NULL); + } + info("message is still in the ipc queue, starting daemon..."); + retval = start_daemon(); + +exit: return retval; } |