X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udevd.c;h=e227a64d71de32ee82a29f85ed6def978e33709f;hp=8423278d6cca0bc2715656469f1a2d67c94a73fc;hb=2321ba6fd89635f321ec08fa3803aa7e20aa76bf;hpb=af5461f72f86bc00fd40a11a8ac2b6979f8cd61a diff --git a/udevd.c b/udevd.c index 8423278d6..e227a64d7 100644 --- a/udevd.c +++ b/udevd.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -54,29 +55,23 @@ static int udevd_sock; static int uevent_netlink_sock; static pid_t sid; -static int pipefds[2] = {-1, -1}; +static int signal_pipe[2] = {-1, -1}; 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; - -static LIST_HEAD(msg_list); -static LIST_HEAD(exec_list); -static LIST_HEAD(running_list); - -static void exec_queue_manager(void); -static void msg_queue_manager(void); -static void user_sighandler(void); -static void reap_sigchilds(void); - static char *udev_bin; -static unsigned long long expected_seqnum; static int event_timeout; static int max_childs; static int max_childs_running; +static unsigned long long expected_seqnum; +static char log[32]; + +static LIST_HEAD(msg_list); +static LIST_HEAD(exec_list); +static LIST_HEAD(running_list); #ifdef USE_LOG @@ -117,7 +112,7 @@ static void msg_queue_insert(struct uevent_msg *msg) if (msg->seqnum == 0) { dbg("no SEQNUM, move straight to the exec queue"); - list_add(&msg->node, &exec_list); + list_add_tail(&msg->node, &exec_list); run_exec_q = 1; return; } @@ -136,14 +131,6 @@ static void msg_queue_insert(struct uevent_msg *msg) init_phase = 0; } - /* don't delay messages with timeout set */ - if (msg->timeout) { - dbg("move seq %llu with timeout %u to exec queue", msg->seqnum, msg->timeout); - list_add(&msg->node, &exec_list); - run_exec_q = 1; - return; - } - /* sort message by sequence number into list */ list_for_each_entry_reverse(loop_msg, &msg_list, node) { if (loop_msg->seqnum < msg->seqnum) @@ -156,7 +143,7 @@ static void msg_queue_insert(struct uevent_msg *msg) } } list_add(&msg->node, &loop_msg->node); - info("seq %llu queued, devpath '%s'", msg->seqnum, msg->devpath); + info("seq %llu queued, '%s' '%s'", msg->seqnum, msg->action, msg->devpath); /* run msg queue manager */ run_msg_q = 1; @@ -165,7 +152,7 @@ static void msg_queue_insert(struct uevent_msg *msg) } /* forks event and removes event from run queue when finished */ -static void udev_event_fork(struct uevent_msg *msg) +static void udev_event_run(struct uevent_msg *msg) { char *const argv[] = { "udev", msg->subsystem, NULL }; pid_t pid; @@ -190,8 +177,8 @@ static void udev_event_fork(struct uevent_msg *msg) default: /* get SIGCHLD in main loop */ sysinfo(&info); - info("seq %llu forked, pid %d, %ld seconds old", - msg->seqnum, pid, info.uptime - msg->queue_time); + info("seq %llu forked, pid [%d], '%s' '%s', %ld seconds old", + msg->seqnum, pid, msg->action, msg->subsystem, info.uptime - msg->queue_time); msg->pid = pid; } } @@ -208,7 +195,7 @@ static int running_processes(void) if (f == -1) return -1; - len = read(f, buf, sizeof(buf)); + len = read(f, buf, sizeof(buf)-1); close(f); if (len <= 0) @@ -257,7 +244,7 @@ static int running_processes_in_session(pid_t session, int limit) if (f == -1) continue; - len = read(f, line, sizeof(line)); + len = read(f, line, sizeof(line)-1); close(f); if (len <= 0) @@ -385,7 +372,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); - udev_event_fork(loop_msg); + udev_event_run(loop_msg); running++; dbg("moved seq %llu to running list", loop_msg->seqnum); } else @@ -441,9 +428,9 @@ recheck: msg_dump_queue(); /* set timeout for remaining queued events */ - if (list_empty(&msg_list) == 0) { + if (!list_empty(&msg_list)) { struct itimerval itv = {{0, 0}, {timeout - msg_age, 0}}; - dbg("next event expires in %li seconds", timeout - msg_age); + info("next event expires in %li seconds", timeout - msg_age); setitimer(ITIMER_REAL, &itv, NULL); } } @@ -526,24 +513,24 @@ static struct uevent_msg *get_udevd_msg(void) size = recvmsg(udevd_sock, &smsg, 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevd message"); + err("unable to receive udevd message"); return NULL; } cmsg = CMSG_FIRSTHDR(&smsg); cred = (struct ucred *) CMSG_DATA(cmsg); if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { - info("no sender credentials received, message ignored"); + err("no sender credentials received, message ignored"); return NULL; } if (cred->uid != 0) { - info("sender uid=%i, message ignored", cred->uid); + err("sender uid=%i, message ignored", cred->uid); return NULL; } if (strncmp(usend_msg.magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) { - info("message magic '%s' doesn't match, ignore it", usend_msg.magic); + err("message magic '%s' doesn't match, ignore it", usend_msg.magic); return NULL; } @@ -571,6 +558,8 @@ static struct uevent_msg *get_udevd_msg(void) intval = (int *) usend_msg.envbuf; info("udevd message (SET_LOG_PRIORITY) received, udev_log_priority=%i", *intval); udev_log_priority = *intval; + sprintf(log, "UDEV_LOG=%i", udev_log_priority); + putenv(log); break; case UDEVD_SET_MAX_CHILDS: intval = (int *) usend_msg.envbuf; @@ -595,7 +584,7 @@ static struct uevent_msg *get_netlink_msg(void) size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevd message"); + err("unable to receive udevd message"); return NULL; } @@ -614,20 +603,20 @@ static struct uevent_msg *get_netlink_msg(void) /* validate message */ pos = strchr(buffer, '@'); if (pos == NULL) { - dbg("invalid uevent '%s'", buffer); + err("invalid uevent '%s'", buffer); free(msg); return NULL; } pos[0] = '\0'; if (msg->action == NULL) { - dbg("no ACTION in payload found, skip event '%s'", buffer); + err("no ACTION in payload found, skip event '%s'", buffer); free(msg); return NULL; } if (strcmp(msg->action, buffer) != 0) { - dbg("ACTION in payload does not match uevent, skip event '%s'", buffer); + err("ACTION in payload does not match uevent, skip event '%s'", buffer); free(msg); return NULL; } @@ -637,8 +626,6 @@ static struct uevent_msg *get_netlink_msg(void) static void asmlinkage sig_handler(int signum) { - int rc; - switch (signum) { case SIGINT: case SIGTERM: @@ -654,14 +641,8 @@ static void asmlinkage sig_handler(int signum) break; } - /* 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)); - if (rc >= 0) - sig_flag = 1; - } + /* write to pipe, which will wakeup select() in our mainloop */ + write(signal_pipe[WRITE_END], "", 1); } static void udev_done(int pid) @@ -673,7 +654,10 @@ 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 seconds old", msg->seqnum, info.uptime - msg->queue_time); + if (msg->queue_time) + info("seq %llu, pid [%d] exit, %ld seconds old", msg->seqnum, msg->pid, info.uptime - msg->queue_time); + else + info("seq 0, pid [%d] exit", msg->pid); msg_queue_delete(msg); /* we want to run the exec queue manager since there may @@ -688,27 +672,13 @@ static void udev_done(int pid) static void reap_sigchilds(void) { - while(1) { - int pid = waitpid(-1, NULL, WNOHANG); - if ((pid == -1) || (pid == 0)) - break; - udev_done(pid); - } -} - -/* just read everything from the pipe and clear the flag, - * the flags was set in the signal handler - */ -static void user_sighandler(void) -{ - int sig; + pid_t pid; - while(1) { - int rc = read(pipefds[0], &sig, sizeof(sig)); - if (rc < 0) + while (1) { + pid = waitpid(-1, NULL, WNOHANG); + if (pid <= 0) break; - - sig_flag = 0; + udev_done(pid); } } @@ -762,7 +732,7 @@ static int init_uevent_netlink_sock(void) uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (uevent_netlink_sock == -1) { - dbg("error getting socket, %s", strerror(errno)); + err("error getting socket, %s", strerror(errno)); return -1; } @@ -772,7 +742,7 @@ static int init_uevent_netlink_sock(void) retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl)); if (retval < 0) { - dbg("bind failed, %s", strerror(errno)); + err("bind failed, %s", strerror(errno)); close(uevent_netlink_sock); uevent_netlink_sock = -1; return -1; @@ -783,7 +753,6 @@ static int init_uevent_netlink_sock(void) int main(int argc, char *argv[], char *envp[]) { - int maxsockplus; int retval; int devnull; struct sigaction act; @@ -793,7 +762,23 @@ int main(int argc, char *argv[], char *envp[]) int daemonize = 0; int i; + /* set std fd's to /dev/null, if the kernel forks us, we don't have them at all */ + devnull = open("/dev/null", O_RDWR); + if (devnull >= 0) { + if (devnull != STDIN_FILENO) + dup2(devnull, STDIN_FILENO); + if (devnull != STDOUT_FILENO) + dup2(devnull, STDOUT_FILENO); + if (devnull != STDERR_FILENO) + dup2(devnull, STDERR_FILENO); + if (devnull > STDERR_FILENO) + close(devnull); + } + logging_init("udevd"); + if (devnull < 0) + err("fatal, could not open /dev/null"); + udev_init_config(); dbg("version %s", UDEV_VERSION); @@ -813,6 +798,7 @@ int main(int argc, char *argv[], char *envp[]) stop_exec_q = 1; } } + if (daemonize) { pid_t pid; @@ -840,38 +826,26 @@ int main(int argc, char *argv[], char *envp[]) /* set a reasonable scheduling priority for the daemon */ setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); - /* Set fds to dev/null */ - devnull = open( "/dev/null", O_RDWR ); - if (devnull > 0) { - dup2(devnull, STDIN_FILENO); - dup2(devnull, STDOUT_FILENO); - dup2(devnull, STDERR_FILENO); - close(devnull); - } else - err("error opening /dev/null %s", strerror(errno)); - /* setup signal handler pipe */ - retval = pipe(pipefds); + retval = pipe(signal_pipe); if (retval < 0) { err("error getting pipes: %s", strerror(errno)); goto exit; } - - retval = fcntl(pipefds[0], F_SETFL, O_NONBLOCK); + retval = fcntl(signal_pipe[READ_END], F_SETFL, O_NONBLOCK); if (retval < 0) { err("error fcntl on read pipe: %s", strerror(errno)); goto exit; } - retval = fcntl(pipefds[0], F_SETFD, FD_CLOEXEC); + retval = fcntl(signal_pipe[READ_END], F_SETFD, FD_CLOEXEC); if (retval < 0) err("error fcntl on read pipe: %s", strerror(errno)); - - retval = fcntl(pipefds[1], F_SETFL, O_NONBLOCK); + retval = fcntl(signal_pipe[WRITE_END], F_SETFL, O_NONBLOCK); if (retval < 0) { err("error fcntl on write pipe: %s", strerror(errno)); goto exit; } - retval = fcntl(pipefds[1], F_SETFD, FD_CLOEXEC); + retval = fcntl(signal_pipe[WRITE_END], F_SETFD, FD_CLOEXEC); if (retval < 0) err("error fcntl on write pipe: %s", strerror(errno)); @@ -886,10 +860,6 @@ int main(int argc, char *argv[], char *envp[]) sigaction(SIGCHLD, &act, NULL); sigaction(SIGHUP, &act, NULL); - if (init_uevent_netlink_sock() < 0) { - dbg("uevent socket not available"); - } - if (init_udevd_socket() < 0) { if (errno == EADDRINUSE) dbg("another udevd running, exit"); @@ -899,6 +869,9 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } + if (init_uevent_netlink_sock() < 0) + info("uevent socket not available"); + /* override of forked udev binary, used for testing */ udev_bin = getenv("UDEV_BIN"); if (udev_bin != NULL) @@ -937,40 +910,42 @@ int main(int argc, char *argv[], char *envp[]) max_childs_running = UDEVD_MAX_CHILDS_RUNNING; info("initialize max_childs_running to %u", max_childs_running); - FD_ZERO(&readfds); - FD_SET(udevd_sock, &readfds); - if (uevent_netlink_sock > 0) - FD_SET(uevent_netlink_sock, &readfds); - FD_SET(pipefds[0], &readfds); - maxsockplus = udevd_sock+1; + /* export log_priority , as called programs may want to follow that setting */ + sprintf(log, "UDEV_LOG=%i", udev_log_priority); + putenv(log); + while (!udev_exit) { struct uevent_msg *msg; + int fdcount; - fd_set workreadfds = readfds; - retval = select(maxsockplus, &workreadfds, NULL, NULL, NULL); + FD_ZERO(&readfds); + FD_SET(signal_pipe[READ_END], &readfds); + FD_SET(udevd_sock, &readfds); + if (uevent_netlink_sock > 0) + FD_SET(uevent_netlink_sock, &readfds); - if (retval < 0) { + fdcount = select(UDEV_MAX(udevd_sock, uevent_netlink_sock)+1, &readfds, NULL, NULL, NULL); + if (fdcount < 0) { if (errno != EINTR) dbg("error in select: %s", strerror(errno)); continue; } /* get user socket message */ - if (FD_ISSET(udevd_sock, &workreadfds)) { + if (FD_ISSET(udevd_sock, &readfds)) { msg = get_udevd_msg(); if (msg) { /* discard kernel messages if netlink is active */ if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) { - dbg("skip uevent_helper message, netlink is active"); + info("skip uevent_helper message with SEQNUM, netlink is active"); free(msg); - continue; - } - msg_queue_insert(msg); + } else + msg_queue_insert(msg); } } /* get kernel netlink message */ - if (FD_ISSET(uevent_netlink_sock, &workreadfds)) { + if ((uevent_netlink_sock > 0) && FD_ISSET(uevent_netlink_sock, &readfds)) { msg = get_netlink_msg(); if (msg) { msg_queue_insert(msg); @@ -983,8 +958,11 @@ int main(int argc, char *argv[], char *envp[]) } /* received a signal, clear our notification pipe */ - if (FD_ISSET(pipefds[0], &workreadfds)) - user_sighandler(); + if (FD_ISSET(signal_pipe[READ_END], &readfds)) { + char buf[256]; + + read(signal_pipe[READ_END], &buf, sizeof(buf)); + } /* forked child have returned */ if (sigchilds_waiting) { @@ -1011,14 +989,13 @@ int main(int argc, char *argv[], char *envp[]) } exit: - if (pipefds[0] > 0) - close(pipefds[0]); - if (pipefds[1] > 0) - close(pipefds[1]); + if (signal_pipe[READ_END] > 0) + close(signal_pipe[READ_END]); + if (signal_pipe[WRITE_END] > 0) + close(signal_pipe[WRITE_END]); if (udevd_sock > 0) close(udevd_sock); - if (uevent_netlink_sock > 0) close(uevent_netlink_sock);