X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udevd.c;h=9242acce315ddd7c9ec9a21709f5751ccbf298d6;hp=6fb0bd9433b7e077e71eb44f1d69a8c00f405cb9;hb=63cc8f049100c9b76ca4e37fc5c8976b6e92a207;hpb=561d4c5a3a66830ecfb92fdfd7ccee19cf01c2a7 diff --git a/udevd.c b/udevd.c index 6fb0bd943..9242acce3 100644 --- a/udevd.c +++ b/udevd.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "list.h" @@ -50,13 +51,14 @@ /* global variables*/ static int udevd_sock; -static int uevent_nl_sock; +static int uevent_netlink_sock; static pid_t sid; 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; @@ -101,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); @@ -163,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; @@ -173,19 +175,17 @@ static void execute_udev(struct uevent_msg *msg) switch (pid) { case 0: /* child */ - if (uevent_nl_sock != -1) - close(uevent_nl_sock); + if (uevent_netlink_sock != -1) + 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 */ @@ -362,6 +362,9 @@ static void exec_queue_manager(void) struct uevent_msg *tmp_msg; int running; + if (list_empty(&exec_list)) + return; + running = running_processes(); dbg("%d processes runnning on system", running); if (running < 0) @@ -382,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 @@ -450,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) @@ -472,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; @@ -506,6 +511,7 @@ static struct uevent_msg *get_udevd_msg(void) struct ucred *cred; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; int envbuf_size; + int *intval; memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); iov.iov_base = &usend_msg; @@ -541,24 +547,36 @@ static struct uevent_msg *get_udevd_msg(void) return NULL; } -switch (usend_msg.type) { - case UDEVD_UEVENT: - dbg("udevd message (UEVENT) received"); + switch (usend_msg.type) { + case UDEVD_UEVENT_UDEVSEND: + case UDEVD_UEVENT_INITSEND: + info("udevd event message 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; + msg->type = usend_msg.type; return msg; case UDEVD_STOP_EXEC_QUEUE: - dbg("udevd message (STOP_EXEC_QUEUE) received"); + info("udevd message (STOP_EXEC_QUEUE) received"); stop_exec_q = 1; break; case UDEVD_START_EXEC_QUEUE: - dbg("udevd message (START_EXEC_QUEUE) received"); + info("udevd message (START_EXEC_QUEUE) received"); stop_exec_q = 0; exec_queue_manager(); break; + case UDEVD_SET_LOG_LEVEL: + intval = (int *) usend_msg.envbuf; + info("udevd message (SET_LOG_PRIORITY) received, udev_log_priority=%i", *intval); + udev_log_priority = *intval; + break; + case UDEVD_SET_MAX_CHILDS: + intval = (int *) usend_msg.envbuf; + info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval); + max_childs = *intval; + break; default: dbg("unknown message type"); } @@ -566,7 +584,7 @@ switch (usend_msg.type) { } /* receive the kernel user event message and do some sanity checks */ -static struct uevent_msg *get_uevent_msg(void) +static struct uevent_msg *get_netlink_msg(void) { struct uevent_msg *msg; int bufpos; @@ -574,7 +592,7 @@ static struct uevent_msg *get_uevent_msg(void) static char buffer[UEVENT_BUFFER_SIZE + 512]; char *pos; - size = recv(uevent_nl_sock, &buffer, sizeof(buffer), 0); + size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0); if (size < 0) { if (errno != EINTR) dbg("unable to receive udevd message"); @@ -584,13 +602,14 @@ static struct uevent_msg *get_uevent_msg(void) if ((size_t)size > sizeof(buffer)-1) size = sizeof(buffer)-1; buffer[size] = '\0'; - dbg("uevent_size=%i", size); + dbg("uevent_size=%zi", size); /* start of event payload */ bufpos = strlen(buffer)+1; msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos); if (msg == NULL) return NULL; + msg->type = UDEVD_UEVENT_NETLINK; /* validate message */ pos = strchr(buffer, '@'); @@ -623,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)); @@ -657,8 +673,8 @@ static void udev_done(int pid) list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { sysinfo(&info); - info("seq %llu exit, %ld sec old", msg->seqnum, info.uptime - msg->queue_time); - run_queue_delete(msg); + info("seq %llu exit, %ld seconds old", msg->seqnum, info.uptime - msg->queue_time); + 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 @@ -699,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; @@ -715,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) { @@ -729,9 +749,10 @@ static int init_udevd_socket(void) return 0; } -static int init_uevent_nl_sock(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)); @@ -739,18 +760,21 @@ static int init_uevent_nl_sock(void) snl.nl_pid = getpid(); snl.nl_groups = 0xffffffff; - uevent_nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (uevent_nl_sock == -1) { + uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (uevent_netlink_sock == -1) { dbg("error getting socket, %s", strerror(errno)); return -1; } - retval = bind(uevent_nl_sock, (struct sockaddr *) &snl, + /* 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) { dbg("bind failed, %s", strerror(errno)); - close(uevent_nl_sock); - uevent_nl_sock = -1; + close(uevent_netlink_sock); + uevent_netlink_sock = -1; return -1; } @@ -765,7 +789,7 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *value; - int uevent_nl_active = 0; + int uevent_netlink_active = 0; int daemonize = 0; int i; @@ -785,7 +809,7 @@ int main(int argc, char *argv[], char *envp[]) daemonize = 1; } if (strcmp(arg, "--stop-exec-queue") == 0) { - info("will not execute event until START_EXEC_QUEUE is received"); + info("will not execute events until START_EXEC_QUEUE is received"); stop_exec_q = 1; } } @@ -813,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 */ @@ -861,8 +885,9 @@ 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_nl_sock() < 0) { + if (init_uevent_netlink_sock() < 0) { dbg("uevent socket not available"); } @@ -915,11 +940,11 @@ int main(int argc, char *argv[], char *envp[]) FD_ZERO(&readfds); FD_SET(udevd_sock, &readfds); - if (uevent_nl_sock != -1) - FD_SET(uevent_nl_sock, &readfds); + 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; @@ -931,11 +956,12 @@ 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) { /* discard kernel messages if netlink is active */ - if (uevent_nl_active && msg->seqnum != 0) { + if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) { dbg("skip uevent_helper message, netlink is active"); free(msg); continue; @@ -944,21 +970,24 @@ int main(int argc, char *argv[], char *envp[]) } } - if (FD_ISSET(uevent_nl_sock, &workreadfds)) { - msg = get_uevent_msg(); + /* get kernel netlink message */ + if (FD_ISSET(uevent_netlink_sock, &workreadfds)) { + msg = get_netlink_msg(); if (msg) { msg_queue_insert(msg); - /* disable kernel uevent_helper with first netlink message */ - if (!uevent_nl_active) { - info("uevent_nl message received, disable uevent_helper messages"); - uevent_nl_active = 1; + /* disable udevsend with first netlink message */ + if (!uevent_netlink_active) { + info("uevent_nl message received, disable udevsend messages"); + uevent_netlink_active = 1; } } } + /* 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(); @@ -983,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; }