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