~ubuntu-branches/ubuntu/dapper/postfix/dapper-security

« back to all changes in this revision

Viewing changes to src/master/single_server.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

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