bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 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
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Boschvoid program_client_local_exited(struct program_client_local *plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomivoid exec_child(const char *bin_path, const char *const *args,
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch ARRAY_TYPE(const_string) *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
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen if (in_fd < 0)
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen in_fd = dev_null_fd;
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen if (out_fd < 0)
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen out_fd = dev_null_fd;
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
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen if (in_fd != STDIN_FILENO && in_fd != dev_null_fd && close(in_fd) < 0)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi i_error("close(in_fd) failed: %m");
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen if (out_fd != STDOUT_FILENO && out_fd != dev_null_fd &&
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen (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) {
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen if (dup2(dev_null_fd, STDERR_FILENO) < 0)
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen i_fatal("dup2(stderr) failed: %m");
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();
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch if (array_is_created(envs)) {
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch const char *const *env;
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch array_foreach(envs, env) {
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch env_put(*env);
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch }
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,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_local *plclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch i_assert(plclient->pid == status->pid);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->status = status->status;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->exited = TRUE;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->pid = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->stopping)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi else
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_program_input(&plclient->client);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomistatic
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomiint program_client_local_connect(struct program_client *pclient)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_local *plclient =
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) {
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen i_assert(xfd_count < INT_MAX);
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen parent_extra_fds = t_new(int, xfd_count);
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen child_extra_fds = t_new(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 */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if ((plclient->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
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->pid == 0) {
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 */
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi restrict_access(&pclient->set.restrict_set,
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi pclient->set.allow_root ? RESTRICT_ACCESS_FLAG_ALLOW_ROOT : 0,
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi pclient->set.home);
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
fc2b1489550d5b20f369ceaf92f590cf06b002fdStephan Bosch exec_child(pclient->path, pclient->args, &pclient->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
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->child_wait =
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch child_wait_new_with_pid(plclient->pid,
1be27c35ea17fccd83c54e2acc66eb8c44d1a8feAki Tuomi program_client_local_waitchild,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient);
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
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Boschvoid program_client_local_exited(struct program_client_local *plclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&plclient->to_kill);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->child_wait != NULL)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch child_wait_free(&plclient->child_wait);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client *pclient = &plclient->client;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->exited = TRUE;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->pid = -1;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Evaluate child exit status */
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_INTERNAL_FAILURE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (WIFEXITED(plclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Exited */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch int exit_code = WEXITSTATUS(plclient->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);
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_FAILURE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_SUCCESS;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch } else if (WIFSIGNALED(plclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Killed with a signal */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->sent_term) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' was forcibly terminated with signal %d",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->path, WTERMSIG(plclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' terminated abnormally, signal %d",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->path, WTERMSIG(plclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch } else if (WIFSTOPPED(plclient->status)) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Stopped */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' stopped, signal %d",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->path, WSTOPSIG(plclient->status));
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Something else */
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("program `%s' terminated abnormally, return status %d",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pclient->path, plclient->status);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_disconnected(pclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Boschvoid program_client_local_kill(struct program_client_local *plclient)
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi{
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* time to die */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&plclient->to_kill);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch i_assert(plclient->pid != (pid_t)-1);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->client.error == PROGRAM_CLIENT_ERROR_NONE)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.error = PROGRAM_CLIENT_ERROR_RUN_TIMEOUT;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->sent_term) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* no need for this anymore */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch child_wait_free(&plclient->child_wait);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Timed out again */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->client.debug) {
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_debug("program `%s' (%d) did not die after %d milliseconds: "
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi "sending KILL signal",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.path, plclient->pid, KILL_TIMEOUT);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Kill it brutally now, it should die right away */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (kill(plclient->pid, SIGKILL) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("failed to send SIGKILL signal to program `%s'",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.path);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch } else if (waitpid(plclient->pid, &plclient->status, 0) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("waitpid(%s) failed: %m",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.path);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->client.debug)
17541ea25593c656060199715051db2c1eef221dAki Tuomi i_debug("program `%s'(%d) execution timed out after %u milliseconds: "
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch "sending TERM signal", plclient->client.path, plclient->pid,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.set.input_idle_timeout_msecs);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* send sigterm, keep on waiting */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->sent_term = TRUE;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* Kill child gently first */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (kill(plclient->pid, SIGTERM) < 0) {
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi i_error("failed to send SIGTERM signal to program `%s'",
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->client.path);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch (void)kill(plclient->pid, SIGKILL);
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch i_assert(plclient->child_wait != NULL);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->to_kill = timeout_add_short(KILL_TIMEOUT,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_kill, plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi}
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomistatic
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomivoid program_client_local_disconnect(struct program_client *pclient, bool force)
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_local *plclient =
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi (struct program_client_local *) pclient;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch pid_t pid = plclient->pid;
17541ea25593c656060199715051db2c1eef221dAki Tuomi unsigned long runtime, timeout = 0;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->exited) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi }
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (plclient->stopping) return;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->stopping = TRUE;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi if (pid < 0) {
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi /* program never started */
d9683a6493b2298ecd309522df315f8e7188e869Stephan Bosch pclient->exit_code = PROGRAM_CLIENT_EXIT_FAILURE;
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi return;
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi }
4036c1ca99d2c517f68a5b67a419ae7fdfd45300Aki Tuomi
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi /* make sure it hasn't already been reaped */
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch if (waitpid(plclient->pid, &plclient->status, WNOHANG) > 0) {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_exited(plclient);
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)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->to_kill =
17541ea25593c656060199715051db2c1eef221dAki Tuomi timeout_add_short(timeout,
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi program_client_local_kill,
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient);
4fbe0d10901a80b27aacc9d9e6848e30e5fe727dAki Tuomi } else {
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch program_client_local_kill(plclient);
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{
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch struct program_client_local *plclient =
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi (struct program_client_local *)pclient;
204afc1f4f37a4f1cb53ff44b993a661cc45bf5dAki Tuomi
59cd0982252ea1a416f9ed04fd083697ba31fb3aStephan Bosch if (plclient->to_kill != NULL)
6aecc29b894bf0eb6784d212eec13cb37c72951cStephan Bosch plclient->to_kill = io_loop_move_timeout(&plclient->to_kill);
0043fea12a75cf8fcf2892673106844376da8e76Stephan Bosch child_wait_switch_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}