program-client-local.c revision 2558976f0b03852ba673d75d0af6850a61e733ce
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "lib.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "lib-signals.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "env-util.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "execv-const.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "array.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "net.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "istream.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "ostream.h"
1acc8d6538864577b8f40cc4e1ca922a62f52327Aki Tuomi#include "restrict-access.h"
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi#include "child-wait.h"
17541ea25593c656060199715051db2c1eef221dAki Tuomi#include "time-util.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include "program-client-private.h"
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sys/types.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sys/socket.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sys/stat.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <sys/wait.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <unistd.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <fcntl.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi#include <grp.h>
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi#define KILL_TIMEOUT 5000
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct program_client_local {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi struct child_wait *child_wait;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi struct timeout *to_kill;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pid_t pid;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi int status;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi bool exited:1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi bool stopping:1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi bool sent_term:1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi};
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid program_client_local_waitchild(const struct child_wait_status *,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi struct program_client_local *);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_disconnect(struct program_client *pclient, bool force);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_exited(struct program_client_local *slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid exec_child(const char *bin_path, const char *const *args,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi const char *const *envs,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int in_fd, int out_fd, int *extra_fds, bool drop_stderr)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi ARRAY_TYPE(const_string) exec_args;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Setup stdin/stdout */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (in_fd < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi in_fd = open("/dev/null", O_RDONLY);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (in_fd == -1)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("open(/dev/null) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (out_fd < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi out_fd = open("/dev/null", O_WRONLY);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (out_fd == -1)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("open(/dev/null) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (in_fd != STDIN_FILENO && dup2(in_fd, STDIN_FILENO) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("dup2(stdin) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (out_fd != STDOUT_FILENO && dup2(out_fd, STDOUT_FILENO) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("dup2(stdout) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (in_fd != STDIN_FILENO && close(in_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(in_fd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (out_fd != STDOUT_FILENO && (out_fd != in_fd) && close(out_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(out_fd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Drop stderr if requested */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (drop_stderr) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int err_fd = open("/dev/null", O_WRONLY);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (err_fd == -1)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("open(/dev/null) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (err_fd != STDERR_FILENO) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (dup2(err_fd, STDERR_FILENO) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("dup2(stderr) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(err_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(err_fd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Setup extra fds */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (extra_fds != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int *efd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(efd = extra_fds; *efd != -1; efd += 2) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(efd[1] != STDIN_FILENO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(efd[1] != STDOUT_FILENO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_assert(efd[1] != STDERR_FILENO);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efd[0] != efd[1]) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (dup2(efd[0], efd[1]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_fatal("dup2(extra_fd=%d) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd[1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(efd = extra_fds; *efd != -1; efd += 2) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (efd[0] != efd[1] && efd[0] != STDIN_FILENO &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd[0] != STDOUT_FILENO &&
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd[0] != STDERR_FILENO) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(efd[0]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(extra_fd=%d) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efd[1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Compose argv */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi t_array_init(&exec_args, 16);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi array_append(&exec_args, &bin_path, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (args != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(; *args != NULL; args++)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi array_append(&exec_args, args, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi (void) array_append_space(&exec_args);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Setup environment */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi env_clean();
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (envs != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(; *envs != NULL; envs++)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi env_put(*envs);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Execute */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi args = array_idx(&exec_args, 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi execvp_const(args[0], args);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_waitchild(const struct child_wait_status *status,
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi struct program_client_local *slclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_assert(slclient->pid == status->pid);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->status = status->status;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->exited = TRUE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->pid = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->stopping)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi else
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_program_input(&slclient->client);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_local_connect(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi struct program_client_local *slclient =
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi (struct program_client_local *)pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int fd_in[2] = { -1, -1 }, fd_out[2] = {-1, -1};
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_extra_fd *efds = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int *parent_extra_fds = NULL, *child_extra_fds = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int xfd_count = 0, i;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* create normal I/O fds */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->input != NULL) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pipe(fd_in) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("pipe(in) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->output != NULL || pclient->output_seekable) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pipe(fd_out) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("pipe(out) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* create pipes for additional output through side-channel fds */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (array_is_created(&pclient->extra_fds)) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int extra_fd[2];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds = array_get_modifiable(&pclient->extra_fds, &xfd_count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (xfd_count > 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi parent_extra_fds = t_malloc0(sizeof(int) * xfd_count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds =
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi t_malloc0(sizeof(int) * xfd_count * 2 + 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < xfd_count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pipe(extra_fd) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("pipe(extra=%d) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi extra_fd[1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi parent_extra_fds[i] = extra_fd[0];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 0] = extra_fd[1];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 1] = efds[i].child_fd;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[xfd_count * 2] = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* fork child */
03c6532fe7aa3ddae23c99ff6bec78d8dd2e8165Aki Tuomi if ((slclient->pid = fork()) == (pid_t)-1) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("fork() failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* clean up */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in[0] >= 0 && close(fd_in[0]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:in:rd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in[1] >= 0 && close(fd_in[1]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:in:wr) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out[0] >= 0 && close(fd_out[0]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:out:rd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out[1] >= 0 && close(fd_out[1]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:out:wr) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < xfd_count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(child_extra_fds[i * 2]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:extra=%d:wr) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(parent_extra_fds[i]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:extra=%d:rd) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (slclient->pid == 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi unsigned int count;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const char *const *envs = NULL;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* child */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in[1] >= 0 && close(fd_in[1]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:in:wr) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out[0] >= 0 && close(fd_out[0]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:out:rd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < xfd_count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(parent_extra_fds[i]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:extra=%d:rd) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
2558976f0b03852ba673d75d0af6850a61e733ceAki Tuomi /* if we want to allow root, then we will not drop
2558976f0b03852ba673d75d0af6850a61e733ceAki Tuomi root privileges */
2558976f0b03852ba673d75d0af6850a61e733ceAki Tuomi pclient->set.restrict_set.drop_setuid_root =
2558976f0b03852ba673d75d0af6850a61e733ceAki Tuomi !pclient->set.allow_root;
2558976f0b03852ba673d75d0af6850a61e733ceAki Tuomi
1acc8d6538864577b8f40cc4e1ca922a62f52327Aki Tuomi restrict_access(&pclient->set.restrict_set, pclient->set.home,
1acc8d6538864577b8f40cc4e1ca922a62f52327Aki Tuomi !pclient->set.allow_root);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (array_is_created(&pclient->envs))
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi envs = array_get(&pclient->envs, &count);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi exec_child(pclient->path, pclient->args, envs,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi fd_in[0], fd_out[1], child_extra_fds,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->set.drop_stderr);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_unreached();
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* parent */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in[0] >= 0 && close(fd_in[0]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:in:rd) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out[1] >= 0 && close(fd_out[1]) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:out:wr) failed: %m");
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_in[1] >= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi net_set_nonblock(fd_in[1], TRUE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_out = fd_in[1];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out[0] >= 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi net_set_nonblock(fd_out[0], TRUE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_in = fd_out[0];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi for(i = 0; i < xfd_count; i++) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (close(child_extra_fds[i * 2]) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(pipe:extra=%d:wr) failed: %m",
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi child_extra_fds[i * 2 + 1]);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi net_set_nonblock(parent_extra_fds[i], TRUE);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi efds[i].parent_fd = parent_extra_fds[i];
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_init_streams(pclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi slclient->child_wait =
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi child_wait_new_with_pid(slclient->pid,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_local_waitchild,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi slclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return program_client_connected(pclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_local_close_output(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi int fd_out = pclient->fd_out;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->fd_out = -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Shutdown output; program stdin will get EOF */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (fd_out >= 0 && close(fd_out) < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(%s) failed: %m", pclient->path);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return -1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return 1;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_exited(struct program_client_local *slclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->to_kill != NULL)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi timeout_remove(&slclient->to_kill);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->child_wait != NULL)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi child_wait_free(&slclient->child_wait);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi struct program_client *pclient = &slclient->client;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->exited = TRUE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->pid = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Evaluate child exit status */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->exit_code = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (WIFEXITED(slclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Exited */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi int exit_code = WEXITSTATUS(slclient->status);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (exit_code != 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_info("program `%s' terminated with non-zero exit code %d",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->path, exit_code);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->exit_code = 0;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->exit_code = 1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else if (WIFSIGNALED(slclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Killed with a signal */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->sent_term) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' was forcibly terminated with signal %d",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->path, WTERMSIG(slclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' terminated abnormally, signal %d",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->path, WTERMSIG(slclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else if (WIFSTOPPED(slclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Stopped */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' stopped, signal %d",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->path, WSTOPSIG(slclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Something else */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' terminated abnormally, return status %d",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->path, slclient->status);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_disconnected(pclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_kill(struct program_client_local *slclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* time to die */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->to_kill != NULL)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi timeout_remove(&slclient->to_kill);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_assert(slclient->pid != (pid_t)-1);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->client.error == PROGRAM_CLIENT_ERROR_NONE)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->client.error = PROGRAM_CLIENT_ERROR_RUN_TIMEOUT;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->sent_term) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* no need for this anymore */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi child_wait_free(&slclient->child_wait);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Timed out again */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->client.debug) {
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_debug("program `%s' (%d) did not die after %d milliseconds: "
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi "sending KILL signal",
17541ea25593c656060199715051db2c1eef221dAki Tuomi slclient->client.path, slclient->pid, KILL_TIMEOUT);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Kill it brutally now, it should die right away */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (kill(slclient->pid, SIGKILL) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("failed to send SIGKILL signal to program `%s'",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->client.path);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else if (waitpid(slclient->pid, &slclient->status, 0) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("waitpid(%s) failed: %m",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->client.path);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->client.debug)
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_debug("program `%s'(%d) execution timed out after %u milliseconds: "
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi "sending TERM signal", slclient->client.path, slclient->pid,
17541ea25593c656060199715051db2c1eef221dAki Tuomi slclient->client.set.input_idle_timeout_msecs);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* send sigterm, keep on waiting */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->sent_term = TRUE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Kill child gently first */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (kill(slclient->pid, SIGTERM) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("failed to send SIGTERM signal to program `%s'",
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->client.path);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi (void)kill(slclient->pid, SIGKILL);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_assert(slclient->child_wait != NULL);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->to_kill = timeout_add_short(KILL_TIMEOUT,
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_kill, slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_disconnect(struct program_client *pclient, bool force)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi struct program_client_local *slclient =
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi (struct program_client_local *) pclient;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pid_t pid = slclient->pid;
17541ea25593c656060199715051db2c1eef221dAki Tuomi unsigned long runtime, timeout = 0;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->exited) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (slclient->stopping) return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->stopping = TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pid < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* program never started */
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->exit_code = 0;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* make sure it hasn't already been reaped */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (waitpid(slclient->pid, &slclient->status, WNOHANG) > 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_exited(slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* Calculate timeout */
17541ea25593c656060199715051db2c1eef221dAki Tuomi runtime = timeval_diff_msecs(&ioloop_timeval, &pclient->start_time);
17541ea25593c656060199715051db2c1eef221dAki Tuomi if (!force && pclient->set.input_idle_timeout_msecs > 0 &&
17541ea25593c656060199715051db2c1eef221dAki Tuomi runtime < pclient->set.input_idle_timeout_msecs)
17541ea25593c656060199715051db2c1eef221dAki Tuomi timeout = pclient->set.input_idle_timeout_msecs - runtime;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pclient->debug) {
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_debug("waiting for program `%s' to finish after %lu msecs",
17541ea25593c656060199715051db2c1eef221dAki Tuomi pclient->path, runtime);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi force = force ||
17541ea25593c656060199715051db2c1eef221dAki Tuomi (timeout == 0 && pclient->set.input_idle_timeout_msecs > 0);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (!force) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi if (timeout > 0)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient->to_kill =
17541ea25593c656060199715051db2c1eef221dAki Tuomi timeout_add_short(timeout,
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_kill,
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi slclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_kill(slclient);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_destroy(struct program_client *pclient ATTR_UNUSED)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi child_wait_deinit();
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomistatic
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomivoid program_client_local_switch_ioloop(struct program_client *pclient)
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi{
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi struct program_client_local *slclient =
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi (struct program_client_local *)pclient;
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi if (slclient->to_kill)
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi slclient->to_kill = io_loop_move_timeout(&slclient->to_kill);
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi lib_signals_reset_ioloop();
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi}
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistruct program_client *
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiprogram_client_local_create(const char *bin_path,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const char *const *args,
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi const struct program_client_settings *set)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi struct program_client_local *pclient;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pool_t pool;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pool = pool_alloconly_create("program client local", 1024);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient = p_new(pool, struct program_client_local, 1);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi program_client_init(&pclient->client, pool, bin_path, args, set);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->client.connect = program_client_local_connect;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->client.close_output = program_client_local_close_output;
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi pclient->client.switch_ioloop = program_client_local_switch_ioloop;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->client.disconnect = program_client_local_disconnect;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi pclient->client.destroy = program_client_local_destroy;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi pclient->pid = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi child_wait_init();
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi return &pclient->client;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi}