| | @@ -77,10 +77,12 @@ |
| 77 | 77 | #else |
| 78 | 78 | # include <unistd.h> |
| 79 | 79 | # include <sys/types.h> |
| 80 | 80 | # include <signal.h> |
| 81 | 81 | # include <errno.h> |
| 82 | +# include <sys/time.h> |
| 83 | +# include <sys/resource.h> |
| 82 | 84 | # include <fcntl.h> |
| 83 | 85 | # define GETPID getpid |
| 84 | 86 | #endif |
| 85 | 87 | #include <time.h> |
| 86 | 88 | |
| | @@ -121,13 +123,32 @@ |
| 121 | 123 | ** should run if backoffice process is needed. It is set by the |
| 122 | 124 | ** backoffice_check_if_needed() routine which must be run while the database |
| 123 | 125 | ** file is open. Later, after the database is closed, the |
| 124 | 126 | ** backoffice_run_if_needed() will consult this variable to see if it |
| 125 | 127 | ** should be a no-op. |
| 128 | +** |
| 129 | +** The magic string "x" in this variable means "do not run the backoffice". |
| 126 | 130 | */ |
| 127 | 131 | static char *backofficeDb = 0; |
| 128 | 132 | |
| 133 | +/* |
| 134 | +** Log backoffice activity to a file named here. If not NULL, this |
| 135 | +** overrides the "backoffice-logfile" setting of the database. If NULL, |
| 136 | +** the "backoffice-logfile" setting is used instead. |
| 137 | +*/ |
| 138 | +static char *backofficeLogfile = 0; |
| 139 | + |
| 140 | +/* |
| 141 | +** Write backoffice log messages to this connection: |
| 142 | +*/ |
| 143 | +static FILE *backofficeLog = 0; |
| 144 | + |
| 145 | +/* |
| 146 | +** Prefix for backoffice log messages |
| 147 | +*/ |
| 148 | +static char *backofficeLogPrefix = 0; |
| 149 | + |
| 129 | 150 | /* End of state variables |
| 130 | 151 | ****************************************************************************/ |
| 131 | 152 | |
| 132 | 153 | /* |
| 133 | 154 | ** This function emits a diagnostic message related to the processing in |
| | @@ -514,32 +535,92 @@ |
| 514 | 535 | } |
| 515 | 536 | } |
| 516 | 537 | } |
| 517 | 538 | return; |
| 518 | 539 | } |
| 540 | + |
| 541 | +/* |
| 542 | +** Append to a message to the backoffice log, if the log is open. |
| 543 | +*/ |
| 544 | +void backoffice_log(const char *zFormat, ...){ |
| 545 | + va_list ap; |
| 546 | + if( backofficeLog==0 ) return; |
| 547 | + fprintf(backofficeLog, "%s ", backofficeLogPrefix); |
| 548 | + va_start(ap, zFormat); |
| 549 | + vfprintf(backofficeLog, zFormat, ap); |
| 550 | + fflush(backofficeLog); |
| 551 | + va_end(ap); |
| 552 | +} |
| 553 | + |
| 554 | +#if !defined(_WIN32) |
| 555 | +/* |
| 556 | +** Capture routine for signals while running backoffice. |
| 557 | +*/ |
| 558 | +static void backoffice_signal_handler(int sig){ |
| 559 | + const char *zSig = "(unk)"; |
| 560 | + if( sig==SIGSEGV ) zSig = "SIGSEGV"; |
| 561 | + if( sig==SIGFPE ) zSig = "SIGFPE"; |
| 562 | + if( sig==SIGABRT ) zSig = "SIGABRT"; |
| 563 | + if( sig==SIGILL ) zSig = "SIGILL"; |
| 564 | + backoffice_log("caught signal %d %s\n", sig, zSig); |
| 565 | + exit(1); |
| 566 | +} |
| 567 | +#endif |
| 568 | + |
| 569 | +#if !defined(_WIN32) |
| 570 | +/* |
| 571 | +** Convert a struct timeval into an integer number of microseconds |
| 572 | +*/ |
| 573 | +static long long int tvms(struct timeval *p){ |
| 574 | + return ((long long int)p->tv_sec)*1000000 + (long long int)p->tv_usec; |
| 575 | +} |
| 576 | +#endif |
| 577 | + |
| 519 | 578 | |
| 520 | 579 | /* |
| 521 | 580 | ** This routine runs to do the backoffice processing. When adding new |
| 522 | 581 | ** backoffice processing tasks, add them here. |
| 523 | 582 | */ |
| 524 | 583 | void backoffice_work(void){ |
| 525 | 584 | /* Log the backoffice run for testing purposes. For production deployments |
| 526 | 585 | ** the "backoffice-logfile" property should be unset and the following code |
| 527 | 586 | ** should be a no-op. */ |
| 528 | | - char *zLog = db_get("backoffice-logfile",0); |
| 587 | + char *zLog = backofficeLogfile; |
| 588 | + int nAlert = 0; |
| 589 | + int nSmtp = 0; |
| 590 | +#if !defined(_WIN32) |
| 591 | + struct timeval sStart, sEnd; |
| 592 | +#endif |
| 593 | + if( zLog==0 ) db_get("backoffice-logfile",0); |
| 529 | 594 | if( zLog && zLog[0] ){ |
| 530 | | - FILE *pLog = fossil_fopen(zLog, "a"); |
| 531 | | - if( pLog ){ |
| 532 | | - char *zDate = db_text(0, "SELECT datetime('now');"); |
| 533 | | - fprintf(pLog, "%s (%d) backoffice running\n", zDate, GETPID()); |
| 534 | | - fclose(pLog); |
| 535 | | - } |
| 595 | + backofficeLog = fossil_fopen(zLog, "a"); |
| 596 | + backofficeLogPrefix = mprintf("%d %s", |
| 597 | + GETPID(), db_get("project-name","???")); |
| 598 | + backoffice_log("start %s\n", db_text(0, "SELECT datetime('now');")); |
| 599 | +#if !defined(_WIN32) |
| 600 | + gettimeofday(&sStart, 0); |
| 601 | + signal(SIGSEGV, backoffice_signal_handler); |
| 602 | + signal(SIGABRT, backoffice_signal_handler); |
| 603 | + signal(SIGFPE, backoffice_signal_handler); |
| 604 | + signal(SIGILL, backoffice_signal_handler); |
| 605 | +#endif |
| 536 | 606 | } |
| 537 | 607 | |
| 538 | 608 | /* Here is where the actual work of the backoffice happens */ |
| 539 | | - alert_backoffice(0); |
| 540 | | - smtp_cleanup(); |
| 609 | + nAlert = alert_backoffice(0); |
| 610 | + if( nAlert ) backoffice_log("%d alerts sent\n", nAlert); |
| 611 | + nSmtp = smtp_cleanup(); |
| 612 | + if( nSmtp ) backoffice_log("%d SMTP cleanup ops\n", nSmtp); |
| 613 | + |
| 614 | + /* Close the log */ |
| 615 | + if( backofficeLog ){ |
| 616 | +#if !defined(_WIN32) |
| 617 | + gettimeofday(&sEnd,0); |
| 618 | + backoffice_log("elapse time %d us\n", tvms(&sEnd) - tvms(&sStart)); |
| 619 | +#endif |
| 620 | + fclose(backofficeLog); |
| 621 | + } |
| 541 | 622 | } |
| 542 | 623 | |
| 543 | 624 | /* |
| 544 | 625 | ** COMMAND: backoffice* |
| 545 | 626 | ** |
| | @@ -554,10 +635,12 @@ |
| 554 | 635 | ** on collection of repositories. |
| 555 | 636 | ** |
| 556 | 637 | ** OPTIONS: |
| 557 | 638 | ** |
| 558 | 639 | ** --debug Show what this command is doing. |
| 640 | +** |
| 641 | +** --logfile FILE Append a log of backoffice actions onto FILE. |
| 559 | 642 | ** |
| 560 | 643 | ** --min N When polling, invoke backoffice at least |
| 561 | 644 | ** once every N seconds even if the repository |
| 562 | 645 | ** never changes. 0 or negative means disable |
| 563 | 646 | ** this feature. Default: 3600 (once per hour). |
| | @@ -581,10 +664,11 @@ |
| 581 | 664 | const char *zPoll; |
| 582 | 665 | int bDebug = 0; |
| 583 | 666 | unsigned int nCmd = 0; |
| 584 | 667 | if( find_option("trace",0,0)!=0 ) g.fAnyTrace = 1; |
| 585 | 668 | if( find_option("nodelay",0,0)!=0 ) backofficeNoDelay = 1; |
| 669 | + backofficeLogfile = find_option("logfile",0,1); |
| 586 | 670 | zPoll = find_option("poll",0,1); |
| 587 | 671 | nPoll = zPoll ? atoi(zPoll) : 0; |
| 588 | 672 | zPoll = find_option("min",0,1); |
| 589 | 673 | nMin = zPoll ? atoi(zPoll) : 3600; |
| 590 | 674 | bDebug = find_option("debug",0,0)!=0; |
| 591 | 675 | |