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