Exemple #1
0
void    master_reap_child(void)
{
    MASTER_SERV *serv;
    MASTER_PROC *proc;
    MASTER_PID pid;
    WAIT_STATUS_T status;

    /*
     * Pick up termination status of all dead children. When a process failed
     * on its first job, assume we see the symptom of a structural problem
     * (configuration problem, system running out of resources) and back off.
     */
    while ((pid = waitpid((pid_t) - 1, &status, WNOHANG)) > 0) {
	if (msg_verbose)
	    msg_info("master_reap_child: pid %d", pid);
	if ((proc = (MASTER_PROC *) binhash_find(master_child_table,
					  (void *) &pid, sizeof(pid))) == 0)
	    msg_panic("master_reap: unknown pid: %d", pid);
	serv = proc->serv;

#define MASTER_KILL_SIGNAL	SIGTERM
#define MASTER_SENT_SIGNAL(serv, status) \
	(MASTER_MARKED_FOR_DELETION(serv) \
	    && WTERMSIG(status) == MASTER_KILL_SIGNAL)

	/*
	 * XXX The code for WIFSTOPPED() is here in case some buggy kernel
	 * reports WIFSTOPPED() events to a Postfix daemon's parent process
	 * (the master(8) daemon) instead of the tracing process (e.g., gdb).
	 * 
	 * The WIFSTOPPED() test prevents master(8) from deleting its record of
	 * a child process that is stopped. That would cause a master(8)
	 * panic (unknown child) when the child terminates.
	 */
	if (!NORMAL_EXIT_STATUS(status)) {
	    if (WIFSTOPPED(status)) {
		msg_warn("process %s pid %d stopped by signal %d",
			 serv->path, pid, WSTOPSIG(status));
		continue;
	    }
	    if (WIFEXITED(status))
		msg_warn("process %s pid %d exit status %d",
			 serv->path, pid, WEXITSTATUS(status));
	    if (WIFSIGNALED(status) && !MASTER_SENT_SIGNAL(serv, status))
		msg_warn("process %s pid %d killed by signal %d",
			 serv->path, pid, WTERMSIG(status));
	    /* master_delete_children() throttles first, then kills. */
	    if (proc->use_count == 0
		&& (serv->flags & MASTER_FLAG_THROTTLE) == 0) {
		msg_warn("%s: bad command startup -- throttling", serv->path);
		master_throttle(serv);
	    }
	}
	master_delete_child(proc);
    }
}
Exemple #2
0
static void spawn_service(VSTREAM *client_stream, char *service, char **argv)
{
    const char *myname = "spawn_service";
    static SPAWN_ATTR attr;
    WAIT_STATUS_T status;
    ARGV   *export_env;

    /*
     * This routine runs whenever a client connects to the UNIX-domain socket
     * dedicated to running an external command.
     */
    if (msg_verbose)
	msg_info("%s: service=%s, command=%s...", myname, service, argv[0]);

    /*
     * Look up service attributes and config information only once. This is
     * safe since the information comes from a trusted source.
     */
    if (attr.argv == 0) {
	get_service_attr(&attr, service, argv);
    }

    /*
     * Execute the command.
     */
    export_env = mail_parm_split(VAR_EXPORT_ENVIRON, var_export_environ);
    status = spawn_command(CA_SPAWN_CMD_STDIN(vstream_fileno(client_stream)),
			 CA_SPAWN_CMD_STDOUT(vstream_fileno(client_stream)),
			 CA_SPAWN_CMD_STDERR(vstream_fileno(client_stream)),
			   CA_SPAWN_CMD_UID(attr.uid),
			   CA_SPAWN_CMD_GID(attr.gid),
			   CA_SPAWN_CMD_ARGV(attr.argv),
			   CA_SPAWN_CMD_TIME_LIMIT(attr.time_limit),
			   CA_SPAWN_CMD_EXPORT(export_env->argv),
			   CA_SPAWN_CMD_END);
    argv_free(export_env);

    /*
     * Warn about unsuccessful completion.
     */
    if (!NORMAL_EXIT_STATUS(status)) {
	if (WIFEXITED(status))
	    msg_warn("command %s exit status %d",
		     attr.argv[0], WEXITSTATUS(status));
	if (WIFSIGNALED(status))
	    msg_warn("command %s killed by signal %d",
		     attr.argv[0], WTERMSIG(status));
    }
}