xref: /netbsd-src/external/ibm-public/postfix/dist/src/master/event_server.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: event_server.c,v 1.1.1.2 2011/03/02 19:32:20 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	event_server 3
6 /* SUMMARY
7 /*	skeleton multi-threaded mail subsystem
8 /* SYNOPSIS
9 /*	#include <mail_server.h>
10 /*
11 /*	NORETURN event_server_main(argc, argv, service, key, value, ...)
12 /*	int	argc;
13 /*	char	**argv;
14 /*	void	(*service)(VSTREAM *stream, char *service_name, char **argv);
15 /*	int	key;
16 /*
17 /*	void	event_server_disconnect(fd)
18 /*	VSTREAM	*stream;
19 /*
20 /*	void	event_server_drain()
21 /* DESCRIPTION
22 /*	This module implements a skeleton for multi-threaded
23 /*	mail subsystems: mail subsystem programs that service multiple
24 /*	clients at the same time. The resulting program expects to be run
25 /*	from the \fBmaster\fR process.
26 /*
27 /*	event_server_main() is the skeleton entry point. It should be
28 /*	called from the application main program.  The skeleton does all
29 /*	the generic command-line processing, initialization of
30 /*	configurable parameters, and connection management.
31 /*	Unlike multi_server, this skeleton does not attempt to manage
32 /*	all the events on a client connection.
33 /*	The skeleton never returns.
34 /*
35 /*	Arguments:
36 /* .IP "void (*service)(VSTREAM *stream, char *service_name, char **argv)"
37 /*	A pointer to a function that is called by the skeleton each
38 /*	time a client connects to the program's service port. The
39 /*	function is run after the program has optionally dropped
40 /*	its privileges. The application is responsible for managing
41 /*	subsequent I/O events on the stream, and is responsible for
42 /*	calling event_server_disconnect() when the stream is closed.
43 /*	The stream initial state is non-blocking mode.  The service
44 /*	name argument corresponds to the service name in the master.cf
45 /*	file.  The argv argument specifies command-line arguments
46 /*	left over after options processing.
47 /* .PP
48 /*	Optional arguments are specified as a null-terminated (key, value)
49 /*	list. Keys and expected values are:
50 /* .IP "MAIL_SERVER_INT_TABLE (CONFIG_INT_TABLE *)"
51 /*	A table with configurable parameters, to be loaded from the
52 /*	global Postfix configuration file. Tables are loaded in the
53 /*	order as specified, and multiple instances of the same type
54 /*	are allowed.
55 /* .IP "MAIL_SERVER_STR_TABLE (CONFIG_STR_TABLE *)"
56 /*	A table with configurable parameters, to be loaded from the
57 /*	global Postfix configuration file. Tables are loaded in the
58 /*	order as specified, and multiple instances of the same type
59 /*	are allowed.
60 /* .IP "MAIL_SERVER_BOOL_TABLE (CONFIG_BOOL_TABLE *)"
61 /*	A table with configurable parameters, to be loaded from the
62 /*	global Postfix configuration file. Tables are loaded in the
63 /*	order as specified, and multiple instances of the same type
64 /*	are allowed.
65 /* .IP "MAIL_SERVER_TIME_TABLE (CONFIG_TIME_TABLE *)"
66 /*	A table with configurable parameters, to be loaded from the
67 /*	global Postfix configuration file. Tables are loaded in the
68 /*	order as specified, and multiple instances of the same type
69 /*	are allowed.
70 /* .IP "MAIL_SERVER_RAW_TABLE (CONFIG_RAW_TABLE *)"
71 /*	A table with configurable parameters, to be loaded from the
72 /*	global Postfix configuration file. Tables are loaded in the
73 /*	order as specified, and multiple instances of the same type
74 /*	are allowed. Raw parameters are not subjected to $name
75 /*	evaluation.
76 /* .IP "MAIL_SERVER_NINT_TABLE (CONFIG_NINT_TABLE *)"
77 /*	A table with configurable parameters, to be loaded from the
78 /*	global Postfix configuration file. Tables are loaded in the
79 /*	order as specified, and multiple instances of the same type
80 /*	are allowed.
81 /* .IP "MAIL_SERVER_NBOOL_TABLE (CONFIG_NBOOL_TABLE *)"
82 /*	A table with configurable parameters, to be loaded from the
83 /*	global Postfix configuration file. Tables are loaded in the
84 /*	order as specified, and multiple instances of the same type
85 /*	are allowed.
86 /* .IP "MAIL_SERVER_PRE_INIT (void *(char *service_name, char **argv))"
87 /*	A pointer to a function that is called once
88 /*	by the skeleton after it has read the global configuration file
89 /*	and after it has processed command-line arguments, but before
90 /*	the skeleton has optionally relinquished the process privileges.
91 /* .sp
92 /*	Only the last instance of this parameter type is remembered.
93 /* .IP "MAIL_SERVER_POST_INIT (void *(char *service_name, char **argv))"
94 /*	A pointer to a function that is called once
95 /*	by the skeleton after it has optionally relinquished the process
96 /*	privileges, but before servicing client connection requests.
97 /* .sp
98 /*	Only the last instance of this parameter type is remembered.
99 /* .IP "MAIL_SERVER_LOOP (int *(char *service_name, char **argv))"
100 /*	A pointer to function that is executed from
101 /*	within the event loop, whenever an I/O or timer event has happened,
102 /*	or whenever nothing has happened for a specified amount of time.
103 /*	The result value of the function specifies how long to wait until
104 /*	the next event. Specify -1 to wait for "as long as it takes".
105 /* .sp
106 /*	Only the last instance of this parameter type is remembered.
107 /* .IP "MAIL_SERVER_EXIT (void *(char *service_name, char **argv))"
108 /*	A pointer to function that is executed immediately before normal
109 /*	process termination.
110 /* .IP "MAIL_SERVER_PRE_ACCEPT (void *(char *service_name, char **argv))"
111 /*	Function to be executed prior to accepting a new connection.
112 /* .sp
113 /*	Only the last instance of this parameter type is remembered.
114 /* .IP "MAIL_SERVER_PRE_DISCONN (VSTREAM *, char *service_name, char **argv)"
115 /*	A pointer to a function that is called
116 /*	by the event_server_disconnect() function (see below).
117 /* .sp
118 /*	Only the last instance of this parameter type is remembered.
119 /* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)"
120 /*	Pause $in_flow_delay seconds when no "mail flow control token"
121 /*	is available. A token is consumed for each connection request.
122 /* .IP MAIL_SERVER_SOLITARY
123 /*	This service must be configured with process limit of 1.
124 /* .IP MAIL_SERVER_UNLIMITED
125 /*	This service must be configured with process limit of 0.
126 /* .IP MAIL_SERVER_PRIVILEGED
127 /*	This service must be configured as privileged.
128 /* .IP "MAIL_SERVER_SLOW_EXIT (void *(char *service_name, char **argv))"
129 /*	A pointer to a function that is called after "postfix reload"
130 /*	or "master exit".  The application can call event_server_drain()
131 /*	(see below) to finish ongoing activities in the background.
132 /* .IP "MAIL_SERVER_WATCHDOG (int *)"
133 /*	Override the default 1000s watchdog timeout. The value is
134 /*	used after command-line and main.cf file processing.
135 /* .PP
136 /*	event_server_disconnect() should be called by the application
137 /*	to close a client connection.
138 /*
139 /*	event_server_drain() should be called when the application
140 /*	no longer wishes to accept new client connections. Existing
141 /*	clients are handled in a background process, and the process
142 /*	terminates when the last client is disconnected. A non-zero
143 /*	result means this call should be tried again later.
144 /*
145 /*	The var_use_limit variable limits the number of clients
146 /*	that a server can service before it commits suicide.  This
147 /*	value is taken from the global \fBmain.cf\fR configuration
148 /*	file. Setting \fBvar_use_limit\fR to zero disables the
149 /*	client limit.
150 /*
151 /*	The var_idle_limit variable limits the time that a service
152 /*	receives no client connection requests before it commits
153 /*	suicide.  This value is taken from the global \fBmain.cf\fR
154 /*	configuration file. Setting \fBvar_idle_limit\fR to zero
155 /*	disables the idle limit.
156 /* DIAGNOSTICS
157 /*	Problems and transactions are logged to \fBsyslogd\fR(8).
158 /* SEE ALSO
159 /*	master(8), master process
160 /*	syslogd(8) system logging
161 /* LICENSE
162 /* .ad
163 /* .fi
164 /*	The Secure Mailer license must be distributed with this software.
165 /* AUTHOR(S)
166 /*	Wietse Venema
167 /*	IBM T.J. Watson Research
168 /*	P.O. Box 704
169 /*	Yorktown Heights, NY 10598, USA
170 /*--*/
171 
172 /* System library. */
173 
174 #include <sys_defs.h>
175 #include <sys/socket.h>
176 #include <sys/time.h>			/* select() */
177 #include <unistd.h>
178 #include <signal.h>
179 #include <syslog.h>
180 #include <stdlib.h>
181 #include <limits.h>
182 #include <string.h>
183 #include <errno.h>
184 #include <fcntl.h>
185 #include <stdarg.h>
186 #ifdef STRCASECMP_IN_STRINGS_H
187 #include <strings.h>
188 #endif
189 #include <time.h>
190 
191 #ifdef USE_SYS_SELECT_H
192 #include <sys/select.h>			/* select() */
193 #endif
194 
195 /* Utility library. */
196 
197 #include <msg.h>
198 #include <msg_syslog.h>
199 #include <msg_vstream.h>
200 #include <chroot_uid.h>
201 #include <listen.h>
202 #include <events.h>
203 #include <vstring.h>
204 #include <vstream.h>
205 #include <msg_vstream.h>
206 #include <mymalloc.h>
207 #include <iostuff.h>
208 #include <stringops.h>
209 #include <sane_accept.h>
210 #include <myflock.h>
211 #include <safe_open.h>
212 #include <listen.h>
213 #include <watchdog.h>
214 #include <split_at.h>
215 
216 /* Global library. */
217 
218 #include <mail_task.h>
219 #include <debug_process.h>
220 #include <mail_params.h>
221 #include <mail_conf.h>
222 #include <mail_dict.h>
223 #include <timed_ipc.h>
224 #include <resolve_local.h>
225 #include <mail_flow.h>
226 
227 /* Process manager. */
228 
229 #include "master_proto.h"
230 
231 /* Application-specific */
232 
233 #include "mail_server.h"
234 
235  /*
236   * Global state.
237   */
238 static int client_count;
239 static int use_count;
240 static int socket_count = 1;
241 
242 static void (*event_server_service) (VSTREAM *, char *, char **);
243 static char *event_server_name;
244 static char **event_server_argv;
245 static void (*event_server_accept) (int, char *);
246 static void (*event_server_onexit) (char *, char **);
247 static void (*event_server_pre_accept) (char *, char **);
248 static VSTREAM *event_server_lock;
249 static int event_server_in_flow_delay;
250 static unsigned event_server_generation;
251 static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
252 static void (*event_server_slow_exit) (char *, char **);
253 static int event_server_watchdog = 1000;
254 
255 /* event_server_exit - normal termination */
256 
257 static NORETURN event_server_exit(void)
258 {
259     if (event_server_onexit)
260 	event_server_onexit(event_server_name, event_server_argv);
261     exit(0);
262 }
263 
264 /* event_server_abort - terminate after abnormal master exit */
265 
266 static void event_server_abort(int unused_event, char *unused_context)
267 {
268     if (msg_verbose)
269 	msg_info("master disconnect -- exiting");
270     event_disable_readwrite(MASTER_STATUS_FD);
271     if (event_server_slow_exit)
272 	event_server_slow_exit(event_server_name, event_server_argv);
273     else
274 	event_server_exit();
275 }
276 
277 /* event_server_timeout - idle time exceeded */
278 
279 static void event_server_timeout(int unused_event, char *unused_context)
280 {
281     if (msg_verbose)
282 	msg_info("idle timeout -- exiting");
283     event_server_exit();
284 }
285 
286 /*  event_server_drain - stop accepting new clients */
287 
288 int     event_server_drain(void)
289 {
290     const char *myname = "event_server_drain";
291     int     fd;
292 
293     switch (fork()) {
294 	/* Try again later. */
295     case -1:
296 	return (-1);
297 	/* Finish existing clients in the background, then terminate. */
298     case 0:
299 	(void) msg_cleanup((MSG_CLEANUP_FN) 0);
300 	event_fork();
301 	for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
302 	    event_disable_readwrite(fd);
303 	    (void) close(fd);
304 	    /* Play safe - don't reuse this file number. */
305 	    if (DUP2(STDIN_FILENO, fd) < 0)
306 		msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
307 	}
308 	var_use_limit = 1;
309 	return (0);
310 	/* Let the master start a new process. */
311     default:
312 	exit(0);
313     }
314 }
315 
316 /* event_server_disconnect - terminate client session */
317 
318 void    event_server_disconnect(VSTREAM *stream)
319 {
320     if (msg_verbose)
321 	msg_info("connection closed fd %d", vstream_fileno(stream));
322     if (event_server_pre_disconn)
323 	event_server_pre_disconn(stream, event_server_name, event_server_argv);
324     (void) vstream_fclose(stream);
325     client_count--;
326     /* Avoid integer wrap-around in a persistent process.  */
327     if (use_count < INT_MAX)
328 	use_count++;
329     if (client_count == 0 && var_idle_limit > 0)
330 	event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
331 }
332 
333 /* event_server_execute - in case (char *) != (struct *) */
334 
335 static void event_server_execute(int unused_event, char *context)
336 {
337     VSTREAM *stream = (VSTREAM *) context;
338 
339     if (event_server_lock != 0
340 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
341 		   MYFLOCK_OP_NONE) < 0)
342 	msg_fatal("select unlock: %m");
343 
344     /*
345      * Do bother the application when the client disconnected. Don't drop the
346      * already accepted client request after "postfix reload"; that would be
347      * rude.
348      */
349     if (master_notify(var_pid, event_server_generation, MASTER_STAT_TAKEN) < 0)
350 	 /* void */ ;
351     event_server_service(stream, event_server_name, event_server_argv);
352     if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
353 	event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
354 }
355 
356 /* event_server_wakeup - wake up application */
357 
358 static void event_server_wakeup(int fd)
359 {
360     VSTREAM *stream;
361     char   *tmp;
362 
363 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
364 #ifndef THRESHOLD_FD_WORKAROUND
365 #define THRESHOLD_FD_WORKAROUND 128
366 #endif
367     int     new_fd;
368 
369     /*
370      * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
371      * case of a multi-server with a thousand clients.
372      */
373     if (fd < THRESHOLD_FD_WORKAROUND) {
374 	if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
375 	    msg_fatal("fcntl F_DUPFD: %m");
376 	(void) close(fd);
377 	fd = new_fd;
378     }
379 #endif
380     if (msg_verbose)
381 	msg_info("connection established fd %d", fd);
382     non_blocking(fd, BLOCKING);
383     close_on_exec(fd, CLOSE_ON_EXEC);
384     client_count++;
385     stream = vstream_fdopen(fd, O_RDWR);
386     tmp = concatenate(event_server_name, " socket", (char *) 0);
387     vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
388     myfree(tmp);
389     timed_ipc_setup(stream);
390     if (event_server_in_flow_delay && mail_flow_get(1) < 0)
391 	event_request_timer(event_server_execute, (char *) stream,
392 			    var_in_flow_delay);
393     else
394 	event_server_execute(0, (char *) stream);
395 }
396 
397 /* event_server_accept_local - accept client connection request */
398 
399 static void event_server_accept_local(int unused_event, char *context)
400 {
401     int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
402     int     time_left = -1;
403     int     fd;
404 
405     /*
406      * Be prepared for accept() to fail because some other process already
407      * got the connection (the number of processes competing for clients is
408      * kept small, so this is not a "thundering herd" problem). If the
409      * accept() succeeds, be sure to disable non-blocking I/O, in order to
410      * minimize confusion.
411      */
412     if (client_count == 0 && var_idle_limit > 0)
413 	time_left = event_cancel_timer(event_server_timeout, (char *) 0);
414 
415     if (event_server_pre_accept)
416 	event_server_pre_accept(event_server_name, event_server_argv);
417     fd = LOCAL_ACCEPT(listen_fd);
418     if (event_server_lock != 0
419 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
420 		   MYFLOCK_OP_NONE) < 0)
421 	msg_fatal("select unlock: %m");
422     if (fd < 0) {
423 	if (errno != EAGAIN)
424 	    msg_error("accept connection: %m");
425 	if (time_left >= 0)
426 	    event_request_timer(event_server_timeout, (char *) 0, time_left);
427 	return;
428     }
429     event_server_wakeup(fd);
430 }
431 
432 #ifdef MASTER_XPORT_NAME_PASS
433 
434 /* event_server_accept_pass - accept descriptor */
435 
436 static void event_server_accept_pass(int unused_event, char *context)
437 {
438     int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
439     int     time_left = -1;
440     int     fd;
441 
442     /*
443      * Be prepared for accept() to fail because some other process already
444      * got the connection (the number of processes competing for clients is
445      * kept small, so this is not a "thundering herd" problem). If the
446      * accept() succeeds, be sure to disable non-blocking I/O, in order to
447      * minimize confusion.
448      */
449     if (client_count == 0 && var_idle_limit > 0)
450 	time_left = event_cancel_timer(event_server_timeout, (char *) 0);
451 
452     if (event_server_pre_accept)
453 	event_server_pre_accept(event_server_name, event_server_argv);
454     fd = PASS_ACCEPT(listen_fd);
455     if (event_server_lock != 0
456 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
457 		   MYFLOCK_OP_NONE) < 0)
458 	msg_fatal("select unlock: %m");
459     if (fd < 0) {
460 	if (errno != EAGAIN)
461 	    msg_error("accept connection: %m");
462 	if (time_left >= 0)
463 	    event_request_timer(event_server_timeout, (char *) 0, time_left);
464 	return;
465     }
466     event_server_wakeup(fd);
467 }
468 
469 #endif
470 
471 /* event_server_accept_inet - accept client connection request */
472 
473 static void event_server_accept_inet(int unused_event, char *context)
474 {
475     int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
476     int     time_left = -1;
477     int     fd;
478 
479     /*
480      * Be prepared for accept() to fail because some other process already
481      * got the connection (the number of processes competing for clients is
482      * kept small, so this is not a "thundering herd" problem). If the
483      * accept() succeeds, be sure to disable non-blocking I/O, in order to
484      * minimize confusion.
485      */
486     if (client_count == 0 && var_idle_limit > 0)
487 	time_left = event_cancel_timer(event_server_timeout, (char *) 0);
488 
489     if (event_server_pre_accept)
490 	event_server_pre_accept(event_server_name, event_server_argv);
491     fd = inet_accept(listen_fd);
492     if (event_server_lock != 0
493 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
494 		   MYFLOCK_OP_NONE) < 0)
495 	msg_fatal("select unlock: %m");
496     if (fd < 0) {
497 	if (errno != EAGAIN)
498 	    msg_error("accept connection: %m");
499 	if (time_left >= 0)
500 	    event_request_timer(event_server_timeout, (char *) 0, time_left);
501 	return;
502     }
503     event_server_wakeup(fd);
504 }
505 
506 /* event_server_main - the real main program */
507 
508 NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
509 {
510     const char *myname = "event_server_main";
511     VSTREAM *stream = 0;
512     char   *root_dir = 0;
513     char   *user_name = 0;
514     int     debug_me = 0;
515     int     daemon_mode = 1;
516     char   *service_name = basename(argv[0]);
517     int     delay;
518     int     c;
519     int     fd;
520     va_list ap;
521     MAIL_SERVER_INIT_FN pre_init = 0;
522     MAIL_SERVER_INIT_FN post_init = 0;
523     MAIL_SERVER_LOOP_FN loop = 0;
524     int     key;
525     char   *transport = 0;
526 
527 #if 0
528     char   *lock_path;
529     VSTRING *why;
530 
531 #endif
532     int     alone = 0;
533     int     zerolimit = 0;
534     WATCHDOG *watchdog;
535     char   *oname_val;
536     char   *oname;
537     char   *oval;
538     const char *err;
539     char   *generation;
540     int     msg_vstream_needed = 0;
541     int     redo_syslog_init = 0;
542 
543     /*
544      * Process environment options as early as we can.
545      */
546     if (getenv(CONF_ENV_VERB))
547 	msg_verbose = 1;
548     if (getenv(CONF_ENV_DEBUG))
549 	debug_me = 1;
550 
551     /*
552      * Don't die when a process goes away unexpectedly.
553      */
554     signal(SIGPIPE, SIG_IGN);
555 
556     /*
557      * Don't die for frivolous reasons.
558      */
559 #ifdef SIGXFSZ
560     signal(SIGXFSZ, SIG_IGN);
561 #endif
562 
563     /*
564      * May need this every now and then.
565      */
566     var_procname = mystrdup(basename(argv[0]));
567     set_mail_conf_str(VAR_PROCNAME, var_procname);
568 
569     /*
570      * Initialize logging and exit handler. Do the syslog first, so that its
571      * initialization completes before we enter the optional chroot jail.
572      */
573     msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
574     if (msg_verbose)
575 	msg_info("daemon started");
576 
577     /*
578      * Initialize from the configuration file. Allow command-line options to
579      * override compiled-in defaults or configured parameter values.
580      */
581     mail_conf_suck();
582 
583     /*
584      * Register dictionaries that use higher-level interfaces and protocols.
585      */
586     mail_dict_init();
587 
588     /*
589      * Pick up policy settings from master process. Shut up error messages to
590      * stderr, because no-one is going to see them.
591      */
592     opterr = 0;
593     while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
594 	switch (c) {
595 	case 'c':
596 	    root_dir = "setme";
597 	    break;
598 	case 'd':
599 	    daemon_mode = 0;
600 	    break;
601 	case 'D':
602 	    debug_me = 1;
603 	    break;
604 	case 'i':
605 	    mail_conf_update(VAR_MAX_IDLE, optarg);
606 	    break;
607 	case 'l':
608 	    alone = 1;
609 	    break;
610 	case 'm':
611 	    mail_conf_update(VAR_MAX_USE, optarg);
612 	    break;
613 	case 'n':
614 	    service_name = optarg;
615 	    break;
616 	case 'o':
617 	    oname_val = mystrdup(optarg);
618 	    if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
619 		msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
620 	    mail_conf_update(oname, oval);
621 	    if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
622 		redo_syslog_init = 1;
623 	    myfree(oname_val);
624 	    break;
625 	case 's':
626 	    if ((socket_count = atoi(optarg)) <= 0)
627 		msg_fatal("invalid socket_count: %s", optarg);
628 	    break;
629 	case 'S':
630 	    stream = VSTREAM_IN;
631 	    break;
632 	case 'u':
633 	    user_name = "setme";
634 	    break;
635 	case 't':
636 	    transport = optarg;
637 	    break;
638 	case 'v':
639 	    msg_verbose++;
640 	    break;
641 	case 'V':
642 	    if (++msg_vstream_needed == 1)
643 		msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
644 	    break;
645 	case 'z':
646 	    zerolimit = 1;
647 	    break;
648 	default:
649 	    msg_fatal("invalid option: %c", c);
650 	    break;
651 	}
652     }
653 
654     /*
655      * Initialize generic parameters.
656      */
657     mail_params_init();
658     if (redo_syslog_init)
659 	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
660 
661     /*
662      * If not connected to stdin, stdin must not be a terminal.
663      */
664     if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
665 	msg_vstream_init(var_procname, VSTREAM_ERR);
666 	msg_fatal("do not run this command by hand");
667     }
668 
669     /*
670      * Application-specific initialization.
671      */
672     va_start(ap, service);
673     while ((key = va_arg(ap, int)) != 0) {
674 	switch (key) {
675 	case MAIL_SERVER_INT_TABLE:
676 	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
677 	    break;
678 	case MAIL_SERVER_STR_TABLE:
679 	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
680 	    break;
681 	case MAIL_SERVER_BOOL_TABLE:
682 	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
683 	    break;
684 	case MAIL_SERVER_TIME_TABLE:
685 	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
686 	    break;
687 	case MAIL_SERVER_RAW_TABLE:
688 	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
689 	    break;
690 	case MAIL_SERVER_NINT_TABLE:
691 	    get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
692 	    break;
693 	case MAIL_SERVER_NBOOL_TABLE:
694 	    get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
695 	    break;
696 	case MAIL_SERVER_PRE_INIT:
697 	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
698 	    break;
699 	case MAIL_SERVER_POST_INIT:
700 	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
701 	    break;
702 	case MAIL_SERVER_LOOP:
703 	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
704 	    break;
705 	case MAIL_SERVER_EXIT:
706 	    event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
707 	    break;
708 	case MAIL_SERVER_PRE_ACCEPT:
709 	    event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
710 	    break;
711 	case MAIL_SERVER_PRE_DISCONN:
712 	    event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
713 	    break;
714 	case MAIL_SERVER_IN_FLOW_DELAY:
715 	    event_server_in_flow_delay = 1;
716 	    break;
717 	case MAIL_SERVER_SOLITARY:
718 	    if (stream == 0 && !alone)
719 		msg_fatal("service %s requires a process limit of 1",
720 			  service_name);
721 	    break;
722 	case MAIL_SERVER_UNLIMITED:
723 	    if (stream == 0 && !zerolimit)
724 		msg_fatal("service %s requires a process limit of 0",
725 			  service_name);
726 	    break;
727 	case MAIL_SERVER_PRIVILEGED:
728 	    if (user_name)
729 		msg_fatal("service %s requires privileged operation",
730 			  service_name);
731 	    break;
732 	case MAIL_SERVER_WATCHDOG:
733 	    event_server_watchdog = *va_arg(ap, int *);
734 	    break;
735 	case MAIL_SERVER_SLOW_EXIT:
736 	    event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
737 	    break;
738 	default:
739 	    msg_panic("%s: unknown argument type: %d", myname, key);
740 	}
741     }
742     va_end(ap);
743 
744     if (root_dir)
745 	root_dir = var_queue_dir;
746     if (user_name)
747 	user_name = var_mail_owner;
748 
749     /*
750      * Can options be required?
751      */
752     if (stream == 0) {
753 	if (transport == 0)
754 	    msg_fatal("no transport type specified");
755 	if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
756 	    event_server_accept = event_server_accept_inet;
757 	else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
758 	    event_server_accept = event_server_accept_local;
759 #ifdef MASTER_XPORT_NAME_PASS
760 	else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
761 	    event_server_accept = event_server_accept_pass;
762 #endif
763 	else
764 	    msg_fatal("unsupported transport type: %s", transport);
765     }
766 
767     /*
768      * Retrieve process generation from environment.
769      */
770     if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
771 	if (!alldig(generation))
772 	    msg_fatal("bad generation: %s", generation);
773 	OCTAL_TO_UNSIGNED(event_server_generation, generation);
774 	if (msg_verbose)
775 	    msg_info("process generation: %s (%o)",
776 		     generation, event_server_generation);
777     }
778 
779     /*
780      * Optionally start the debugger on ourself.
781      */
782     if (debug_me)
783 	debug_process();
784 
785     /*
786      * Traditionally, BSD select() can't handle multiple processes selecting
787      * on the same socket, and wakes up every process in select(). See TCP/IP
788      * Illustrated volume 2 page 532. We avoid select() collisions with an
789      * external lock file.
790      */
791 
792     /*
793      * XXX Can't compete for exclusive access to the listen socket because we
794      * also have to monitor existing client connections for service requests.
795      */
796 #if 0
797     if (stream == 0 && !alone) {
798 	lock_path = concatenate(DEF_PID_DIR, "/", transport,
799 				".", service_name, (char *) 0);
800 	why = vstring_alloc(1);
801 	if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
802 				      (struct stat *) 0, -1, -1, why)) == 0)
803 	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
804 	close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
805 	myfree(lock_path);
806 	vstring_free(why);
807     }
808 #endif
809 
810     /*
811      * Set up call-back info.
812      */
813     event_server_service = service;
814     event_server_name = service_name;
815     event_server_argv = argv + optind;
816 
817     /*
818      * Run pre-jail initialization.
819      */
820     if (chdir(var_queue_dir) < 0)
821 	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
822     if (pre_init)
823 	pre_init(event_server_name, event_server_argv);
824 
825     /*
826      * Optionally, restrict the damage that this process can do.
827      */
828     resolve_local_init();
829     tzset();
830     chroot_uid(root_dir, user_name);
831 
832     /*
833      * Run post-jail initialization.
834      */
835     if (post_init)
836 	post_init(event_server_name, event_server_argv);
837 
838     /*
839      * Are we running as a one-shot server with the client connection on
840      * standard input? If so, make sure the output is written to stdout so as
841      * to satisfy common expectation.
842      */
843     if (stream != 0) {
844 	vstream_control(stream,
845 			VSTREAM_CTL_DOUBLE,
846 			VSTREAM_CTL_WRITE_FD, STDOUT_FILENO,
847 			VSTREAM_CTL_END);
848 	service(stream, event_server_name, event_server_argv);
849 	vstream_fflush(stream);
850 	event_server_exit();
851     }
852 
853     /*
854      * Running as a semi-resident server. Service connection requests.
855      * Terminate when we have serviced a sufficient number of clients, when
856      * no-one has been talking to us for a configurable amount of time, or
857      * when the master process terminated abnormally.
858      */
859     if (var_idle_limit > 0)
860 	event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
861     for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
862 	event_enable_read(fd, event_server_accept, CAST_INT_TO_CHAR_PTR(fd));
863 	close_on_exec(fd, CLOSE_ON_EXEC);
864     }
865     event_enable_read(MASTER_STATUS_FD, event_server_abort, (char *) 0);
866     close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
867     close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
868     close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
869     watchdog = watchdog_create(event_server_watchdog,
870 			       (WATCHDOG_FN) 0, (char *) 0);
871 
872     /*
873      * The event loop, at last.
874      */
875     while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
876 	if (event_server_lock != 0) {
877 	    watchdog_stop(watchdog);
878 	    if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
879 			MYFLOCK_OP_EXCLUSIVE) < 0)
880 		msg_fatal("select lock: %m");
881 	}
882 	watchdog_start(watchdog);
883 	delay = loop ? loop(event_server_name, event_server_argv) : -1;
884 	event_loop(delay);
885     }
886     event_server_exit();
887 }
888