~ubuntu-branches/ubuntu/hoary/postfix/hoary-security

« back to all changes in this revision

Viewing changes to src/master/trigger_server.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-10-06 11:50:33 UTC
  • Revision ID: james.westby@ubuntu.com-20041006115033-ooo6yfg6kmoteu04
Tags: upstream-2.1.3
ImportĀ upstreamĀ versionĀ 2.1.3

Show diffs side-by-side

added added

removed removed

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