1 /* $NetBSD: flush.c,v 1.1.1.2 2013/01/02 18:58:55 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 #include <warn_stat.h> 176 177 /* Global library. */ 178 179 #include <mail_params.h> 180 #include <mail_version.h> 181 #include <mail_queue.h> 182 #include <mail_proto.h> 183 #include <mail_flush.h> 184 #include <flush_clnt.h> 185 #include <mail_conf.h> 186 #include <mail_scan_dir.h> 187 #include <maps.h> 188 #include <domain_list.h> 189 #include <match_parent_style.h> 190 191 /* Single server skeleton. */ 192 193 #include <mail_server.h> 194 195 /* Application-specific. */ 196 197 /* 198 * Tunable parameters. The fast_flush_domains parameter is not defined here, 199 * because it is also used by the global library, and therefore is owned by 200 * the library. 201 */ 202 int var_fflush_refresh; 203 int var_fflush_purge; 204 205 /* 206 * Flush policy stuff. 207 */ 208 static DOMAIN_LIST *flush_domains; 209 210 /* 211 * Some hard-wired policy: how many queue IDs we remember while we're 212 * flushing a logfile (duplicate elimination). Sites with 1000+ emails 213 * queued should arrange for permanent connectivity. 214 */ 215 #define FLUSH_DUP_FILTER_SIZE 10000 /* graceful degradation */ 216 217 /* 218 * Silly little macros. 219 */ 220 #define STR(x) vstring_str(x) 221 #define STREQ(x,y) ((x) == (y) || strcmp(x,y) == 0) 222 223 /* 224 * Forward declarations resulting from breaking up routines according to 225 * name space: domain names versus safe-to-use pathnames. 226 */ 227 static int flush_add_path(const char *, const char *); 228 static int flush_send_path(const char *, int); 229 230 /* 231 * Do we only refresh the per-destination logfile, or do we really request 232 * mail delivery as if someone sent ETRN? If the latter, we must override 233 * information about unavailable hosts or unavailable transports. 234 * 235 * When selectively flushing deferred mail, we need to override the queue 236 * manager's "dead destination" information and unthrottle transports and 237 * queues. There are two options: 238 * 239 * - Unthrottle all transports and queues before we move mail to the incoming 240 * queue. This is less accurate, but has the advantage when flushing lots of 241 * mail, because Postfix can skip delivery of flushed messages after it 242 * discovers that a destination is (still) unavailable. 243 * 244 * - Unthrottle some transports and queues after the queue manager moves mail 245 * to the active queue. This is more accurate, but has the disadvantage when 246 * flushing lots of mail, because Postfix cannot skip delivery of flushed 247 * messages after it discovers that a destination is (still) unavailable. 248 */ 249 #define REFRESH_ONLY 0 250 #define UNTHROTTLE_BEFORE (1<<0) 251 #define UNTHROTTLE_AFTER (1<<1) 252 253 /* flush_site_to_path - convert domain or [addr] to harmless string */ 254 255 static VSTRING *flush_site_to_path(VSTRING *path, const char *site) 256 { 257 const char *ptr; 258 int ch; 259 260 /* 261 * Allocate buffer on the fly; caller still needs to clean up. 262 */ 263 if (path == 0) 264 path = vstring_alloc(10); 265 266 /* 267 * Mask characters that could upset the name-to-queue-file mapping code. 268 */ 269 for (ptr = site; (ch = *(unsigned const char *) ptr) != 0; ptr++) 270 if (ISALNUM(ch)) 271 VSTRING_ADDCH(path, ch); 272 else 273 VSTRING_ADDCH(path, '_'); 274 VSTRING_TERMINATE(path); 275 276 if (msg_verbose) 277 msg_info("site %s to path %s", site, STR(path)); 278 279 return (path); 280 } 281 282 /* flush_add_service - append queue ID to per-site fast flush logfile */ 283 284 static int flush_add_service(const char *site, const char *queue_id) 285 { 286 const char *myname = "flush_add_service"; 287 VSTRING *site_path; 288 int status; 289 290 if (msg_verbose) 291 msg_info("%s: site %s queue_id %s", myname, site, queue_id); 292 293 /* 294 * If this site is not eligible for logging, deny the request. 295 */ 296 if (domain_list_match(flush_domains, site) == 0) 297 return (flush_domains->error ? FLUSH_STAT_FAIL : FLUSH_STAT_DENY); 298 299 /* 300 * Map site to path and update log. 301 */ 302 site_path = flush_site_to_path((VSTRING *) 0, site); 303 status = flush_add_path(STR(site_path), queue_id); 304 vstring_free(site_path); 305 306 return (status); 307 } 308 309 /* flush_add_path - add record to log */ 310 311 static int flush_add_path(const char *path, const char *queue_id) 312 { 313 const char *myname = "flush_add_path"; 314 VSTREAM *log; 315 316 /* 317 * Sanity check. 318 */ 319 if (!mail_queue_id_ok(path)) 320 return (FLUSH_STAT_BAD); 321 322 /* 323 * Open the logfile or bust. 324 */ 325 if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, 326 O_CREAT | O_APPEND | O_WRONLY, 0600)) == 0) 327 msg_fatal("%s: open fast flush logfile %s: %m", myname, path); 328 329 /* 330 * We must lock the logfile, so that we don't lose information due to 331 * concurrent access. If the lock takes too long, the Postfix watchdog 332 * will eventually take care of the problem, but it will take a while. 333 */ 334 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) 335 msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); 336 337 /* 338 * Append the queue ID. With 15 bits of microsecond time, a queue ID is 339 * not recycled often enough for false hits to be a problem. If it does, 340 * then we could add other signature information, such as the file size 341 * in bytes. 342 */ 343 vstream_fprintf(log, "%s\n", queue_id); 344 if (vstream_fflush(log)) 345 msg_warn("write fast flush logfile %s: %m", path); 346 347 /* 348 * Clean up. 349 */ 350 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) 351 msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); 352 if (vstream_fclose(log) != 0) 353 msg_warn("write fast flush logfile %s: %m", path); 354 355 return (FLUSH_STAT_OK); 356 } 357 358 /* flush_send_service - flush mail queued for site */ 359 360 static int flush_send_service(const char *site, int how) 361 { 362 const char *myname = "flush_send_service"; 363 VSTRING *site_path; 364 int status; 365 366 if (msg_verbose) 367 msg_info("%s: site %s", myname, site); 368 369 /* 370 * If this site is not eligible for logging, deny the request. 371 */ 372 if (domain_list_match(flush_domains, site) == 0) 373 return (flush_domains->error ? FLUSH_STAT_FAIL : FLUSH_STAT_DENY); 374 375 /* 376 * Map site name to path name and flush the log. 377 */ 378 site_path = flush_site_to_path((VSTRING *) 0, site); 379 status = flush_send_path(STR(site_path), how); 380 vstring_free(site_path); 381 382 return (status); 383 } 384 385 /* flush_one_file - move one queue file to incoming queue */ 386 387 static int flush_one_file(const char *queue_id, VSTRING *queue_file, 388 struct utimbuf * tbuf, int how) 389 { 390 const char *myname = "flush_one_file"; 391 const char *queue_name; 392 const char *path; 393 394 /* 395 * Some other instance of this program may flush some logfile and may 396 * just have moved this queue file to the incoming queue. 397 */ 398 for (queue_name = MAIL_QUEUE_DEFERRED; /* see below */ ; 399 queue_name = MAIL_QUEUE_INCOMING) { 400 path = mail_queue_path(queue_file, queue_name, queue_id); 401 if (utime(path, tbuf) == 0) 402 break; 403 if (errno != ENOENT) 404 msg_warn("%s: update %s time stamps: %m", myname, path); 405 if (STREQ(queue_name, MAIL_QUEUE_INCOMING)) 406 return (0); 407 } 408 409 /* 410 * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue 411 * manager to unthrottle transports and queues as it reads recipients 412 * from a queue file. We request this unthrottle operation by setting the 413 * group read permission bit. 414 * 415 * Note: we must avoid using chmod(). It is not only slower than fchmod() 416 * but it is also less secure. With chmod(), an attacker could repeatedly 417 * send requests to the flush server and trick it into changing 418 * permissions of non-queue files, by exploiting a race condition. 419 * 420 * We use safe_open() because we don't validate the file content before 421 * modifying the file status. 422 */ 423 if (how & UNTHROTTLE_AFTER) { 424 VSTRING *why; 425 struct stat st; 426 VSTREAM *fp; 427 428 for (why = vstring_alloc(1); /* see below */ ; 429 queue_name = MAIL_QUEUE_INCOMING, 430 path = mail_queue_path(queue_file, queue_name, queue_id)) { 431 if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) != 0) 432 break; 433 if (errno != ENOENT) 434 msg_warn("%s: open %s: %s", myname, path, STR(why)); 435 if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) { 436 vstring_free(why); 437 return (0); 438 } 439 } 440 vstring_free(why); 441 if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) { 442 (void) vstream_fclose(fp); 443 return (0); 444 } 445 if (fchmod(vstream_fileno(fp), st.st_mode | MAIL_QUEUE_STAT_UNTHROTTLE) < 0) 446 msg_warn("%s: fchmod %s: %m", myname, path); 447 (void) vstream_fclose(fp); 448 } 449 450 /* 451 * Move the file to the incoming queue, if it isn't already there. 452 */ 453 if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0 454 && mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0 455 && errno != ENOENT) 456 msg_warn("%s: rename from %s to %s: %m", 457 path, queue_name, MAIL_QUEUE_INCOMING); 458 459 /* 460 * If we got here, we achieved something, so let's claim succes. 461 */ 462 return (1); 463 } 464 465 /* flush_send_path - flush logfile file */ 466 467 static int flush_send_path(const char *path, int how) 468 { 469 const char *myname = "flush_send_path"; 470 VSTRING *queue_id; 471 VSTRING *queue_file; 472 VSTREAM *log; 473 struct utimbuf tbuf; 474 static char qmgr_flush_trigger[] = { 475 QMGR_REQ_FLUSH_DEAD, /* flush dead site/transport cache */ 476 }; 477 static char qmgr_scan_trigger[] = { 478 QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ 479 }; 480 HTABLE *dup_filter; 481 int count; 482 483 /* 484 * Sanity check. 485 */ 486 if (!mail_queue_id_ok(path)) 487 return (FLUSH_STAT_BAD); 488 489 /* 490 * Open the logfile. If the file does not exist, then there is no queued 491 * mail for this destination. 492 */ 493 if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, O_RDWR, 0600)) == 0) { 494 if (errno != ENOENT) 495 msg_fatal("%s: open fast flush logfile %s: %m", myname, path); 496 return (FLUSH_STAT_OK); 497 } 498 499 /* 500 * We must lock the logfile, so that we don't lose information when it is 501 * truncated. Unfortunately, this means that the file can be locked for a 502 * significant amount of time. If things really get stuck the Postfix 503 * watchdog will take care of it. 504 */ 505 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) 506 msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); 507 508 /* 509 * With the UNTHROTTLE_BEFORE strategy, we ask the queue manager to 510 * unthrottle all transports and queues before we move a deferred queue 511 * file to the incoming queue. This minimizes a race condition where the 512 * queue manager seizes a queue file before it knows that we want to 513 * flush that message. 514 * 515 * This reduces the race condition time window to a very small amount (the 516 * flush server does not really know when the queue manager reads its 517 * command fifo). But there is a worse race, where the queue manager 518 * moves a deferred queue file to the active queue before we have a 519 * chance to expedite its delivery. 520 */ 521 if (how & UNTHROTTLE_BEFORE) 522 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 523 qmgr_flush_trigger, sizeof(qmgr_flush_trigger)); 524 525 /* 526 * This is the part that dominates running time: schedule the listed 527 * queue files for delivery by updating their file time stamps and by 528 * moving them from the deferred queue to the incoming queue. This should 529 * take no more than a couple seconds under normal conditions. Filter out 530 * duplicate queue file names to avoid hammering the file system, with 531 * some finite limit on the amount of memory that we are willing to 532 * sacrifice for duplicate filtering. Graceful degradation. 533 * 534 * By moving selected queue files from the deferred queue to the incoming 535 * queue we optimize for the case where most deferred mail is for other 536 * sites. If that assumption does not hold, i.e. all deferred mail is for 537 * the same site, then doing a "fast flush" will cost more disk I/O than 538 * a "slow flush" that delivers the entire deferred queue. This penalty 539 * is only temporary - it will go away after we unite the active queue 540 * and the incoming queue. 541 */ 542 queue_id = vstring_alloc(10); 543 queue_file = vstring_alloc(10); 544 dup_filter = htable_create(10); 545 tbuf.actime = tbuf.modtime = event_time(); 546 for (count = 0; vstring_get_nonl(queue_id, log) != VSTREAM_EOF; count++) { 547 if (!mail_queue_id_ok(STR(queue_id))) { 548 msg_warn("bad queue id \"%.30s...\" in fast flush logfile %s", 549 STR(queue_id), path); 550 continue; 551 } 552 if (dup_filter->used >= FLUSH_DUP_FILTER_SIZE 553 || htable_find(dup_filter, STR(queue_id)) == 0) { 554 if (msg_verbose) 555 msg_info("%s: logfile %s: update queue file %s time stamps", 556 myname, path, STR(queue_id)); 557 if (dup_filter->used <= FLUSH_DUP_FILTER_SIZE) 558 htable_enter(dup_filter, STR(queue_id), 0); 559 count += flush_one_file(STR(queue_id), queue_file, &tbuf, how); 560 } else { 561 if (msg_verbose) 562 msg_info("%s: logfile %s: skip queue file %s as duplicate", 563 myname, path, STR(queue_file)); 564 } 565 } 566 htable_free(dup_filter, (void (*) (char *)) 0); 567 vstring_free(queue_file); 568 vstring_free(queue_id); 569 570 /* 571 * Truncate the fast flush log. 572 */ 573 if (count > 0 && ftruncate(vstream_fileno(log), (off_t) 0) < 0) 574 msg_fatal("%s: truncate fast flush logfile %s: %m", myname, path); 575 576 /* 577 * Workaround for noatime mounts. Use futimes() if available. 578 */ 579 (void) utimes(VSTREAM_PATH(log), (struct timeval *) 0); 580 581 /* 582 * Request delivery and clean up. 583 */ 584 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) 585 msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); 586 if (vstream_fclose(log) != 0) 587 msg_warn("%s: read fast flush logfile %s: %m", myname, path); 588 if (count > 0) { 589 if (msg_verbose) 590 msg_info("%s: requesting delivery for logfile %s", myname, path); 591 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 592 qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); 593 } 594 return (FLUSH_STAT_OK); 595 } 596 597 /* flush_send_file_service - flush one queue file */ 598 599 static int flush_send_file_service(const char *queue_id) 600 { 601 const char *myname = "flush_send_file_service"; 602 VSTRING *queue_file; 603 struct utimbuf tbuf; 604 static char qmgr_scan_trigger[] = { 605 QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ 606 }; 607 608 /* 609 * Sanity check. 610 */ 611 if (!mail_queue_id_ok(queue_id)) 612 return (FLUSH_STAT_BAD); 613 614 if (msg_verbose) 615 msg_info("%s: requesting delivery for queue_id %s", myname, queue_id); 616 617 queue_file = vstring_alloc(30); 618 tbuf.actime = tbuf.modtime = event_time(); 619 if (flush_one_file(queue_id, queue_file, &tbuf, UNTHROTTLE_AFTER) > 0) 620 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 621 qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); 622 vstring_free(queue_file); 623 624 return (FLUSH_STAT_OK); 625 } 626 627 /* flush_refresh_service - refresh logfiles beyond some age */ 628 629 static int flush_refresh_service(int max_age) 630 { 631 const char *myname = "flush_refresh_service"; 632 SCAN_DIR *scan; 633 char *site_path; 634 struct stat st; 635 VSTRING *path = vstring_alloc(10); 636 637 scan = scan_dir_open(MAIL_QUEUE_FLUSH); 638 while ((site_path = mail_scan_dir_next(scan)) != 0) { 639 if (!mail_queue_id_ok(site_path)) 640 continue; /* XXX grumble. */ 641 mail_queue_path(path, MAIL_QUEUE_FLUSH, site_path); 642 if (stat(STR(path), &st) < 0) { 643 if (errno != ENOENT) 644 msg_warn("%s: stat %s: %m", myname, STR(path)); 645 else if (msg_verbose) 646 msg_info("%s: %s: %m", myname, STR(path)); 647 continue; 648 } 649 if (st.st_size == 0) { 650 if (st.st_mtime + var_fflush_purge < event_time()) { 651 if (unlink(STR(path)) < 0) 652 msg_warn("remove logfile %s: %m", STR(path)); 653 else if (msg_verbose) 654 msg_info("%s: unlink %s, empty and unchanged for %d days", 655 myname, STR(path), var_fflush_purge / 86400); 656 } else if (msg_verbose) 657 msg_info("%s: skip logfile %s - empty log", myname, site_path); 658 } else if (st.st_atime + max_age < event_time()) { 659 if (msg_verbose) 660 msg_info("%s: flush logfile %s", myname, site_path); 661 flush_send_path(site_path, REFRESH_ONLY); 662 } else { 663 if (msg_verbose) 664 msg_info("%s: skip logfile %s, unread for <%d hours(s) ", 665 myname, site_path, max_age / 3600); 666 } 667 } 668 scan_dir_close(scan); 669 vstring_free(path); 670 671 return (FLUSH_STAT_OK); 672 } 673 674 /* flush_request_receive - receive request */ 675 676 static int flush_request_receive(VSTREAM *client_stream, VSTRING *request) 677 { 678 int count; 679 680 /* 681 * Kluge: choose the protocol depending on the request size. 682 */ 683 if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) { 684 msg_warn("timeout while waiting for data from %s", 685 VSTREAM_PATH(client_stream)); 686 return (-1); 687 } 688 if ((count = peekfd(vstream_fileno(client_stream))) < 0) { 689 msg_warn("cannot examine read buffer of %s: %m", 690 VSTREAM_PATH(client_stream)); 691 return (-1); 692 } 693 694 /* 695 * Short request: master trigger. Use the string+null protocol. 696 */ 697 if (count <= 2) { 698 if (vstring_get_null(request, client_stream) == VSTREAM_EOF) { 699 msg_warn("end-of-input while reading request from %s: %m", 700 VSTREAM_PATH(client_stream)); 701 return (-1); 702 } 703 } 704 705 /* 706 * Long request: real flush client. Use the attribute list protocol. 707 */ 708 else { 709 if (attr_scan(client_stream, 710 ATTR_FLAG_MORE | ATTR_FLAG_STRICT, 711 ATTR_TYPE_STR, MAIL_ATTR_REQ, request, 712 ATTR_TYPE_END) != 1) { 713 return (-1); 714 } 715 } 716 return (0); 717 } 718 719 /* flush_service - perform service for client */ 720 721 static void flush_service(VSTREAM *client_stream, char *unused_service, 722 char **argv) 723 { 724 VSTRING *request = vstring_alloc(10); 725 VSTRING *site = 0; 726 VSTRING *queue_id = 0; 727 static char wakeup[] = { /* master wakeup request */ 728 TRIGGER_REQ_WAKEUP, 729 0, 730 }; 731 int status = FLUSH_STAT_BAD; 732 733 /* 734 * Sanity check. This service takes no command-line arguments. 735 */ 736 if (argv[0]) 737 msg_fatal("unexpected command-line argument: %s", argv[0]); 738 739 /* 740 * This routine runs whenever a client connects to the UNIX-domain socket 741 * dedicated to the fast flush service. What we see below is a little 742 * protocol to (1) read a request from the client (the name of the site) 743 * and (2) acknowledge that we have received the request. 744 * 745 * All connection-management stuff is handled by the common code in 746 * single_server.c. 747 */ 748 if (flush_request_receive(client_stream, request) == 0) { 749 if (STREQ(STR(request), FLUSH_REQ_ADD)) { 750 site = vstring_alloc(10); 751 queue_id = vstring_alloc(10); 752 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 753 ATTR_TYPE_STR, MAIL_ATTR_SITE, site, 754 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 755 ATTR_TYPE_END) == 2 756 && mail_queue_id_ok(STR(queue_id))) 757 status = flush_add_service(lowercase(STR(site)), STR(queue_id)); 758 attr_print(client_stream, ATTR_FLAG_NONE, 759 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 760 ATTR_TYPE_END); 761 } else if (STREQ(STR(request), FLUSH_REQ_SEND_SITE)) { 762 site = vstring_alloc(10); 763 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 764 ATTR_TYPE_STR, MAIL_ATTR_SITE, site, 765 ATTR_TYPE_END) == 1) 766 status = flush_send_service(lowercase(STR(site)), 767 UNTHROTTLE_BEFORE); 768 attr_print(client_stream, ATTR_FLAG_NONE, 769 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 770 ATTR_TYPE_END); 771 } else if (STREQ(STR(request), FLUSH_REQ_SEND_FILE)) { 772 queue_id = vstring_alloc(10); 773 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 774 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 775 ATTR_TYPE_END) == 1) 776 status = flush_send_file_service(STR(queue_id)); 777 attr_print(client_stream, ATTR_FLAG_NONE, 778 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 779 ATTR_TYPE_END); 780 } else if (STREQ(STR(request), FLUSH_REQ_REFRESH) 781 || STREQ(STR(request), wakeup)) { 782 attr_print(client_stream, ATTR_FLAG_NONE, 783 ATTR_TYPE_INT, MAIL_ATTR_STATUS, FLUSH_STAT_OK, 784 ATTR_TYPE_END); 785 vstream_fflush(client_stream); 786 (void) flush_refresh_service(var_fflush_refresh); 787 } else if (STREQ(STR(request), FLUSH_REQ_PURGE)) { 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(0); 793 } 794 } else 795 attr_print(client_stream, ATTR_FLAG_NONE, 796 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 797 ATTR_TYPE_END); 798 vstring_free(request); 799 if (site) 800 vstring_free(site); 801 if (queue_id) 802 vstring_free(queue_id); 803 } 804 805 /* pre_jail_init - pre-jail initialization */ 806 807 static void pre_jail_init(char *unused_name, char **unused_argv) 808 { 809 flush_domains = domain_list_init(MATCH_FLAG_RETURN 810 | match_parent_style(VAR_FFLUSH_DOMAINS), 811 var_fflush_domains); 812 } 813 814 MAIL_VERSION_STAMP_DECLARE; 815 816 /* main - pass control to the single-threaded skeleton */ 817 818 int main(int argc, char **argv) 819 { 820 static const CONFIG_TIME_TABLE time_table[] = { 821 VAR_FFLUSH_REFRESH, DEF_FFLUSH_REFRESH, &var_fflush_refresh, 1, 0, 822 VAR_FFLUSH_PURGE, DEF_FFLUSH_PURGE, &var_fflush_purge, 1, 0, 823 0, 824 }; 825 826 /* 827 * Fingerprint executables and core dumps. 828 */ 829 MAIL_VERSION_STAMP_ALLOCATE; 830 831 single_server_main(argc, argv, flush_service, 832 MAIL_SERVER_TIME_TABLE, time_table, 833 MAIL_SERVER_PRE_INIT, pre_jail_init, 834 MAIL_SERVER_UNLIMITED, 835 0); 836 } 837