chiark / gitweb /
update README
[elogind.git] / udevd.c
diff --git a/udevd.c b/udevd.c
index f69abc4c09991796af6646b02b44bf79576004f3..d51ed2f7b0d98cdfe45364476fb9b954e9122952 100644 (file)
--- a/udevd.c
+++ b/udevd.c
@@ -1,5 +1,5 @@
 /*
- * udevd.c - hotplug event serializer
+ * udevd.c - event listener and serializer
  *
  * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
  * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
@@ -38,6 +38,7 @@
 #include <sys/un.h>
 #include <sys/sysinfo.h>
 #include <sys/stat.h>
+#include <linux/types.h>
 #include <linux/netlink.h>
 
 #include "list.h"
 #include "udevd.h"
 #include "logging.h"
 
-#ifndef NETLINK_KOBJECT_UEVENT
-#define NETLINK_KOBJECT_UEVENT 15
-#endif
-
 /* global variables*/
 static int udevd_sock;
 static int uevent_netlink_sock;
@@ -61,6 +58,7 @@ static int pipefds[2];
 static volatile int sigchilds_waiting;
 static volatile int run_msg_q;
 static volatile int sig_flag;
+static volatile int udev_exit;
 static int init_phase = 1;
 static int run_exec_q;
 static int stop_exec_q;
@@ -105,7 +103,7 @@ static void msg_dump_queue(void)
 #endif
 }
 
-static void run_queue_delete(struct uevent_msg *msg)
+static void msg_queue_delete(struct uevent_msg *msg)
 {
        list_del(&msg->node);
        free(msg);
@@ -167,7 +165,7 @@ static void msg_queue_insert(struct uevent_msg *msg)
 }
 
 /* forks event and removes event from run queue when finished */
-static void execute_udev(struct uevent_msg *msg)
+static void udev_event_fork(struct uevent_msg *msg)
 {
        char *const argv[] = { "udev", msg->subsystem, NULL };
        pid_t pid;
@@ -181,15 +179,13 @@ static void execute_udev(struct uevent_msg *msg)
                        close(uevent_netlink_sock);
                close(udevd_sock);
                logging_close();
-
                setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY);
                execve(udev_bin, argv, msg->envp);
                err("exec of child failed");
                _exit(1);
-               break;
        case -1:
                err("fork of child failed");
-               run_queue_delete(msg);
+               msg_queue_delete(msg);
                break;
        default:
                /* get SIGCHLD in main loop */
@@ -389,7 +385,7 @@ static void exec_queue_manager(void)
                if (running_with_devpath(loop_msg, max_childs) == 0) {
                        /* move event to run list */
                        list_move_tail(&loop_msg->node, &running_list);
-                       execute_udev(loop_msg);
+                       udev_event_fork(loop_msg);
                        running++;
                        dbg("moved seq %llu to running list", loop_msg->seqnum);
                } else
@@ -457,6 +453,8 @@ static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size)
        int bufpos;
        int i;
        struct uevent_msg *msg;
+       int major = 0;
+       int minor = 0;
 
        msg = malloc(sizeof(struct uevent_msg) + buf_size);
        if (msg == NULL)
@@ -479,22 +477,22 @@ static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size)
                /* remember some keys for further processing */
                if (strncmp(key, "ACTION=", 7) == 0)
                        msg->action = &key[7];
-
-               if (strncmp(key, "DEVPATH=", 8) == 0)
+               else if (strncmp(key, "DEVPATH=", 8) == 0)
                        msg->devpath = &key[8];
-
-               if (strncmp(key, "SUBSYSTEM=", 10) == 0)
+               else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
                        msg->subsystem = &key[10];
-
-               if (strncmp(key, "SEQNUM=", 7) == 0)
+               else if (strncmp(key, "SEQNUM=", 7) == 0)
                        msg->seqnum = strtoull(&key[7], NULL, 10);
-
-               if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+               else if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
                        msg->physdevpath = &key[12];
-
-               if (strncmp(key, "TIMEOUT=", 8) == 0)
+               else if (strncmp(key, "MAJOR=", 6) == 0)
+                       major = strtoull(&key[6], NULL, 10);
+               else if (strncmp(key, "MINOR=", 6) == 0)
+                       minor = strtoull(&key[6], NULL, 10);
+               else if (strncmp(key, "TIMEOUT=", 8) == 0)
                        msg->timeout = strtoull(&key[8], NULL, 10);
        }
+       msg->devt = makedev(major, minor);
        msg->envp[i++] = "UDEVD_EVENT=1";
        msg->envp[i] = NULL;
 
@@ -604,7 +602,7 @@ static struct uevent_msg *get_netlink_msg(void)
        if ((size_t)size > sizeof(buffer)-1)
                size = sizeof(buffer)-1;
        buffer[size] = '\0';
-       dbg("uevent_size=%li", (long)size);
+       dbg("uevent_size=%zi", size);
 
        /* start of event payload */
        bufpos = strlen(buffer)+1;
@@ -644,23 +642,20 @@ static void asmlinkage sig_handler(int signum)
        switch (signum) {
                case SIGINT:
                case SIGTERM:
-                       exit(20 + signum);
+                       udev_exit = 1;
                        break;
                case SIGALRM:
                        /* set flag, then write to pipe if needed */
                        run_msg_q = 1;
-                       goto do_write;
                        break;
                case SIGCHLD:
                        /* set flag, then write to pipe if needed */
                        sigchilds_waiting = 1;
-                       goto do_write;
                        break;
        }
 
-do_write:
-       /* if pipe is empty, write to pipe to force select to return
-        * immediately when it gets called
+       /* if pipe is empty, write to pipe to force select to return,
+        * which will wakeup our mainloop
         */
        if (!sig_flag) {
                rc = write(pipefds[1],&signum,sizeof(signum));
@@ -679,7 +674,7 @@ static void udev_done(int pid)
                if (msg->pid == pid) {
                        sysinfo(&info);
                        info("seq %llu exit, %ld seconds old", msg->seqnum, info.uptime - msg->queue_time);
-                       run_queue_delete(msg);
+                       msg_queue_delete(msg);
 
                        /* we want to run the exec queue manager since there may
                         * be events waiting with the devpath of the one that
@@ -720,6 +715,7 @@ static void user_sighandler(void)
 static int init_udevd_socket(void)
 {
        struct sockaddr_un saddr;
+       const int buffersize = 1024 * 1024;
        socklen_t addrlen;
        const int feature_on = 1;
        int retval;
@@ -736,6 +732,9 @@ static int init_udevd_socket(void)
                return -1;
        }
 
+       /* set receive buffersize */
+       setsockopt(udevd_sock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
+
        /* the bind takes care of ensuring only one copy running */
        retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen);
        if (retval < 0) {
@@ -753,6 +752,7 @@ static int init_udevd_socket(void)
 static int init_uevent_netlink_sock(void)
 {
        struct sockaddr_nl snl;
+       const int buffersize = 1024 * 1024;
        int retval;
 
        memset(&snl, 0x00, sizeof(struct sockaddr_nl));
@@ -766,6 +766,9 @@ static int init_uevent_netlink_sock(void)
                return -1;
        }
 
+       /* set receive buffersize */
+       setsockopt(uevent_netlink_sock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
+
        retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl,
                      sizeof(struct sockaddr_nl));
        if (retval < 0) {
@@ -834,7 +837,7 @@ int main(int argc, char *argv[], char *envp[])
        chdir("/");
        umask(umask(077) | 022);
 
-       /*set a reasonable scheduling priority for the daemon */
+       /* set a reasonable scheduling priority for the daemon */
        setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
 
        /* Set fds to dev/null */
@@ -882,6 +885,7 @@ int main(int argc, char *argv[], char *envp[])
        sigaction(SIGTERM, &act, NULL);
        sigaction(SIGALRM, &act, NULL);
        sigaction(SIGCHLD, &act, NULL);
+       sigaction(SIGHUP, &act, NULL);
 
        if (init_uevent_netlink_sock() < 0) {
                dbg("uevent socket not available");
@@ -936,11 +940,11 @@ int main(int argc, char *argv[], char *envp[])
 
        FD_ZERO(&readfds);
        FD_SET(udevd_sock, &readfds);
-       if (uevent_netlink_sock != -1)
+       if (uevent_netlink_sock > 0)
                FD_SET(uevent_netlink_sock, &readfds);
        FD_SET(pipefds[0], &readfds);
        maxsockplus = udevd_sock+1;
-       while (1) {
+       while (!udev_exit) {
                struct uevent_msg *msg;
 
                fd_set workreadfds = readfds;
@@ -952,6 +956,7 @@ int main(int argc, char *argv[], char *envp[])
                        continue;
                }
 
+               /* get user socket message */
                if (FD_ISSET(udevd_sock, &workreadfds)) {
                        msg = get_udevd_msg();
                        if (msg) {
@@ -965,6 +970,7 @@ int main(int argc, char *argv[], char *envp[])
                        }
                }
 
+               /* get kernel netlink message */
                if (FD_ISSET(uevent_netlink_sock, &workreadfds)) {
                        msg = get_netlink_msg();
                        if (msg) {
@@ -977,9 +983,11 @@ int main(int argc, char *argv[], char *envp[])
                        }
                }
 
+               /* received a signal, clear our notification pipe */
                if (FD_ISSET(pipefds[0], &workreadfds))
                        user_sighandler();
 
+               /* forked child have returned */
                if (sigchilds_waiting) {
                        sigchilds_waiting = 0;
                        reap_sigchilds();
@@ -1004,6 +1012,13 @@ int main(int argc, char *argv[], char *envp[])
        }
 
 exit:
+       if (udevd_sock > 0)
+               close(udevd_sock);
+
+       if (uevent_netlink_sock > 0)
+               close(uevent_netlink_sock);
+
        logging_close();
-       return 1;
+
+       return 0;
 }