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