7 /* Postfix fast flush server
9 /* \fBflush\fR [generic Postfix daemon options]
11 /* The \fBflush\fR(8) server maintains a record of deferred
12 /* mail by destination.
13 /* This information is used to improve the performance of the SMTP
14 /* \fBETRN\fR request, and of its command-line equivalent,
15 /* "\fBsendmail -qR\fR" or "\fBpostqueue -f\fR".
16 /* This program expects to be run from the \fBmaster\fR(8) process
19 /* The record is implemented as a per-destination logfile with
20 /* as contents the queue IDs of deferred mail. A logfile is
21 /* append-only, and is truncated when delivery is requested
22 /* for the corresponding destination. A destination is the
23 /* part on the right-hand side of the right-most \fB@\fR in
26 /* Per-destination logfiles of deferred mail are maintained only for
27 /* eligible destinations. The list of eligible destinations is
28 /* specified with the \fBfast_flush_domains\fR configuration parameter,
29 /* which defaults to \fB$relay_domains\fR.
31 /* This server implements the following requests:
32 /* .IP "\fBadd\fI sitename queueid\fR"
33 /* Inform the \fBflush\fR(8) server that the message with the specified
34 /* queue ID is queued for the specified destination.
35 /* .IP "\fBsend_site\fI sitename\fR"
36 /* Request delivery of mail that is queued for the specified
38 /* .IP "\fBsend_file\fI queueid\fR"
39 /* Request delivery of the specified deferred message.
41 /* Refresh non-empty per-destination logfiles that were not read in
42 /* \fB$fast_flush_refresh_time\fR hours, by simulating
43 /* send requests (see above) for the corresponding destinations.
45 /* Delete empty per-destination logfiles that were not updated in
46 /* \fB$fast_flush_purge_time\fR days.
48 /* This request completes in the background.
50 /* Do a \fBrefresh\fR for all per-destination logfiles.
54 /* The \fBflush\fR(8) server is not security-sensitive. It does not
55 /* talk to the network, and it does not talk to local users.
56 /* The fast flush server can run chrooted at fixed low privilege.
58 /* Problems and transactions are logged to \fBsyslogd\fR(8).
60 /* Fast flush logfiles are truncated only after a "send"
61 /* request, not when mail is actually delivered, and therefore can
62 /* accumulate outdated or redundant data. In order to maintain sanity,
63 /* "refresh" must be executed periodically. This can
64 /* be automated with a suitable wakeup timer setting in the
65 /* \fBmaster.cf\fR configuration file.
67 /* Upon receipt of a request to deliver mail for an eligible
68 /* destination, the \fBflush\fR(8) server requests delivery of all messages
69 /* that are listed in that destination's logfile, regardless of the
70 /* recipients of those messages. This is not an issue for mail
71 /* that is sent to a \fBrelay_domains\fR destination because
72 /* such mail typically only has recipients in one domain.
73 /* CONFIGURATION PARAMETERS
76 /* Changes to \fBmain.cf\fR are picked up automatically as \fBflush\fR(8)
77 /* processes run for only a limited amount of time. Use the command
78 /* "\fBpostfix reload\fR" to speed up a change.
80 /* The text below provides only a parameter summary. See
81 /* \fBpostconf\fR(5) for more details including examples.
82 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
83 /* The default location of the Postfix main.cf and master.cf
84 /* configuration files.
85 /* .IP "\fBdaemon_timeout (18000s)\fR"
86 /* How much time a Postfix daemon process may take to handle a
87 /* request before it is terminated by a built-in watchdog timer.
88 /* .IP "\fBfast_flush_domains ($relay_domains)\fR"
89 /* Optional list of destinations that are eligible for per-destination
90 /* logfiles with mail that is queued to those destinations.
91 /* .IP "\fBfast_flush_refresh_time (12h)\fR"
92 /* The time after which a non-empty but unread per-destination "fast
93 /* flush" logfile needs to be refreshed.
94 /* .IP "\fBfast_flush_purge_time (7d)\fR"
95 /* The time after which an empty per-destination "fast flush" logfile
97 /* .IP "\fBipc_timeout (3600s)\fR"
98 /* The time limit for sending or receiving information over an internal
99 /* communication channel.
100 /* .IP "\fBmax_idle (100s)\fR"
101 /* The maximum amount of time that an idle Postfix daemon process waits
102 /* for an incoming connection before terminating voluntarily.
103 /* .IP "\fBmax_use (100)\fR"
104 /* The maximal number of incoming connections that a Postfix daemon
105 /* process will service before terminating voluntarily.
106 /* .IP "\fBparent_domain_matches_subdomains (see 'postconf -d' output)\fR"
107 /* What Postfix features match subdomains of "domain.tld" automatically,
108 /* instead of requiring an explicit ".domain.tld" pattern.
109 /* .IP "\fBprocess_id (read-only)\fR"
110 /* The process ID of a Postfix command or daemon process.
111 /* .IP "\fBprocess_name (read-only)\fR"
112 /* The process name of a Postfix command or daemon process.
113 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
114 /* The location of the Postfix top-level queue directory.
115 /* .IP "\fBsyslog_facility (mail)\fR"
116 /* The syslog facility of Postfix logging.
117 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
118 /* The mail system name that is prepended to the process name in syslog
119 /* records, so that "smtpd" becomes, for example, "postfix/smtpd".
121 /* /var/spool/postfix/flush, "fast flush" logfiles.
123 /* smtpd(8), SMTP server
124 /* qmgr(8), queue manager
125 /* postconf(5), configuration parameters
126 /* master(5), generic daemon options
127 /* master(8), process manager
128 /* syslogd(8), system logging
132 /* Use "\fBpostconf readme_directory\fR" or
133 /* "\fBpostconf html_directory\fR" to locate this information.
136 /* ETRN_README, Postfix ETRN howto
140 /* The Secure Mailer license must be distributed with this software.
142 /* This service was introduced with Postfix version 1.0.
145 /* IBM T.J. Watson Research
147 /* Yorktown Heights, NY 10598, USA
150 /* System library. */
152 #include <sys_defs.h>
153 #include <sys/stat.h>
154 #include <sys/time.h>
162 /* Utility library. */
168 #include <vstring_vstream.h>
172 #include <scan_dir.h>
173 #include <stringops.h>
174 #include <safe_open.h>
176 /* Global library. */
178 #include <mail_params.h>
179 #include <mail_version.h>
180 #include <mail_queue.h>
181 #include <mail_proto.h>
182 #include <mail_flush.h>
183 #include <flush_clnt.h>
184 #include <mail_conf.h>
185 #include <mail_scan_dir.h>
187 #include <domain_list.h>
188 #include <match_parent_style.h>
190 /* Single server skeleton. */
192 #include <mail_server.h>
194 /* Application-specific. */
197 * Tunable parameters. The fast_flush_domains parameter is not defined here,
198 * because it is also used by the global library, and therefore is owned by
201 int var_fflush_refresh
;
202 int var_fflush_purge
;
205 * Flush policy stuff.
207 static DOMAIN_LIST
*flush_domains
;
210 * Some hard-wired policy: how many queue IDs we remember while we're
211 * flushing a logfile (duplicate elimination). Sites with 1000+ emails
212 * queued should arrange for permanent connectivity.
214 #define FLUSH_DUP_FILTER_SIZE 10000 /* graceful degradation */
217 * Silly little macros.
219 #define STR(x) vstring_str(x)
220 #define STREQ(x,y) ((x) == (y) || strcmp(x,y) == 0)
223 * Forward declarations resulting from breaking up routines according to
224 * name space: domain names versus safe-to-use pathnames.
226 static int flush_add_path(const char *, const char *);
227 static int flush_send_path(const char *, int);
230 * Do we only refresh the per-destination logfile, or do we really request
231 * mail delivery as if someone sent ETRN? If the latter, we must override
232 * information about unavailable hosts or unavailable transports.
234 * When selectively flushing deferred mail, we need to override the queue
235 * manager's "dead destination" information and unthrottle transports and
236 * queues. There are two options:
238 * - Unthrottle all transports and queues before we move mail to the incoming
239 * queue. This is less accurate, but has the advantage when flushing lots of
240 * mail, because Postfix can skip delivery of flushed messages after it
241 * discovers that a destination is (still) unavailable.
243 * - Unthrottle some transports and queues after the queue manager moves mail
244 * to the active queue. This is more accurate, but has the disadvantage when
245 * flushing lots of mail, because Postfix cannot skip delivery of flushed
246 * messages after it discovers that a destination is (still) unavailable.
248 #define REFRESH_ONLY 0
249 #define UNTHROTTLE_BEFORE (1<<0)
250 #define UNTHROTTLE_AFTER (1<<1)
252 /* flush_site_to_path - convert domain or [addr] to harmless string */
254 static VSTRING
*flush_site_to_path(VSTRING
*path
, const char *site
)
260 * Allocate buffer on the fly; caller still needs to clean up.
263 path
= vstring_alloc(10);
266 * Mask characters that could upset the name-to-queue-file mapping code.
268 for (ptr
= site
; (ch
= *(unsigned const char *) ptr
) != 0; ptr
++)
270 VSTRING_ADDCH(path
, ch
);
272 VSTRING_ADDCH(path
, '_');
273 VSTRING_TERMINATE(path
);
276 msg_info("site %s to path %s", site
, STR(path
));
281 /* flush_policy_ok - check logging policy */
283 static int flush_policy_ok(const char *site
)
285 return (domain_list_match(flush_domains
, site
));
288 /* flush_add_service - append queue ID to per-site fast flush logfile */
290 static int flush_add_service(const char *site
, const char *queue_id
)
292 const char *myname
= "flush_add_service";
297 msg_info("%s: site %s queue_id %s", myname
, site
, queue_id
);
300 * If this site is not eligible for logging, deny the request.
302 if (flush_policy_ok(site
) == 0)
303 return (FLUSH_STAT_DENY
);
306 * Map site to path and update log.
308 site_path
= flush_site_to_path((VSTRING
*) 0, site
);
309 status
= flush_add_path(STR(site_path
), queue_id
);
310 vstring_free(site_path
);
315 /* flush_add_path - add record to log */
317 static int flush_add_path(const char *path
, const char *queue_id
)
319 const char *myname
= "flush_add_path";
325 if (!mail_queue_id_ok(path
))
326 return (FLUSH_STAT_BAD
);
329 * Open the logfile or bust.
331 if ((log
= mail_queue_open(MAIL_QUEUE_FLUSH
, path
,
332 O_CREAT
| O_APPEND
| O_WRONLY
, 0600)) == 0)
333 msg_fatal("%s: open fast flush logfile %s: %m", myname
, path
);
336 * We must lock the logfile, so that we don't lose information due to
337 * concurrent access. If the lock takes too long, the Postfix watchdog
338 * will eventually take care of the problem, but it will take a while.
340 if (myflock(vstream_fileno(log
), INTERNAL_LOCK
, MYFLOCK_OP_EXCLUSIVE
) < 0)
341 msg_fatal("%s: lock fast flush logfile %s: %m", myname
, path
);
344 * Append the queue ID. With 15 bits of microsecond time, a queue ID is
345 * not recycled often enough for false hits to be a problem. If it does,
346 * then we could add other signature information, such as the file size
349 vstream_fprintf(log
, "%s\n", queue_id
);
350 if (vstream_fflush(log
))
351 msg_warn("write fast flush logfile %s: %m", path
);
356 if (myflock(vstream_fileno(log
), INTERNAL_LOCK
, MYFLOCK_OP_NONE
) < 0)
357 msg_fatal("%s: unlock fast flush logfile %s: %m", myname
, path
);
358 if (vstream_fclose(log
) != 0)
359 msg_warn("write fast flush logfile %s: %m", path
);
361 return (FLUSH_STAT_OK
);
364 /* flush_send_service - flush mail queued for site */
366 static int flush_send_service(const char *site
, int how
)
368 const char *myname
= "flush_send_service";
373 msg_info("%s: site %s", myname
, site
);
376 * If this site is not eligible for logging, deny the request.
378 if (flush_policy_ok(site
) == 0)
379 return (FLUSH_STAT_DENY
);
382 * Map site name to path name and flush the log.
384 site_path
= flush_site_to_path((VSTRING
*) 0, site
);
385 status
= flush_send_path(STR(site_path
), how
);
386 vstring_free(site_path
);
391 /* flush_one_file - move one queue file to incoming queue */
393 static int flush_one_file(const char *queue_id
, VSTRING
*queue_file
,
394 struct utimbuf
* tbuf
, int how
)
396 const char *myname
= "flush_one_file";
397 const char *queue_name
;
401 * Some other instance of this program may flush some logfile and may
402 * just have moved this queue file to the incoming queue.
404 for (queue_name
= MAIL_QUEUE_DEFERRED
; /* see below */ ;
405 queue_name
= MAIL_QUEUE_INCOMING
) {
406 path
= mail_queue_path(queue_file
, queue_name
, queue_id
);
407 if (utime(path
, tbuf
) == 0)
410 msg_warn("%s: update %s time stamps: %m", myname
, path
);
411 if (STREQ(queue_name
, MAIL_QUEUE_INCOMING
))
416 * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue
417 * manager to unthrottle transports and queues as it reads recipients
418 * from a queue file. We request this unthrottle operation by setting the
419 * group read permission bit.
421 * Note: we must avoid using chmod(). It is not only slower than fchmod()
422 * but it is also less secure. With chmod(), an attacker could repeatedly
423 * send requests to the flush server and trick it into changing
424 * permissions of non-queue files, by exploiting a race condition.
426 * We use safe_open() because we don't validate the file content before
427 * modifying the file status.
429 if (how
& UNTHROTTLE_AFTER
) {
434 for (why
= vstring_alloc(1); /* see below */ ;
435 queue_name
= MAIL_QUEUE_INCOMING
,
436 path
= mail_queue_path(queue_file
, queue_name
, queue_id
)) {
437 if ((fp
= safe_open(path
, O_RDWR
, 0, &st
, -1, -1, why
)) != 0)
440 msg_warn("%s: open %s: %s", myname
, path
, STR(why
));
441 if (errno
!= ENOENT
|| STREQ(queue_name
, MAIL_QUEUE_INCOMING
)) {
447 if ((st
.st_mode
& MAIL_QUEUE_STAT_READY
) != MAIL_QUEUE_STAT_READY
) {
448 (void) vstream_fclose(fp
);
451 if (fchmod(vstream_fileno(fp
), st
.st_mode
| MAIL_QUEUE_STAT_UNTHROTTLE
) < 0)
452 msg_warn("%s: fchmod %s: %m", myname
, path
);
453 (void) vstream_fclose(fp
);
457 * Move the file to the incoming queue, if it isn't already there.
459 if (STREQ(queue_name
, MAIL_QUEUE_INCOMING
) == 0
460 && mail_queue_rename(queue_id
, queue_name
, MAIL_QUEUE_INCOMING
) < 0
462 msg_warn("%s: rename from %s to %s: %m",
463 path
, queue_name
, MAIL_QUEUE_INCOMING
);
466 * If we got here, we achieved something, so let's claim succes.
471 /* flush_send_path - flush logfile file */
473 static int flush_send_path(const char *path
, int how
)
475 const char *myname
= "flush_send_path";
480 static char qmgr_flush_trigger
[] = {
481 QMGR_REQ_FLUSH_DEAD
, /* flush dead site/transport cache */
483 static char qmgr_scan_trigger
[] = {
484 QMGR_REQ_SCAN_INCOMING
, /* scan incoming queue */
492 if (!mail_queue_id_ok(path
))
493 return (FLUSH_STAT_BAD
);
496 * Open the logfile. If the file does not exist, then there is no queued
497 * mail for this destination.
499 if ((log
= mail_queue_open(MAIL_QUEUE_FLUSH
, path
, O_RDWR
, 0600)) == 0) {
501 msg_fatal("%s: open fast flush logfile %s: %m", myname
, path
);
502 return (FLUSH_STAT_OK
);
506 * We must lock the logfile, so that we don't lose information when it is
507 * truncated. Unfortunately, this means that the file can be locked for a
508 * significant amount of time. If things really get stuck the Postfix
509 * watchdog will take care of it.
511 if (myflock(vstream_fileno(log
), INTERNAL_LOCK
, MYFLOCK_OP_EXCLUSIVE
) < 0)
512 msg_fatal("%s: lock fast flush logfile %s: %m", myname
, path
);
515 * With the UNTHROTTLE_BEFORE strategy, we ask the queue manager to
516 * unthrottle all transports and queues before we move a deferred queue
517 * file to the incoming queue. This minimizes a race condition where the
518 * queue manager seizes a queue file before it knows that we want to
519 * flush that message.
521 * This reduces the race condition time window to a very small amount (the
522 * flush server does not really know when the queue manager reads its
523 * command fifo). But there is a worse race, where the queue manager
524 * moves a deferred queue file to the active queue before we have a
525 * chance to expedite its delivery.
527 if (how
& UNTHROTTLE_BEFORE
)
528 mail_trigger(MAIL_CLASS_PUBLIC
, var_queue_service
,
529 qmgr_flush_trigger
, sizeof(qmgr_flush_trigger
));
532 * This is the part that dominates running time: schedule the listed
533 * queue files for delivery by updating their file time stamps and by
534 * moving them from the deferred queue to the incoming queue. This should
535 * take no more than a couple seconds under normal conditions. Filter out
536 * duplicate queue file names to avoid hammering the file system, with
537 * some finite limit on the amount of memory that we are willing to
538 * sacrifice for duplicate filtering. Graceful degradation.
540 * By moving selected queue files from the deferred queue to the incoming
541 * queue we optimize for the case where most deferred mail is for other
542 * sites. If that assumption does not hold, i.e. all deferred mail is for
543 * the same site, then doing a "fast flush" will cost more disk I/O than
544 * a "slow flush" that delivers the entire deferred queue. This penalty
545 * is only temporary - it will go away after we unite the active queue
546 * and the incoming queue.
548 queue_id
= vstring_alloc(10);
549 queue_file
= vstring_alloc(10);
550 dup_filter
= htable_create(10);
551 tbuf
.actime
= tbuf
.modtime
= event_time();
552 for (count
= 0; vstring_get_nonl(queue_id
, log
) != VSTREAM_EOF
; count
++) {
553 if (!mail_queue_id_ok(STR(queue_id
))) {
554 msg_warn("bad queue id \"%.30s...\" in fast flush logfile %s",
555 STR(queue_id
), path
);
558 if (dup_filter
->used
>= FLUSH_DUP_FILTER_SIZE
559 || htable_find(dup_filter
, STR(queue_id
)) == 0) {
561 msg_info("%s: logfile %s: update queue file %s time stamps",
562 myname
, path
, STR(queue_id
));
563 if (dup_filter
->used
<= FLUSH_DUP_FILTER_SIZE
)
564 htable_enter(dup_filter
, STR(queue_id
), 0);
565 count
+= flush_one_file(STR(queue_id
), queue_file
, &tbuf
, how
);
568 msg_info("%s: logfile %s: skip queue file %s as duplicate",
569 myname
, path
, STR(queue_file
));
572 htable_free(dup_filter
, (void (*) (char *)) 0);
573 vstring_free(queue_file
);
574 vstring_free(queue_id
);
577 * Truncate the fast flush log.
579 if (count
> 0 && ftruncate(vstream_fileno(log
), (off_t
) 0) < 0)
580 msg_fatal("%s: truncate fast flush logfile %s: %m", myname
, path
);
583 * Workaround for noatime mounts. Use futimes() if available.
585 (void) utimes(VSTREAM_PATH(log
), (struct timeval
*) 0);
588 * Request delivery and clean up.
590 if (myflock(vstream_fileno(log
), INTERNAL_LOCK
, MYFLOCK_OP_NONE
) < 0)
591 msg_fatal("%s: unlock fast flush logfile %s: %m", myname
, path
);
592 if (vstream_fclose(log
) != 0)
593 msg_warn("%s: read fast flush logfile %s: %m", myname
, path
);
596 msg_info("%s: requesting delivery for logfile %s", myname
, path
);
597 mail_trigger(MAIL_CLASS_PUBLIC
, var_queue_service
,
598 qmgr_scan_trigger
, sizeof(qmgr_scan_trigger
));
600 return (FLUSH_STAT_OK
);
603 /* flush_send_file_service - flush one queue file */
605 static int flush_send_file_service(const char *queue_id
)
607 const char *myname
= "flush_send_file_service";
610 static char qmgr_scan_trigger
[] = {
611 QMGR_REQ_SCAN_INCOMING
, /* scan incoming queue */
617 if (!mail_queue_id_ok(queue_id
))
618 return (FLUSH_STAT_BAD
);
621 msg_info("%s: requesting delivery for queue_id %s", myname
, queue_id
);
623 queue_file
= vstring_alloc(30);
624 tbuf
.actime
= tbuf
.modtime
= event_time();
625 if (flush_one_file(queue_id
, queue_file
, &tbuf
, UNTHROTTLE_AFTER
) > 0)
626 mail_trigger(MAIL_CLASS_PUBLIC
, var_queue_service
,
627 qmgr_scan_trigger
, sizeof(qmgr_scan_trigger
));
628 vstring_free(queue_file
);
630 return (FLUSH_STAT_OK
);
633 /* flush_refresh_service - refresh logfiles beyond some age */
635 static int flush_refresh_service(int max_age
)
637 const char *myname
= "flush_refresh_service";
641 VSTRING
*path
= vstring_alloc(10);
643 scan
= scan_dir_open(MAIL_QUEUE_FLUSH
);
644 while ((site_path
= mail_scan_dir_next(scan
)) != 0) {
645 if (!mail_queue_id_ok(site_path
))
646 continue; /* XXX grumble. */
647 mail_queue_path(path
, MAIL_QUEUE_FLUSH
, site_path
);
648 if (stat(STR(path
), &st
) < 0) {
650 msg_warn("%s: stat %s: %m", myname
, STR(path
));
651 else if (msg_verbose
)
652 msg_info("%s: %s: %m", myname
, STR(path
));
655 if (st
.st_size
== 0) {
656 if (st
.st_mtime
+ var_fflush_purge
< event_time()) {
657 if (unlink(STR(path
)) < 0)
658 msg_warn("remove logfile %s: %m", STR(path
));
659 else if (msg_verbose
)
660 msg_info("%s: unlink %s, empty and unchanged for %d days",
661 myname
, STR(path
), var_fflush_purge
/ 86400);
662 } else if (msg_verbose
)
663 msg_info("%s: skip logfile %s - empty log", myname
, site_path
);
664 } else if (st
.st_atime
+ max_age
< event_time()) {
666 msg_info("%s: flush logfile %s", myname
, site_path
);
667 flush_send_path(site_path
, REFRESH_ONLY
);
670 msg_info("%s: skip logfile %s, unread for <%d hours(s) ",
671 myname
, site_path
, max_age
/ 3600);
674 scan_dir_close(scan
);
677 return (FLUSH_STAT_OK
);
680 /* flush_request_receive - receive request */
682 static int flush_request_receive(VSTREAM
*client_stream
, VSTRING
*request
)
687 * Kluge: choose the protocol depending on the request size.
689 if (read_wait(vstream_fileno(client_stream
), var_ipc_timeout
) < 0) {
690 msg_warn("timeout while waiting for data from %s",
691 VSTREAM_PATH(client_stream
));
694 if ((count
= peekfd(vstream_fileno(client_stream
))) < 0) {
695 msg_warn("cannot examine read buffer of %s: %m",
696 VSTREAM_PATH(client_stream
));
701 * Short request: master trigger. Use the string+null protocol.
704 if (vstring_get_null(request
, client_stream
) == VSTREAM_EOF
) {
705 msg_warn("end-of-input while reading request from %s: %m",
706 VSTREAM_PATH(client_stream
));
712 * Long request: real flush client. Use the attribute list protocol.
715 if (attr_scan(client_stream
,
716 ATTR_FLAG_MORE
| ATTR_FLAG_STRICT
,
717 ATTR_TYPE_STR
, MAIL_ATTR_REQ
, request
,
718 ATTR_TYPE_END
) != 1) {
725 /* flush_service - perform service for client */
727 static void flush_service(VSTREAM
*client_stream
, char *unused_service
,
730 VSTRING
*request
= vstring_alloc(10);
732 VSTRING
*queue_id
= 0;
733 static char wakeup
[] = { /* master wakeup request */
737 int status
= FLUSH_STAT_BAD
;
740 * Sanity check. This service takes no command-line arguments.
743 msg_fatal("unexpected command-line argument: %s", argv
[0]);
746 * This routine runs whenever a client connects to the UNIX-domain socket
747 * dedicated to the fast flush service. What we see below is a little
748 * protocol to (1) read a request from the client (the name of the site)
749 * and (2) acknowledge that we have received the request.
751 * All connection-management stuff is handled by the common code in
754 if (flush_request_receive(client_stream
, request
) == 0) {
755 if (STREQ(STR(request
), FLUSH_REQ_ADD
)) {
756 site
= vstring_alloc(10);
757 queue_id
= vstring_alloc(10);
758 if (attr_scan(client_stream
, ATTR_FLAG_STRICT
,
759 ATTR_TYPE_STR
, MAIL_ATTR_SITE
, site
,
760 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, queue_id
,
762 && mail_queue_id_ok(STR(queue_id
)))
763 status
= flush_add_service(lowercase(STR(site
)), STR(queue_id
));
764 attr_print(client_stream
, ATTR_FLAG_NONE
,
765 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, status
,
767 } else if (STREQ(STR(request
), FLUSH_REQ_SEND_SITE
)) {
768 site
= vstring_alloc(10);
769 if (attr_scan(client_stream
, ATTR_FLAG_STRICT
,
770 ATTR_TYPE_STR
, MAIL_ATTR_SITE
, site
,
772 status
= flush_send_service(lowercase(STR(site
)),
774 attr_print(client_stream
, ATTR_FLAG_NONE
,
775 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, status
,
777 } else if (STREQ(STR(request
), FLUSH_REQ_SEND_FILE
)) {
778 queue_id
= vstring_alloc(10);
779 if (attr_scan(client_stream
, ATTR_FLAG_STRICT
,
780 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, queue_id
,
782 status
= flush_send_file_service(STR(queue_id
));
783 attr_print(client_stream
, ATTR_FLAG_NONE
,
784 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, status
,
786 } else if (STREQ(STR(request
), FLUSH_REQ_REFRESH
)
787 || STREQ(STR(request
), wakeup
)) {
788 attr_print(client_stream
, ATTR_FLAG_NONE
,
789 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, FLUSH_STAT_OK
,
791 vstream_fflush(client_stream
);
792 (void) flush_refresh_service(var_fflush_refresh
);
793 } else if (STREQ(STR(request
), FLUSH_REQ_PURGE
)) {
794 attr_print(client_stream
, ATTR_FLAG_NONE
,
795 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, FLUSH_STAT_OK
,
797 vstream_fflush(client_stream
);
798 (void) flush_refresh_service(0);
801 attr_print(client_stream
, ATTR_FLAG_NONE
,
802 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, status
,
804 vstring_free(request
);
808 vstring_free(queue_id
);
811 /* pre_jail_init - pre-jail initialization */
813 static void pre_jail_init(char *unused_name
, char **unused_argv
)
815 flush_domains
= domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS
),
819 MAIL_VERSION_STAMP_DECLARE
;
821 /* main - pass control to the single-threaded skeleton */
823 int main(int argc
, char **argv
)
825 static const CONFIG_TIME_TABLE time_table
[] = {
826 VAR_FFLUSH_REFRESH
, DEF_FFLUSH_REFRESH
, &var_fflush_refresh
, 1, 0,
827 VAR_FFLUSH_PURGE
, DEF_FFLUSH_PURGE
, &var_fflush_purge
, 1, 0,
832 * Fingerprint executables and core dumps.
834 MAIL_VERSION_STAMP_ALLOCATE
;
836 single_server_main(argc
, argv
, flush_service
,
837 MAIL_SERVER_TIME_TABLE
, time_table
,
838 MAIL_SERVER_PRE_INIT
, pre_jail_init
,
839 MAIL_SERVER_UNLIMITED
,