Index | Thread | Search

From:
"Theo de Raadt" <deraadt@openbsd.org>
Subject:
Re: smtpd: create startup.c
To:
Martijn van Duren <openbsd+tech@list.imperialat.at>
Cc:
tech@openbsd.org
Date:
Thu, 02 Jul 2026 08:43:51 -0600

Download raw body.

Thread
I think this is the right approach.  It will take a few steps to see
clearly how to split this (it is not going to split the way sshd did).

> Here's a followup to the shuffling of the deckchairs diff. This diff is
> basically more of the same, but creates a new startup.c for functions
> and variables that would cause issues for smtpctl when added to util.c.
> 
> I realize that startup.c isn't an ideal name, but since it's needed give
> each libexec binary their own main() function it's the best I could come
> up with.
> 
> This diff moves the env, p_*, profiling, backend_*, smtpd_process
> variables, and imsg_callback, and setup_peer(), setup_proc(),
> imsg_wait(), load_pki_tree(), load_pki_keys(), fork_proc_backend(),
> and imsg_dispatch() functions into startup.c.
> 
> The debug variable appears to be a dead store, so can be removed.
> 
> The next step is giving each binary their own main().
> 
> OK?
> 
> martijn@
> 
> diff d010102fe4efde3ee95164581695909c7c6b672a 7c135bf813cf25880851c83cbd4734bfe1ac67c3
> commit - d010102fe4efde3ee95164581695909c7c6b672a
> commit + 7c135bf813cf25880851c83cbd4734bfe1ac67c3
> blob - a6337c2bb329e27300a21ffa517a5a84d0f773c5
> blob + 37b6919a9da103b0f3ce6bccfcb98f6dd5a47d6e
> --- usr.sbin/smtpd/smtpd/Makefile
> +++ usr.sbin/smtpd/smtpd/Makefile
> @@ -14,7 +14,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 206cd414a29ac4acbb22b6a540c5ca2751098e90
> blob + a00f8c6d79b8fea6b9071776ced8a909654aefd4
> --- usr.sbin/smtpd/smtpd-ca/Makefile
> +++ usr.sbin/smtpd/smtpd-ca/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 22d7abdc025cccaec993ecec8f4ab7c4377fd8b3
> blob + d289b421744c03b32a2296c421e9f3734cd44089
> --- usr.sbin/smtpd/smtpd-control/Makefile
> +++ usr.sbin/smtpd/smtpd-control/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 9aa8e1c7ceb3112f7aaba17352f5b5aa3b242bf7
> blob + f4c47fd8387e2bf7ee7c22a395f5e74b099be30d
> --- usr.sbin/smtpd/smtpd-dispatcher/Makefile
> +++ usr.sbin/smtpd/smtpd-dispatcher/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 03476d16571fc4fb85105215a79543bfb9882166
> blob + 0b82bec27876d79e60fa80a4a65436fe3633142e
> --- usr.sbin/smtpd/smtpd-lka/Makefile
> +++ usr.sbin/smtpd/smtpd-lka/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 6fce8a91f1035dffdd28a98bb546d0ed5c62b977
> blob + 7b6651dbeda248bc110f0b655118e59e23dfd9b2
> --- usr.sbin/smtpd/smtpd-queue/Makefile
> +++ usr.sbin/smtpd/smtpd-queue/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 93076c8a5241d7202b0810b4d3d723377dbaba1d
> blob + d26854ca8cd02f506b2c4ebaf93fc204f0130a2c
> --- usr.sbin/smtpd/smtpd-scheduler/Makefile
> +++ usr.sbin/smtpd/smtpd-scheduler/Makefile
> @@ -15,7 +15,7 @@ SRCS=	aliases.c bounce.c ca.c compress_backend.c confi
>  	dispatcher.c proxy.c queue.c queue_backend.c report_smtp.c \
>  	resolver.c rfc5322.c ruleset.c runq.c scheduler.c \
>  	scheduler_backend.c smtp.c smtp_session.c smtpd.c srs.c ssl.c \
> -	stat_backend.c table.c to.c tree.c util.c waitq.c \
> +	startup.c stat_backend.c table.c to.c tree.c util.c waitq.c \
>  	compress_gzip.c table_db.c table_getpwnam.c table_proc.c \
>  	table_static.c queue_fs.c queue_null.c queue_proc.c \
>  	queue_ram.c scheduler_ramqueue.c scheduler_null.c \
> blob - 7292b6810caaa49358b7b92ef3f26ade95d2ea42
> blob + de95861f48bf015b5cc1cce1857a8318d266111b
> --- usr.sbin/smtpd/smtpd.c
> +++ usr.sbin/smtpd/smtpd.c
> @@ -59,12 +59,8 @@ static void forkmda(struct mproc *, uint64_t, struct d
>  static int parent_forward_open(char *, char *, uid_t, gid_t);
>  static struct child *child_add(pid_t, int, const char *);
>  static struct mproc *start_child(int, char **, char *);
> -static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int);
>  static void setup_peers(struct mproc *, struct mproc *);
>  static void setup_done(struct mproc *);
> -static void setup_proc(void);
> -static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int);
> -static int imsg_wait(struct imsgbuf *, struct imsg *, int);
>  
>  static void	offline_scan(int, short, void *);
>  static int	offline_add(char *, uid_t, gid_t);
> @@ -73,8 +69,6 @@ static int	offline_enqueue(char *, uid_t, gid_t);
>  
>  static void	purge_task(void);
>  static int	parent_auth_user(const char *, const char *);
> -static void	load_pki_tree(void);
> -static void	load_pki_keys(void);
>  
>  static void	fork_filter_processes(void);
>  static void	fork_filter_process(const char *, struct filter_proc *);
> @@ -115,26 +109,11 @@ static struct timeval		offline_timeout;
>  static pid_t			purge_pid = -1;
>  
>  extern char	**environ;
> -void		(*imsg_callback)(struct mproc *, struct imsg *);
>  
> -enum smtp_proc_type	smtpd_process;
> +extern const char	*backend_queue;
> +extern const char	*backend_scheduler;
> +extern const char	*backend_stat;
>  
> -struct smtpd	*env = NULL;
> -
> -struct mproc	*p_control = NULL;
> -struct mproc	*p_lka = NULL;
> -struct mproc	*p_parent = NULL;
> -struct mproc	*p_queue = NULL;
> -struct mproc	*p_scheduler = NULL;
> -struct mproc	*p_dispatcher = NULL;
> -struct mproc	*p_ca = NULL;
> -
> -const char	*backend_queue = "fs";
> -const char	*backend_scheduler = "ramqueue";
> -const char	*backend_stat = "ram";
> -
> -int	profiling = 0;
> -int	debug = 0;
>  int	foreground = 0;
>  int	control_socket = -1;
>  
> @@ -483,7 +462,6 @@ main(int argc, char *argv[])
>  
>  	flags = 0;
>  	opts = 0;
> -	debug = 0;
>  	tracing = 0;
>  
>  	log_init(1, LOG_MAIL);
> @@ -523,7 +501,6 @@ main(int argc, char *argv[])
>  			usage();
>  			break;
>  		case 'n':
> -			debug = 2;
>  			opts |= SMTPD_OPT_NOACTION;
>  			break;
>  		case 'f':
> @@ -902,136 +879,6 @@ setup_done(struct mproc *p)
>  	imsg_free(&imsg);
>  }
>  
> -static void
> -setup_proc(void)
> -{
> -	struct imsgbuf *ibuf;
> -	struct imsg imsg;
> -        int setup = 1;
> -
> -	log_procinit(proc_title(smtpd_process));
> -
> -	p_parent = calloc(1, sizeof(*p_parent));
> -	if (p_parent == NULL)
> -		fatal("calloc");
> -	if((p_parent->name = strdup("parent")) == NULL)
> -		fatal("strdup");
> -	p_parent->proc = PROC_PARENT;
> -	p_parent->handler = imsg_dispatch;
> -	mproc_init(p_parent, 3);
> -
> -	ibuf = &p_parent->imsgbuf;
> -
> -	while (setup) {
> -		if (imsg_wait(ibuf, &imsg, 10000) == -1)
> -			fatal("imsg_wait");
> -
> -		switch (imsg.hdr.type) {
> -		case IMSG_SETUP_KEY:
> -			env->sc_queue_key = strdup(imsg.data);
> -			break;
> -		case IMSG_SETUP_PEER:
> -			setup_peer(imsg.hdr.peerid, imsg.hdr.pid,
> -			    imsg_get_fd(&imsg));
> -			break;
> -		case IMSG_SETUP_DONE:
> -			setup = 0;
> -			break;
> -		default:
> -			fatal("bad imsg %d", imsg.hdr.type);
> -		}
> -		imsg_free(&imsg);
> -	}
> -
> -	if (imsg_compose(ibuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1)
> -		fatal("imsg_compose");
> -
> -	if (imsgbuf_flush(ibuf) == -1)
> -		fatal("imsgbuf_flush");
> -
> -	log_debug("setup_proc: %s done", proc_title(smtpd_process));
> -}
> -
> -static struct mproc *
> -setup_peer(enum smtp_proc_type proc, pid_t pid, int sock)
> -{
> -	struct mproc *p, **pp;
> -
> -	log_debug("setup_peer: %s -> %s[%u] fd=%d", proc_title(smtpd_process),
> -	    proc_title(proc), pid, sock);
> -
> -	if (sock == -1)
> -		fatalx("peer socket not received");
> -
> -	switch (proc) {
> -	case PROC_LKA:
> -		pp = &p_lka;
> -		break;
> -	case PROC_QUEUE:
> -		pp = &p_queue;
> -		break;
> -	case PROC_CONTROL:
> -		pp = &p_control;
> -		break;
> -	case PROC_SCHEDULER:
> -		pp = &p_scheduler;
> -		break;
> -	case PROC_DISPATCHER:
> -		pp = &p_dispatcher;
> -		break;
> -	case PROC_CA:
> -		pp = &p_ca;
> -		break;
> -	default:
> -		fatalx("unknown peer");
> -	}
> -
> -	if (*pp)
> -		fatalx("peer already set");
> -
> -	p = calloc(1, sizeof(*p));
> -	if (p == NULL)
> -		fatal("calloc");
> -	if((p->name = strdup(proc_title(proc))) == NULL)
> -		fatal("strdup");
> -	mproc_init(p, sock);
> -	p->pid = pid;
> -	p->proc = proc;
> -	p->handler = imsg_dispatch;
> -
> -	*pp = p;
> -
> -	return p;
> -}
> -
> -static int
> -imsg_wait(struct imsgbuf *ibuf, struct imsg *imsg, int timeout)
> -{
> -	struct pollfd pfd[1];
> -	ssize_t n;
> -
> -	pfd[0].fd = ibuf->fd;
> -	pfd[0].events = POLLIN;
> -
> -	while (1) {
> -		if ((n = imsg_get(ibuf, imsg)) == -1)
> -			return -1;
> -		if (n)
> -			return 1;
> -
> -		n = poll(pfd, 1, timeout);
> -		if (n == -1)
> -			return -1;
> -		if (n == 0) {
> -			errno = ETIMEDOUT;
> -			return -1;
> -		}
> -
> -		if (imsgbuf_read(ibuf) != 1)
> -			return -1;
> -	}
> -}
> -
>  int
>  smtpd(void) {
>  	struct event	 ev_sigint;
> @@ -1093,111 +940,6 @@ smtpd(void) {
>  	return (0);
>  }
>  
> -static void
> -load_pki_tree(void)
> -{
> -	struct pki	*pki;
> -	struct ca	*sca;
> -	const char	*k;
> -	void		*iter_dict;
> -
> -	log_debug("debug: init ssl-tree");
> -	iter_dict = NULL;
> -	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
> -		log_debug("info: loading pki information for %s", k);
> -		if (pki->pki_cert_file == NULL)
> -			fatalx("load_pki_tree: missing certificate file");
> -		if (pki->pki_key_file == NULL)
> -			fatalx("load_pki_tree: missing key file");
> -
> -		if (!ssl_load_certificate(pki, pki->pki_cert_file))
> -			fatalx("load_pki_tree: failed to load certificate file");
> -	}
> -
> -	log_debug("debug: init ca-tree");
> -	iter_dict = NULL;
> -	while (dict_iter(env->sc_ca_dict, &iter_dict, &k, (void **)&sca)) {
> -		log_debug("info: loading CA information for %s", k);
> -		if (!ssl_load_cafile(sca, sca->ca_cert_file))
> -			fatalx("load_pki_tree: failed to load CA file");
> -	}
> -}
> -
> -void
> -load_pki_keys(void)
> -{
> -	struct pki	*pki;
> -	const char	*k;
> -	void		*iter_dict;
> -
> -	log_debug("debug: init ssl-tree");
> -	iter_dict = NULL;
> -	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
> -		log_debug("info: loading pki keys for %s", k);
> -
> -		if (!ssl_load_keyfile(pki, pki->pki_key_file, k))
> -			fatalx("load_pki_keys: failed to load key file");
> -	}
> -}
> -
> -int
> -fork_proc_backend(const char *key, const char *conf, const char *procname,
> -    int do_stdout)
> -{
> -	pid_t		pid;
> -	int		sp[2];
> -	char		path[PATH_MAX];
> -	char		name[PATH_MAX];
> -	char		*arg;
> -
> -	if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) {
> -		log_warnx("warn: %s-proc: conf too long", key);
> -		return (-1);
> -	}
> -
> -	arg = strchr(name, ':');
> -	if (arg)
> -		*arg++ = '\0';
> -
> -	if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >=
> -	    (ssize_t)sizeof(path)) {
> -		log_warn("warn: %s-proc: exec path too long", key);
> -		return (-1);
> -	}
> -
> -	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
> -		log_warn("warn: %s-proc: socketpair", key);
> -		return (-1);
> -	}
> -
> -	if ((pid = fork()) == -1) {
> -		log_warn("warn: %s-proc: fork", key);
> -		close(sp[0]);
> -		close(sp[1]);
> -		return (-1);
> -	}
> -
> -	if (pid == 0) {
> -		/* child process */
> -		dup2(sp[0], STDIN_FILENO);
> -		if (do_stdout)
> -			dup2(sp[0], STDOUT_FILENO);
> -		if (closefrom(STDERR_FILENO + 1) == -1)
> -			exit(1);
> -
> -		if (procname == NULL)
> -			procname = name;
> -
> -		execl(path, procname, arg, (char *)NULL);
> -		fatal("execl: %s", path);
> -	}
> -
> -	/* parent process */
> -	close(sp[0]);
> -
> -	return (sp[1]);
> -}
> -
>  struct child *
>  child_add(pid_t pid, int type, const char *title)
>  {
> @@ -1835,54 +1577,6 @@ parent_forward_open(char *username, char *directory, u
>  	return fd;
>  }
>  
> -void
> -imsg_dispatch(struct mproc *p, struct imsg *imsg)
> -{
> -	struct timespec	t0, t1, dt;
> -	int		msg;
> -
> -	if (imsg == NULL) {
> -		imsg_callback(p, imsg);
> -		return;
> -	}
> -
> -	log_imsg(smtpd_process, p->proc, imsg);
> -
> -	if (profiling & PROFILE_IMSG)
> -		clock_gettime(CLOCK_MONOTONIC, &t0);
> -
> -	msg = imsg->hdr.type;
> -	imsg_callback(p, imsg);
> -
> -	if (profiling & PROFILE_IMSG) {
> -		clock_gettime(CLOCK_MONOTONIC, &t1);
> -		timespecsub(&t1, &t0, &dt);
> -
> -		log_debug("profile-imsg: %s %s %s %d %lld.%09ld",
> -		    proc_name(smtpd_process),
> -		    proc_name(p->proc),
> -		    imsg_to_str(msg),
> -		    (int)imsg->hdr.len,
> -		    (long long)dt.tv_sec,
> -		    dt.tv_nsec);
> -
> -		if (profiling & PROFILE_TOSTAT) {
> -			char	key[STAT_KEY_SIZE];
> -			/* can't profstat control process yet */
> -			if (smtpd_process == PROC_CONTROL)
> -				return;
> -
> -			if (!bsnprintf(key, sizeof key,
> -				"profiling.imsg.%s.%s.%s",
> -				proc_name(smtpd_process),
> -				proc_name(p->proc),
> -				imsg_to_str(msg)))
> -				return;
> -			stat_set(key, stat_timespec(&dt));
> -		}
> -	}
> -}
> -
>  int
>  parent_auth_user(const char *username, const char *password)
>  {
> blob - b8268d69c6985d4d42234b550c8cfe6086d465b3
> blob + fe8bcb8204fbf40110bcecfdf4ee634876b35013
> --- usr.sbin/smtpd/smtpd.h
> +++ usr.sbin/smtpd/smtpd.h
> @@ -1614,6 +1614,12 @@ const char *srs_encode(const char *, const char *);
>  const char *srs_decode(const char *);
>  
>  
> +/* startup.c */
> +void setup_proc(void);
> +int imsg_wait(struct imsgbuf *, struct imsg *, int);
> +void load_pki_tree(void);
> +void load_pki_keys(void);
> +
>  /* stat_backend.c */
>  struct stat_backend	*stat_backend_lookup(const char *);
>  void	stat_increment(const char *, size_t);
> blob - /dev/null
> blob + 8195f93b98fd0b9a8bd5993d675cc69cc2ce4287 (mode 644)
> --- /dev/null
> +++ usr.sbin/smtpd/startup.c
> @@ -0,0 +1,332 @@
> +/*	$OpenBSD$	*/
> +
> +/*
> + * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
> + * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
> + * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <errno.h>
> +#include <poll.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include "smtpd.h"
> +#include "log.h"
> +#include "ssl.h"
> +
> +struct smtpd		*env = NULL;
> +
> +struct mproc		*p_control = NULL;
> +struct mproc		*p_lka = NULL;
> +struct mproc		*p_parent = NULL;
> +struct mproc		*p_queue = NULL;
> +struct mproc		*p_scheduler = NULL;
> +struct mproc		*p_dispatcher = NULL;
> +struct mproc		*p_ca = NULL;
> +
> +int			 profiling = 0;
> +
> +enum smtp_proc_type	 smtpd_process;
> +
> +const char		*backend_queue = "fs";
> +const char		*backend_scheduler = "ramqueue";
> +const char		*backend_stat = "ram";
> +
> +void (*imsg_callback)(struct mproc *, struct imsg *);
> +
> +static struct mproc *
> +setup_peer(enum smtp_proc_type proc, pid_t pid, int sock)
> +{
> +	struct mproc *p, **pp;
> +
> +	log_debug("setup_peer: %s -> %s[%u] fd=%d", proc_title(smtpd_process),
> +	    proc_title(proc), pid, sock);
> +
> +	if (sock == -1)
> +		fatalx("peer socket not received");
> +
> +	switch (proc) {
> +	case PROC_LKA:
> +		pp = &p_lka;
> +		break;
> +	case PROC_QUEUE:
> +		pp = &p_queue;
> +		break;
> +	case PROC_CONTROL:
> +		pp = &p_control;
> +		break;
> +	case PROC_SCHEDULER:
> +		pp = &p_scheduler;
> +		break;
> +	case PROC_DISPATCHER:
> +		pp = &p_dispatcher;
> +		break;
> +	case PROC_CA:
> +		pp = &p_ca;
> +		break;
> +	default:
> +		fatalx("unknown peer");
> +	}
> +
> +	if (*pp)
> +		fatalx("peer already set");
> +
> +	p = calloc(1, sizeof(*p));
> +	if (p == NULL)
> +		fatal("calloc");
> +	if((p->name = strdup(proc_title(proc))) == NULL)
> +		fatal("strdup");
> +	mproc_init(p, sock);
> +	p->pid = pid;
> +	p->proc = proc;
> +	p->handler = imsg_dispatch;
> +
> +	*pp = p;
> +
> +	return p;
> +}
> +
> +void
> +setup_proc(void)
> +{
> +	struct imsgbuf *ibuf;
> +	struct imsg imsg;
> +        int setup = 1;
> +
> +	log_procinit(proc_title(smtpd_process));
> +
> +	p_parent = calloc(1, sizeof(*p_parent));
> +	if (p_parent == NULL)
> +		fatal("calloc");
> +	if((p_parent->name = strdup("parent")) == NULL)
> +		fatal("strdup");
> +	p_parent->proc = PROC_PARENT;
> +	p_parent->handler = imsg_dispatch;
> +	mproc_init(p_parent, 3);
> +
> +	ibuf = &p_parent->imsgbuf;
> +
> +	while (setup) {
> +		if (imsg_wait(ibuf, &imsg, 10000) == -1)
> +			fatal("imsg_wait");
> +
> +		switch (imsg.hdr.type) {
> +		case IMSG_SETUP_KEY:
> +			env->sc_queue_key = strdup(imsg.data);
> +			break;
> +		case IMSG_SETUP_PEER:
> +			setup_peer(imsg.hdr.peerid, imsg.hdr.pid,
> +			    imsg_get_fd(&imsg));
> +			break;
> +		case IMSG_SETUP_DONE:
> +			setup = 0;
> +			break;
> +		default:
> +			fatal("bad imsg %d", imsg.hdr.type);
> +		}
> +		imsg_free(&imsg);
> +	}
> +
> +	if (imsg_compose(ibuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1)
> +		fatal("imsg_compose");
> +
> +	if (imsgbuf_flush(ibuf) == -1)
> +		fatal("imsgbuf_flush");
> +
> +	log_debug("setup_proc: %s done", proc_title(smtpd_process));
> +}
> +
> +int
> +imsg_wait(struct imsgbuf *ibuf, struct imsg *imsg, int timeout)
> +{
> +	struct pollfd pfd[1];
> +	ssize_t n;
> +
> +	pfd[0].fd = ibuf->fd;
> +	pfd[0].events = POLLIN;
> +
> +	while (1) {
> +		if ((n = imsg_get(ibuf, imsg)) == -1)
> +			return -1;
> +		if (n)
> +			return 1;
> +
> +		n = poll(pfd, 1, timeout);
> +		if (n == -1)
> +			return -1;
> +		if (n == 0) {
> +			errno = ETIMEDOUT;
> +			return -1;
> +		}
> +
> +		if (imsgbuf_read(ibuf) != 1)
> +			return -1;
> +	}
> +}
> +
> +void
> +load_pki_tree(void)
> +{
> +	struct pki	*pki;
> +	struct ca	*sca;
> +	const char	*k;
> +	void		*iter_dict;
> +
> +	log_debug("debug: init ssl-tree");
> +	iter_dict = NULL;
> +	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
> +		log_debug("info: loading pki information for %s", k);
> +		if (pki->pki_cert_file == NULL)
> +			fatalx("load_pki_tree: missing certificate file");
> +		if (pki->pki_key_file == NULL)
> +			fatalx("load_pki_tree: missing key file");
> +
> +		if (!ssl_load_certificate(pki, pki->pki_cert_file))
> +			fatalx("load_pki_tree: failed to load certificate file");
> +	}
> +
> +	log_debug("debug: init ca-tree");
> +	iter_dict = NULL;
> +	while (dict_iter(env->sc_ca_dict, &iter_dict, &k, (void **)&sca)) {
> +		log_debug("info: loading CA information for %s", k);
> +		if (!ssl_load_cafile(sca, sca->ca_cert_file))
> +			fatalx("load_pki_tree: failed to load CA file");
> +	}
> +}
> +
> +void
> +load_pki_keys(void)
> +{
> +	struct pki	*pki;
> +	const char	*k;
> +	void		*iter_dict;
> +
> +	log_debug("debug: init ssl-tree");
> +	iter_dict = NULL;
> +	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
> +		log_debug("info: loading pki keys for %s", k);
> +
> +		if (!ssl_load_keyfile(pki, pki->pki_key_file, k))
> +			fatalx("load_pki_keys: failed to load key file");
> +	}
> +}
> +
> +int
> +fork_proc_backend(const char *key, const char *conf, const char *procname,
> +    int do_stdout)
> +{
> +	pid_t		pid;
> +	int		sp[2];
> +	char		path[PATH_MAX];
> +	char		name[PATH_MAX];
> +	char		*arg;
> +
> +	if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) {
> +		log_warnx("warn: %s-proc: conf too long", key);
> +		return (-1);
> +	}
> +
> +	arg = strchr(name, ':');
> +	if (arg)
> +		*arg++ = '\0';
> +
> +	if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >=
> +	    (ssize_t)sizeof(path)) {
> +		log_warn("warn: %s-proc: exec path too long", key);
> +		return (-1);
> +	}
> +
> +	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
> +		log_warn("warn: %s-proc: socketpair", key);
> +		return (-1);
> +	}
> +
> +	if ((pid = fork()) == -1) {
> +		log_warn("warn: %s-proc: fork", key);
> +		close(sp[0]);
> +		close(sp[1]);
> +		return (-1);
> +	}
> +
> +	if (pid == 0) {
> +		/* child process */
> +		dup2(sp[0], STDIN_FILENO);
> +		if (do_stdout)
> +			dup2(sp[0], STDOUT_FILENO);
> +		if (closefrom(STDERR_FILENO + 1) == -1)
> +			exit(1);
> +
> +		if (procname == NULL)
> +			procname = name;
> +
> +		execl(path, procname, arg, (char *)NULL);
> +		fatal("execl: %s", path);
> +	}
> +
> +	/* parent process */
> +	close(sp[0]);
> +
> +	return (sp[1]);
> +}
> +
> +void
> +imsg_dispatch(struct mproc *p, struct imsg *imsg)
> +{
> +	struct timespec	t0, t1, dt;
> +	int		msg;
> +
> +	if (imsg == NULL) {
> +		imsg_callback(p, imsg);
> +		return;
> +	}
> +
> +	log_imsg(smtpd_process, p->proc, imsg);
> +
> +	if (profiling & PROFILE_IMSG)
> +		clock_gettime(CLOCK_MONOTONIC, &t0);
> +
> +	msg = imsg->hdr.type;
> +	imsg_callback(p, imsg);
> +
> +	if (profiling & PROFILE_IMSG) {
> +		clock_gettime(CLOCK_MONOTONIC, &t1);
> +		timespecsub(&t1, &t0, &dt);
> +
> +		log_debug("profile-imsg: %s %s %s %d %lld.%09ld",
> +		    proc_name(smtpd_process),
> +		    proc_name(p->proc),
> +		    imsg_to_str(msg),
> +		    (int)imsg->hdr.len,
> +		    (long long)dt.tv_sec,
> +		    dt.tv_nsec);
> +
> +		if (profiling & PROFILE_TOSTAT) {
> +			char	key[STAT_KEY_SIZE];
> +			/* can't profstat control process yet */
> +			if (smtpd_process == PROC_CONTROL)
> +				return;
> +
> +			if (!bsnprintf(key, sizeof key,
> +				"profiling.imsg.%s.%s.%s",
> +				proc_name(smtpd_process),
> +				proc_name(p->proc),
> +				imsg_to_str(msg)))
> +				return;
> +			stat_set(key, stat_timespec(&dt));
> +		}
> +	}
> +}
>