=== modified file 'plugin-runner.c' --- plugin-runner.c 2008-08-24 10:19:59 +0000 +++ plugin-runner.c 2008-08-24 23:33:02 +0000 @@ -56,7 +56,8 @@ #include /* struct argp_option, struct argp_state, struct argp, argp_parse(), ARGP_ERR_UNKNOWN, - ARGP_KEY_END, ARGP_KEY_ARG, error_t */ + ARGP_KEY_END, ARGP_KEY_ARG, + error_t */ #include /* struct sigaction, sigemptyset(), sigaddset(), sigaction(), sigprocmask(), SIG_BLOCK, SIGCHLD, @@ -78,8 +79,8 @@ size_t buffer_size; size_t buffer_length; bool eof; - bool completed; - int status; + volatile bool completed; + volatile int status; struct process *next; } process; @@ -199,25 +200,36 @@ process *process_list = NULL; -/* Mark a process as completed when it exits, and save its exit +/* Mark processes as completed when they exit, and save their exit status. */ void handle_sigchld(__attribute__((unused)) int sig){ - process *proc = process_list; - int status; - pid_t pid = wait(&status); - if(pid == -1){ - perror("wait"); - return; - } - while(proc != NULL and proc->pid != pid){ - proc = proc->next; - } - if(proc == NULL){ - /* Process not found in process list */ - return; - } - proc->status = status; - proc->completed = true; + while(true){ + process *proc = process_list; + int status; + pid_t pid = waitpid(-1, &status, WNOHANG); + if(pid == 0){ + /* Only still running child processes */ + break; + } + if(pid == -1){ + if (errno != ECHILD){ + perror("waitpid"); + } + /* No child processes */ + break; + } + + /* A child exited, find it in process_list */ + while(proc != NULL and proc->pid != pid){ + proc = proc->next; + } + if(proc == NULL){ + /* Process not found in process list */ + continue; + } + proc->status = status; + proc->completed = true; + } } bool print_out_password(const char *buffer, size_t length){ @@ -242,7 +254,8 @@ if(argv == NULL){ return NULL; } - argv[0] = NULL; /* Will be set to argv[0] in main before parsing */ + argv[0] = NULL; /* Will be set to argv[0] in main before + parsing */ argv[1] = NULL; } *argc += 1; @@ -501,7 +514,8 @@ if(custom_argv != NULL){ custom_argv[0] = argv[0]; - ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list); + ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, + &plugin_list); if (ret == ARGP_ERR_UNKNOWN){ fprintf(stderr, "Unknown error while parsing arguments\n"); exitstatus = EXIT_FAILURE; @@ -835,7 +849,7 @@ /* Remove the plugin */ FD_CLR(proc->fd, &rfds_all); /* Block signal while modifying process_list */ - ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL); + ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL); if(ret < 0){ perror("sigprocmask"); exitstatus = EXIT_FAILURE; @@ -869,7 +883,8 @@ } /* This process exited nicely, so print its buffer */ - bool bret = print_out_password(proc->buffer, proc->buffer_length); + bool bret = print_out_password(proc->buffer, + proc->buffer_length); if(not bret){ perror("print_out_password"); exitstatus = EXIT_FAILURE; @@ -912,7 +927,8 @@ fallback: if(process_list == NULL or exitstatus != EXIT_SUCCESS){ - /* Fallback if all plugins failed, none are found or an error occured */ + /* Fallback if all plugins failed, none are found or an error + occured */ bool bret; fprintf(stderr, "Going to fallback mode using getpass(3)\n"); char *passwordbuffer = getpass("Password: ");