xref: /netbsd-src/external/ibm-public/postfix/dist/src/flush/flush.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: flush.c,v 1.1.1.1 2009/06/23 10:08:44 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	flush 8
6 /* SUMMARY
7 /*	Postfix fast flush server
8 /* SYNOPSIS
9 /*	\fBflush\fR [generic Postfix daemon options]
10 /* DESCRIPTION
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
17 /*	manager.
18 /*
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
24 /*	an email address.
25 /*
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.
30 /*
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
37 /*	destination.
38 /* .IP "\fBsend_file\fI queueid\fR"
39 /*	Request delivery of the specified deferred message.
40 /* .IP \fBrefresh\fR
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.
44 /* .sp
45 /*	Delete empty per-destination logfiles that were not updated in
46 /*	\fB$fast_flush_purge_time\fR days.
47 /* .sp
48 /*	This request completes in the background.
49 /* .IP \fBpurge\fR
50 /*	Do a \fBrefresh\fR for all per-destination logfiles.
51 /* SECURITY
52 /* .ad
53 /* .fi
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.
57 /* DIAGNOSTICS
58 /*	Problems and transactions are logged to \fBsyslogd\fR(8).
59 /* BUGS
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.
66 /*
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
74 /* .ad
75 /* .fi
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.
79 /*
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
96 /*	is deleted.
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".
120 /* FILES
121 /*	/var/spool/postfix/flush, "fast flush" logfiles.
122 /* SEE ALSO
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
129 /* README FILES
130 /* .ad
131 /* .fi
132 /*	Use "\fBpostconf readme_directory\fR" or
133 /*	"\fBpostconf html_directory\fR" to locate this information.
134 /* .na
135 /* .nf
136 /*	ETRN_README, Postfix ETRN howto
137 /* LICENSE
138 /* .ad
139 /* .fi
140 /*	The Secure Mailer license must be distributed with this software.
141 /* HISTORY
142 /*	This service was introduced with Postfix version 1.0.
143 /* AUTHOR(S)
144 /*	Wietse Venema
145 /*	IBM T.J. Watson Research
146 /*	P.O. Box 704
147 /*	Yorktown Heights, NY 10598, USA
148 /*--*/
149 
150 /* System library. */
151 
152 #include <sys_defs.h>
153 #include <sys/stat.h>
154 #include <sys/time.h>
155 #include <unistd.h>
156 #include <stdlib.h>
157 #include <utime.h>
158 #include <errno.h>
159 #include <ctype.h>
160 #include <string.h>
161 
162 /* Utility library. */
163 
164 #include <msg.h>
165 #include <events.h>
166 #include <vstream.h>
167 #include <vstring.h>
168 #include <vstring_vstream.h>
169 #include <myflock.h>
170 #include <htable.h>
171 #include <dict.h>
172 #include <scan_dir.h>
173 #include <stringops.h>
174 #include <safe_open.h>
175 
176 /* Global library. */
177 
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>
186 #include <maps.h>
187 #include <domain_list.h>
188 #include <match_parent_style.h>
189 
190 /* Single server skeleton. */
191 
192 #include <mail_server.h>
193 
194 /* Application-specific. */
195 
196  /*
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
199   * the library.
200   */
201 int     var_fflush_refresh;
202 int     var_fflush_purge;
203 
204  /*
205   * Flush policy stuff.
206   */
207 static DOMAIN_LIST *flush_domains;
208 
209  /*
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.
213   */
214 #define FLUSH_DUP_FILTER_SIZE	10000	/* graceful degradation */
215 
216  /*
217   * Silly little macros.
218   */
219 #define STR(x)			vstring_str(x)
220 #define STREQ(x,y)		((x) == (y) || strcmp(x,y) == 0)
221 
222  /*
223   * Forward declarations resulting from breaking up routines according to
224   * name space: domain names versus safe-to-use pathnames.
225   */
226 static int flush_add_path(const char *, const char *);
227 static int flush_send_path(const char *, int);
228 
229  /*
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.
233   *
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:
237   *
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.
242   *
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.
247   */
248 #define REFRESH_ONLY		0
249 #define UNTHROTTLE_BEFORE	(1<<0)
250 #define UNTHROTTLE_AFTER	(1<<1)
251 
252 /* flush_site_to_path - convert domain or [addr] to harmless string */
253 
254 static VSTRING *flush_site_to_path(VSTRING *path, const char *site)
255 {
256     const char *ptr;
257     int     ch;
258 
259     /*
260      * Allocate buffer on the fly; caller still needs to clean up.
261      */
262     if (path == 0)
263 	path = vstring_alloc(10);
264 
265     /*
266      * Mask characters that could upset the name-to-queue-file mapping code.
267      */
268     for (ptr = site; (ch = *(unsigned const char *) ptr) != 0; ptr++)
269 	if (ISALNUM(ch))
270 	    VSTRING_ADDCH(path, ch);
271 	else
272 	    VSTRING_ADDCH(path, '_');
273     VSTRING_TERMINATE(path);
274 
275     if (msg_verbose)
276 	msg_info("site %s to path %s", site, STR(path));
277 
278     return (path);
279 }
280 
281 /* flush_policy_ok - check logging policy */
282 
283 static int flush_policy_ok(const char *site)
284 {
285     return (domain_list_match(flush_domains, site));
286 }
287 
288 /* flush_add_service - append queue ID to per-site fast flush logfile */
289 
290 static int flush_add_service(const char *site, const char *queue_id)
291 {
292     const char *myname = "flush_add_service";
293     VSTRING *site_path;
294     int     status;
295 
296     if (msg_verbose)
297 	msg_info("%s: site %s queue_id %s", myname, site, queue_id);
298 
299     /*
300      * If this site is not eligible for logging, deny the request.
301      */
302     if (flush_policy_ok(site) == 0)
303 	return (FLUSH_STAT_DENY);
304 
305     /*
306      * Map site to path and update log.
307      */
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);
311 
312     return (status);
313 }
314 
315 /* flush_add_path - add record to log */
316 
317 static int flush_add_path(const char *path, const char *queue_id)
318 {
319     const char *myname = "flush_add_path";
320     VSTREAM *log;
321 
322     /*
323      * Sanity check.
324      */
325     if (!mail_queue_id_ok(path))
326 	return (FLUSH_STAT_BAD);
327 
328     /*
329      * Open the logfile or bust.
330      */
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);
334 
335     /*
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.
339      */
340     if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
341 	msg_fatal("%s: lock fast flush logfile %s: %m", myname, path);
342 
343     /*
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
347      * in bytes.
348      */
349     vstream_fprintf(log, "%s\n", queue_id);
350     if (vstream_fflush(log))
351 	msg_warn("write fast flush logfile %s: %m", path);
352 
353     /*
354      * Clean up.
355      */
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);
360 
361     return (FLUSH_STAT_OK);
362 }
363 
364 /* flush_send_service - flush mail queued for site */
365 
366 static int flush_send_service(const char *site, int how)
367 {
368     const char *myname = "flush_send_service";
369     VSTRING *site_path;
370     int     status;
371 
372     if (msg_verbose)
373 	msg_info("%s: site %s", myname, site);
374 
375     /*
376      * If this site is not eligible for logging, deny the request.
377      */
378     if (flush_policy_ok(site) == 0)
379 	return (FLUSH_STAT_DENY);
380 
381     /*
382      * Map site name to path name and flush the log.
383      */
384     site_path = flush_site_to_path((VSTRING *) 0, site);
385     status = flush_send_path(STR(site_path), how);
386     vstring_free(site_path);
387 
388     return (status);
389 }
390 
391 /* flush_one_file - move one queue file to incoming queue */
392 
393 static int flush_one_file(const char *queue_id, VSTRING *queue_file,
394 			          struct utimbuf * tbuf, int how)
395 {
396     const char *myname = "flush_one_file";
397     const char *queue_name;
398     const char *path;
399 
400     /*
401      * Some other instance of this program may flush some logfile and may
402      * just have moved this queue file to the incoming queue.
403      */
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)
408 	    break;
409 	if (errno != ENOENT)
410 	    msg_warn("%s: update %s time stamps: %m", myname, path);
411 	if (STREQ(queue_name, MAIL_QUEUE_INCOMING))
412 	    return (0);
413     }
414 
415     /*
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.
420      *
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.
425      *
426      * We use safe_open() because we don't validate the file content before
427      * modifying the file status.
428      */
429     if (how & UNTHROTTLE_AFTER) {
430 	VSTRING *why;
431 	struct stat st;
432 	VSTREAM *fp;
433 
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)
438 		break;
439 	    if (errno != ENOENT)
440 		msg_warn("%s: open %s: %s", myname, path, STR(why));
441 	    if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) {
442 		vstring_free(why);
443 		return (0);
444 	    }
445 	}
446 	vstring_free(why);
447 	if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) {
448 	    (void) vstream_fclose(fp);
449 	    return (0);
450 	}
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);
454     }
455 
456     /*
457      * Move the file to the incoming queue, if it isn't already there.
458      */
459     if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0
460 	&& mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0
461 	&& errno != ENOENT)
462 	msg_warn("%s: rename from %s to %s: %m",
463 		 path, queue_name, MAIL_QUEUE_INCOMING);
464 
465     /*
466      * If we got here, we achieved something, so let's claim succes.
467      */
468     return (1);
469 }
470 
471 /* flush_send_path - flush logfile file */
472 
473 static int flush_send_path(const char *path, int how)
474 {
475     const char *myname = "flush_send_path";
476     VSTRING *queue_id;
477     VSTRING *queue_file;
478     VSTREAM *log;
479     struct utimbuf tbuf;
480     static char qmgr_flush_trigger[] = {
481 	QMGR_REQ_FLUSH_DEAD,		/* flush dead site/transport cache */
482     };
483     static char qmgr_scan_trigger[] = {
484 	QMGR_REQ_SCAN_INCOMING,		/* scan incoming queue */
485     };
486     HTABLE *dup_filter;
487     int     count;
488 
489     /*
490      * Sanity check.
491      */
492     if (!mail_queue_id_ok(path))
493 	return (FLUSH_STAT_BAD);
494 
495     /*
496      * Open the logfile. If the file does not exist, then there is no queued
497      * mail for this destination.
498      */
499     if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, O_RDWR, 0600)) == 0) {
500 	if (errno != ENOENT)
501 	    msg_fatal("%s: open fast flush logfile %s: %m", myname, path);
502 	return (FLUSH_STAT_OK);
503     }
504 
505     /*
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.
510      */
511     if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
512 	msg_fatal("%s: lock fast flush logfile %s: %m", myname, path);
513 
514     /*
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.
520      *
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.
526      */
527     if (how & UNTHROTTLE_BEFORE)
528 	mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service,
529 		     qmgr_flush_trigger, sizeof(qmgr_flush_trigger));
530 
531     /*
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.
539      *
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.
547      */
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);
556 	    continue;
557 	}
558 	if (dup_filter->used >= FLUSH_DUP_FILTER_SIZE
559 	    || htable_find(dup_filter, STR(queue_id)) == 0) {
560 	    if (msg_verbose)
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);
566 	} else {
567 	    if (msg_verbose)
568 		msg_info("%s: logfile %s: skip queue file %s as duplicate",
569 			 myname, path, STR(queue_file));
570 	}
571     }
572     htable_free(dup_filter, (void (*) (char *)) 0);
573     vstring_free(queue_file);
574     vstring_free(queue_id);
575 
576     /*
577      * Truncate the fast flush log.
578      */
579     if (count > 0 && ftruncate(vstream_fileno(log), (off_t) 0) < 0)
580 	msg_fatal("%s: truncate fast flush logfile %s: %m", myname, path);
581 
582     /*
583      * Workaround for noatime mounts. Use futimes() if available.
584      */
585     (void) utimes(VSTREAM_PATH(log), (struct timeval *) 0);
586 
587     /*
588      * Request delivery and clean up.
589      */
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);
594     if (count > 0) {
595 	if (msg_verbose)
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));
599     }
600     return (FLUSH_STAT_OK);
601 }
602 
603 /* flush_send_file_service - flush one queue file */
604 
605 static int flush_send_file_service(const char *queue_id)
606 {
607     const char *myname = "flush_send_file_service";
608     VSTRING *queue_file;
609     struct utimbuf tbuf;
610     static char qmgr_scan_trigger[] = {
611 	QMGR_REQ_SCAN_INCOMING,		/* scan incoming queue */
612     };
613 
614     /*
615      * Sanity check.
616      */
617     if (!mail_queue_id_ok(queue_id))
618 	return (FLUSH_STAT_BAD);
619 
620     if (msg_verbose)
621 	msg_info("%s: requesting delivery for queue_id %s", myname, queue_id);
622 
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);
629 
630     return (FLUSH_STAT_OK);
631 }
632 
633 /* flush_refresh_service - refresh logfiles beyond some age */
634 
635 static int flush_refresh_service(int max_age)
636 {
637     const char *myname = "flush_refresh_service";
638     SCAN_DIR *scan;
639     char   *site_path;
640     struct stat st;
641     VSTRING *path = vstring_alloc(10);
642 
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) {
649 	    if (errno != ENOENT)
650 		msg_warn("%s: stat %s: %m", myname, STR(path));
651 	    else if (msg_verbose)
652 		msg_info("%s: %s: %m", myname, STR(path));
653 	    continue;
654 	}
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()) {
665 	    if (msg_verbose)
666 		msg_info("%s: flush logfile %s", myname, site_path);
667 	    flush_send_path(site_path, REFRESH_ONLY);
668 	} else {
669 	    if (msg_verbose)
670 		msg_info("%s: skip logfile %s, unread for <%d hours(s) ",
671 			 myname, site_path, max_age / 3600);
672 	}
673     }
674     scan_dir_close(scan);
675     vstring_free(path);
676 
677     return (FLUSH_STAT_OK);
678 }
679 
680 /* flush_request_receive - receive request */
681 
682 static int flush_request_receive(VSTREAM *client_stream, VSTRING *request)
683 {
684     int     count;
685 
686     /*
687      * Kluge: choose the protocol depending on the request size.
688      */
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));
692 	return (-1);
693     }
694     if ((count = peekfd(vstream_fileno(client_stream))) < 0) {
695 	msg_warn("cannot examine read buffer of %s: %m",
696 		 VSTREAM_PATH(client_stream));
697 	return (-1);
698     }
699 
700     /*
701      * Short request: master trigger. Use the string+null protocol.
702      */
703     if (count <= 2) {
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));
707 	    return (-1);
708 	}
709     }
710 
711     /*
712      * Long request: real flush client. Use the attribute list protocol.
713      */
714     else {
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) {
719 	    return (-1);
720 	}
721     }
722     return (0);
723 }
724 
725 /* flush_service - perform service for client */
726 
727 static void flush_service(VSTREAM *client_stream, char *unused_service,
728 			          char **argv)
729 {
730     VSTRING *request = vstring_alloc(10);
731     VSTRING *site = 0;
732     VSTRING *queue_id = 0;
733     static char wakeup[] = {		/* master wakeup request */
734 	TRIGGER_REQ_WAKEUP,
735 	0,
736     };
737     int     status = FLUSH_STAT_BAD;
738 
739     /*
740      * Sanity check. This service takes no command-line arguments.
741      */
742     if (argv[0])
743 	msg_fatal("unexpected command-line argument: %s", argv[0]);
744 
745     /*
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.
750      *
751      * All connection-management stuff is handled by the common code in
752      * single_server.c.
753      */
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,
761 			  ATTR_TYPE_END) == 2
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,
766 		       ATTR_TYPE_END);
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,
771 			  ATTR_TYPE_END) == 1)
772 		status = flush_send_service(lowercase(STR(site)),
773 					    UNTHROTTLE_BEFORE);
774 	    attr_print(client_stream, ATTR_FLAG_NONE,
775 		       ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
776 		       ATTR_TYPE_END);
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,
781 			  ATTR_TYPE_END) == 1)
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,
785 		       ATTR_TYPE_END);
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,
790 		       ATTR_TYPE_END);
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,
796 		       ATTR_TYPE_END);
797 	    vstream_fflush(client_stream);
798 	    (void) flush_refresh_service(0);
799 	}
800     } else
801 	attr_print(client_stream, ATTR_FLAG_NONE,
802 		   ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
803 		   ATTR_TYPE_END);
804     vstring_free(request);
805     if (site)
806 	vstring_free(site);
807     if (queue_id)
808 	vstring_free(queue_id);
809 }
810 
811 /* pre_jail_init - pre-jail initialization */
812 
813 static void pre_jail_init(char *unused_name, char **unused_argv)
814 {
815     flush_domains = domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS),
816 				     var_fflush_domains);
817 }
818 
819 MAIL_VERSION_STAMP_DECLARE;
820 
821 /* main - pass control to the single-threaded skeleton */
822 
823 int     main(int argc, char **argv)
824 {
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,
828 	0,
829     };
830 
831     /*
832      * Fingerprint executables and core dumps.
833      */
834     MAIL_VERSION_STAMP_ALLOCATE;
835 
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,
840 		       0);
841 }
842