Fossil SCM
Add the --errorlog command-line option and the errorlog: parameter to CGI scripts. Log all panics, fatal errors, and warnings to the error log, if defined. Panic if file descriptor 2 is not open on unix. Clean up some routines that deal with close().
Commit
4727ef4a8e6b266b9f6bb7f327b078fbe5b8d4fe
Parent
9d73d4c127fc8cf…
5 files changed
+14
-15
+14
-7
+38
+1
+15
+14
-15
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -766,21 +766,20 @@ | ||
| 766 | 766 | ** |
| 767 | 767 | ** Return the number of bytes written. |
| 768 | 768 | */ |
| 769 | 769 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 770 | 770 | FILE *out; |
| 771 | - int wrote; | |
| 771 | + int nWrote; | |
| 772 | 772 | |
| 773 | 773 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 774 | - int n = blob_size(pBlob); | |
| 774 | + nWrote = blob_size(pBlob); | |
| 775 | 775 | #if defined(_WIN32) |
| 776 | - if( fossil_utf8_to_console(blob_buffer(pBlob), n, 0) >= 0 ){ | |
| 777 | - return n; | |
| 776 | + if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){ | |
| 777 | + return nWrote; | |
| 778 | 778 | } |
| 779 | 779 | #endif |
| 780 | - fwrite(blob_buffer(pBlob), 1, n, stdout); | |
| 781 | - return n; | |
| 780 | + fwrite(blob_buffer(pBlob), 1, nWrote, stdout); | |
| 782 | 781 | }else{ |
| 783 | 782 | int i, nName; |
| 784 | 783 | char *zName, zBuf[1000]; |
| 785 | 784 | |
| 786 | 785 | nName = strlen(zFilename); |
| @@ -816,19 +815,19 @@ | ||
| 816 | 815 | if( out==0 ){ |
| 817 | 816 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 818 | 817 | return 0; |
| 819 | 818 | } |
| 820 | 819 | if( zName!=zBuf ) free(zName); |
| 821 | - } | |
| 822 | - blob_is_init(pBlob); | |
| 823 | - wrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); | |
| 824 | - fclose(out); | |
| 825 | - if( wrote!=blob_size(pBlob) && out!=stdout ){ | |
| 826 | - fossil_fatal_recursive("short write: %d of %d bytes to %s", wrote, | |
| 827 | - blob_size(pBlob), zFilename); | |
| 828 | - } | |
| 829 | - return wrote; | |
| 820 | + blob_is_init(pBlob); | |
| 821 | + nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); | |
| 822 | + fclose(out); | |
| 823 | + if( nWrote!=blob_size(pBlob) ){ | |
| 824 | + fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote, | |
| 825 | + blob_size(pBlob), zFilename); | |
| 826 | + } | |
| 827 | + } | |
| 828 | + return nWrote; | |
| 830 | 829 | } |
| 831 | 830 | |
| 832 | 831 | /* |
| 833 | 832 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 834 | 833 | ** pOut to be the same blob. |
| 835 | 834 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -766,21 +766,20 @@ | |
| 766 | ** |
| 767 | ** Return the number of bytes written. |
| 768 | */ |
| 769 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 770 | FILE *out; |
| 771 | int wrote; |
| 772 | |
| 773 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 774 | int n = blob_size(pBlob); |
| 775 | #if defined(_WIN32) |
| 776 | if( fossil_utf8_to_console(blob_buffer(pBlob), n, 0) >= 0 ){ |
| 777 | return n; |
| 778 | } |
| 779 | #endif |
| 780 | fwrite(blob_buffer(pBlob), 1, n, stdout); |
| 781 | return n; |
| 782 | }else{ |
| 783 | int i, nName; |
| 784 | char *zName, zBuf[1000]; |
| 785 | |
| 786 | nName = strlen(zFilename); |
| @@ -816,19 +815,19 @@ | |
| 816 | if( out==0 ){ |
| 817 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 818 | return 0; |
| 819 | } |
| 820 | if( zName!=zBuf ) free(zName); |
| 821 | } |
| 822 | blob_is_init(pBlob); |
| 823 | wrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); |
| 824 | fclose(out); |
| 825 | if( wrote!=blob_size(pBlob) && out!=stdout ){ |
| 826 | fossil_fatal_recursive("short write: %d of %d bytes to %s", wrote, |
| 827 | blob_size(pBlob), zFilename); |
| 828 | } |
| 829 | return wrote; |
| 830 | } |
| 831 | |
| 832 | /* |
| 833 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 834 | ** pOut to be the same blob. |
| 835 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -766,21 +766,20 @@ | |
| 766 | ** |
| 767 | ** Return the number of bytes written. |
| 768 | */ |
| 769 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 770 | FILE *out; |
| 771 | int nWrote; |
| 772 | |
| 773 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 774 | nWrote = blob_size(pBlob); |
| 775 | #if defined(_WIN32) |
| 776 | if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){ |
| 777 | return nWrote; |
| 778 | } |
| 779 | #endif |
| 780 | fwrite(blob_buffer(pBlob), 1, nWrote, stdout); |
| 781 | }else{ |
| 782 | int i, nName; |
| 783 | char *zName, zBuf[1000]; |
| 784 | |
| 785 | nName = strlen(zFilename); |
| @@ -816,19 +815,19 @@ | |
| 815 | if( out==0 ){ |
| 816 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 817 | return 0; |
| 818 | } |
| 819 | if( zName!=zBuf ) free(zName); |
| 820 | blob_is_init(pBlob); |
| 821 | nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); |
| 822 | fclose(out); |
| 823 | if( nWrote!=blob_size(pBlob) ){ |
| 824 | fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote, |
| 825 | blob_size(pBlob), zFilename); |
| 826 | } |
| 827 | } |
| 828 | return nWrote; |
| 829 | } |
| 830 | |
| 831 | /* |
| 832 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 833 | ** pOut to be the same blob. |
| 834 |
+14
-7
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -114,10 +114,11 @@ | ||
| 114 | 114 | ** All global variables are in this structure. |
| 115 | 115 | */ |
| 116 | 116 | struct Global { |
| 117 | 117 | int argc; char **argv; /* Command-line arguments to the program */ |
| 118 | 118 | char *nameOfExe; /* Full path of executable. */ |
| 119 | + const char *zErrlog; /* Log errors to this file, if not NULL */ | |
| 119 | 120 | int isConst; /* True if the output is unchanging */ |
| 120 | 121 | sqlite3 *db; /* The connection to the databases */ |
| 121 | 122 | sqlite3 *dbConfig; /* Separate connection for global_config table */ |
| 122 | 123 | int useAttach; /* True if global_config is attached to repository */ |
| 123 | 124 | const char *zConfigDbName;/* Path of the config database. NULL if not open */ |
| @@ -372,11 +373,11 @@ | ||
| 372 | 373 | unsigned int i, j, k; /* Loop counters */ |
| 373 | 374 | int n; /* Number of bytes in one line */ |
| 374 | 375 | char *z; /* General use string pointer */ |
| 375 | 376 | char **newArgv; /* New expanded g.argv under construction */ |
| 376 | 377 | char const * zFileName; /* input file name */ |
| 377 | - FILE * zInFile; /* input FILE */ | |
| 378 | + FILE *inFile; /* input FILE */ | |
| 378 | 379 | #if defined(_WIN32) |
| 379 | 380 | wchar_t buf[MAX_PATH]; |
| 380 | 381 | #endif |
| 381 | 382 | |
| 382 | 383 | g.argc = argc; |
| @@ -402,21 +403,21 @@ | ||
| 402 | 403 | if( fossil_strcmp(z, "args")==0 ) break; |
| 403 | 404 | } |
| 404 | 405 | if( i>=g.argc-1 ) return; |
| 405 | 406 | |
| 406 | 407 | zFileName = g.argv[i+1]; |
| 407 | - zInFile = (0==strcmp("-",zFileName)) | |
| 408 | + inFile = (0==strcmp("-",zFileName)) | |
| 408 | 409 | ? stdin |
| 409 | 410 | : fossil_fopen(zFileName,"rb"); |
| 410 | - if(!zInFile){ | |
| 411 | + if(!inFile){ | |
| 411 | 412 | fossil_fatal("Cannot open -args file [%s]", zFileName); |
| 412 | 413 | }else{ |
| 413 | - blob_read_from_channel(&file, zInFile, -1); | |
| 414 | - if(stdin != zInFile){ | |
| 415 | - fclose(zInFile); | |
| 414 | + blob_read_from_channel(&file, inFile, -1); | |
| 415 | + if(stdin != inFile){ | |
| 416 | + fclose(inFile); | |
| 416 | 417 | } |
| 417 | - zInFile = NULL; | |
| 418 | + inFile = NULL; | |
| 418 | 419 | } |
| 419 | 420 | blob_to_utf8_no_bom(&file, 1); |
| 420 | 421 | z = blob_str(&file); |
| 421 | 422 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 422 | 423 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| @@ -586,10 +587,11 @@ | ||
| 586 | 587 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 587 | 588 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 588 | 589 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 589 | 590 | g.zLogin = find_option("user", "U", 1); |
| 590 | 591 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| 592 | + g.zErrlog = find_option("errorlog", 0, 1); | |
| 591 | 593 | if( find_option("utc",0,0) ) g.fTimeFormat = 1; |
| 592 | 594 | if( find_option("localtime",0,0) ) g.fTimeFormat = 2; |
| 593 | 595 | if( zChdir && file_chdir(zChdir, 0) ){ |
| 594 | 596 | fossil_fatal("unable to change directories to %s", zChdir); |
| 595 | 597 | } |
| @@ -605,10 +607,11 @@ | ||
| 605 | 607 | g.argc++; |
| 606 | 608 | g.argv = zNewArgv; |
| 607 | 609 | } |
| 608 | 610 | zCmdName = g.argv[1]; |
| 609 | 611 | } |
| 612 | + if( !is_valid_fd(2) ) fossil_panic("file descriptor 2 not open"); | |
| 610 | 613 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 611 | 614 | if( rc==1 ){ |
| 612 | 615 | fossil_fatal("%s: unknown command: %s\n" |
| 613 | 616 | "%s: use \"help\" for more information\n", |
| 614 | 617 | g.argv[0], zCmdName, g.argv[0]); |
| @@ -1504,10 +1507,14 @@ | ||
| 1504 | 1507 | if( blob_buffer(&key)[0]=='#' ) continue; |
| 1505 | 1508 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 1506 | 1509 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 1507 | 1510 | blob_reset(&value); |
| 1508 | 1511 | continue; |
| 1512 | + } | |
| 1513 | + if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ | |
| 1514 | + g.zErrlog = mprintf("%s", blob_str(&value)); | |
| 1515 | + continue; | |
| 1509 | 1516 | } |
| 1510 | 1517 | if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ |
| 1511 | 1518 | cgi_setenv("HOME", blob_str(&value)); |
| 1512 | 1519 | blob_reset(&value); |
| 1513 | 1520 | continue; |
| 1514 | 1521 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -114,10 +114,11 @@ | |
| 114 | ** All global variables are in this structure. |
| 115 | */ |
| 116 | struct Global { |
| 117 | int argc; char **argv; /* Command-line arguments to the program */ |
| 118 | char *nameOfExe; /* Full path of executable. */ |
| 119 | int isConst; /* True if the output is unchanging */ |
| 120 | sqlite3 *db; /* The connection to the databases */ |
| 121 | sqlite3 *dbConfig; /* Separate connection for global_config table */ |
| 122 | int useAttach; /* True if global_config is attached to repository */ |
| 123 | const char *zConfigDbName;/* Path of the config database. NULL if not open */ |
| @@ -372,11 +373,11 @@ | |
| 372 | unsigned int i, j, k; /* Loop counters */ |
| 373 | int n; /* Number of bytes in one line */ |
| 374 | char *z; /* General use string pointer */ |
| 375 | char **newArgv; /* New expanded g.argv under construction */ |
| 376 | char const * zFileName; /* input file name */ |
| 377 | FILE * zInFile; /* input FILE */ |
| 378 | #if defined(_WIN32) |
| 379 | wchar_t buf[MAX_PATH]; |
| 380 | #endif |
| 381 | |
| 382 | g.argc = argc; |
| @@ -402,21 +403,21 @@ | |
| 402 | if( fossil_strcmp(z, "args")==0 ) break; |
| 403 | } |
| 404 | if( i>=g.argc-1 ) return; |
| 405 | |
| 406 | zFileName = g.argv[i+1]; |
| 407 | zInFile = (0==strcmp("-",zFileName)) |
| 408 | ? stdin |
| 409 | : fossil_fopen(zFileName,"rb"); |
| 410 | if(!zInFile){ |
| 411 | fossil_fatal("Cannot open -args file [%s]", zFileName); |
| 412 | }else{ |
| 413 | blob_read_from_channel(&file, zInFile, -1); |
| 414 | if(stdin != zInFile){ |
| 415 | fclose(zInFile); |
| 416 | } |
| 417 | zInFile = NULL; |
| 418 | } |
| 419 | blob_to_utf8_no_bom(&file, 1); |
| 420 | z = blob_str(&file); |
| 421 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 422 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| @@ -586,10 +587,11 @@ | |
| 586 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 587 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 588 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 589 | g.zLogin = find_option("user", "U", 1); |
| 590 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| 591 | if( find_option("utc",0,0) ) g.fTimeFormat = 1; |
| 592 | if( find_option("localtime",0,0) ) g.fTimeFormat = 2; |
| 593 | if( zChdir && file_chdir(zChdir, 0) ){ |
| 594 | fossil_fatal("unable to change directories to %s", zChdir); |
| 595 | } |
| @@ -605,10 +607,11 @@ | |
| 605 | g.argc++; |
| 606 | g.argv = zNewArgv; |
| 607 | } |
| 608 | zCmdName = g.argv[1]; |
| 609 | } |
| 610 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 611 | if( rc==1 ){ |
| 612 | fossil_fatal("%s: unknown command: %s\n" |
| 613 | "%s: use \"help\" for more information\n", |
| 614 | g.argv[0], zCmdName, g.argv[0]); |
| @@ -1504,10 +1507,14 @@ | |
| 1504 | if( blob_buffer(&key)[0]=='#' ) continue; |
| 1505 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 1506 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 1507 | blob_reset(&value); |
| 1508 | continue; |
| 1509 | } |
| 1510 | if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ |
| 1511 | cgi_setenv("HOME", blob_str(&value)); |
| 1512 | blob_reset(&value); |
| 1513 | continue; |
| 1514 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -114,10 +114,11 @@ | |
| 114 | ** All global variables are in this structure. |
| 115 | */ |
| 116 | struct Global { |
| 117 | int argc; char **argv; /* Command-line arguments to the program */ |
| 118 | char *nameOfExe; /* Full path of executable. */ |
| 119 | const char *zErrlog; /* Log errors to this file, if not NULL */ |
| 120 | int isConst; /* True if the output is unchanging */ |
| 121 | sqlite3 *db; /* The connection to the databases */ |
| 122 | sqlite3 *dbConfig; /* Separate connection for global_config table */ |
| 123 | int useAttach; /* True if global_config is attached to repository */ |
| 124 | const char *zConfigDbName;/* Path of the config database. NULL if not open */ |
| @@ -372,11 +373,11 @@ | |
| 373 | unsigned int i, j, k; /* Loop counters */ |
| 374 | int n; /* Number of bytes in one line */ |
| 375 | char *z; /* General use string pointer */ |
| 376 | char **newArgv; /* New expanded g.argv under construction */ |
| 377 | char const * zFileName; /* input file name */ |
| 378 | FILE *inFile; /* input FILE */ |
| 379 | #if defined(_WIN32) |
| 380 | wchar_t buf[MAX_PATH]; |
| 381 | #endif |
| 382 | |
| 383 | g.argc = argc; |
| @@ -402,21 +403,21 @@ | |
| 403 | if( fossil_strcmp(z, "args")==0 ) break; |
| 404 | } |
| 405 | if( i>=g.argc-1 ) return; |
| 406 | |
| 407 | zFileName = g.argv[i+1]; |
| 408 | inFile = (0==strcmp("-",zFileName)) |
| 409 | ? stdin |
| 410 | : fossil_fopen(zFileName,"rb"); |
| 411 | if(!inFile){ |
| 412 | fossil_fatal("Cannot open -args file [%s]", zFileName); |
| 413 | }else{ |
| 414 | blob_read_from_channel(&file, inFile, -1); |
| 415 | if(stdin != inFile){ |
| 416 | fclose(inFile); |
| 417 | } |
| 418 | inFile = NULL; |
| 419 | } |
| 420 | blob_to_utf8_no_bom(&file, 1); |
| 421 | z = blob_str(&file); |
| 422 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 423 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| @@ -586,10 +587,11 @@ | |
| 587 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 588 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 589 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 590 | g.zLogin = find_option("user", "U", 1); |
| 591 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| 592 | g.zErrlog = find_option("errorlog", 0, 1); |
| 593 | if( find_option("utc",0,0) ) g.fTimeFormat = 1; |
| 594 | if( find_option("localtime",0,0) ) g.fTimeFormat = 2; |
| 595 | if( zChdir && file_chdir(zChdir, 0) ){ |
| 596 | fossil_fatal("unable to change directories to %s", zChdir); |
| 597 | } |
| @@ -605,10 +607,11 @@ | |
| 607 | g.argc++; |
| 608 | g.argv = zNewArgv; |
| 609 | } |
| 610 | zCmdName = g.argv[1]; |
| 611 | } |
| 612 | if( !is_valid_fd(2) ) fossil_panic("file descriptor 2 not open"); |
| 613 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 614 | if( rc==1 ){ |
| 615 | fossil_fatal("%s: unknown command: %s\n" |
| 616 | "%s: use \"help\" for more information\n", |
| 617 | g.argv[0], zCmdName, g.argv[0]); |
| @@ -1504,10 +1507,14 @@ | |
| 1507 | if( blob_buffer(&key)[0]=='#' ) continue; |
| 1508 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 1509 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 1510 | blob_reset(&value); |
| 1511 | continue; |
| 1512 | } |
| 1513 | if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ |
| 1514 | g.zErrlog = mprintf("%s", blob_str(&value)); |
| 1515 | continue; |
| 1516 | } |
| 1517 | if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ |
| 1518 | cgi_setenv("HOME", blob_str(&value)); |
| 1519 | blob_reset(&value); |
| 1520 | continue; |
| 1521 |
+38
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -22,10 +22,11 @@ | ||
| 22 | 22 | #include "printf.h" |
| 23 | 23 | #if defined(_WIN32) |
| 24 | 24 | # include <io.h> |
| 25 | 25 | # include <fcntl.h> |
| 26 | 26 | #endif |
| 27 | +#include <time.h> | |
| 27 | 28 | |
| 28 | 29 | /* |
| 29 | 30 | ** Conversion types fall into various categories as defined by the |
| 30 | 31 | ** following enumeration. |
| 31 | 32 | */ |
| @@ -906,10 +907,43 @@ | ||
| 906 | 907 | fossil_puts(blob_str(&b), 1); |
| 907 | 908 | blob_reset(&b); |
| 908 | 909 | va_end(ap); |
| 909 | 910 | } |
| 910 | 911 | |
| 912 | +/* | |
| 913 | +** Write a message to the error log, if the error log filename is | |
| 914 | +** defined. | |
| 915 | +*/ | |
| 916 | +static void fossil_errorlog(const char *zFormat, ...){ | |
| 917 | + struct tm *pNow; | |
| 918 | + time_t now; | |
| 919 | + FILE *out; | |
| 920 | + const char *z; | |
| 921 | + int i; | |
| 922 | + va_list ap; | |
| 923 | + static const char *azEnv[] = { "HTTP_HOST", "HTTP_USER_AGENT", | |
| 924 | + "PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD", | |
| 925 | + "REQUEST_URI", "SCRIPT_NAME" }; | |
| 926 | + if( g.zErrlog==0 ) return; | |
| 927 | + out = fopen(g.zErrlog, "a"); | |
| 928 | + if( out==0 ) return; | |
| 929 | + now = time(0); | |
| 930 | + pNow = gmtime(&now); | |
| 931 | + fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n", | |
| 932 | + pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday+1, | |
| 933 | + pNow->tm_hour, pNow->tm_min, pNow->tm_sec); | |
| 934 | + va_start(ap, zFormat); | |
| 935 | + vfprintf(out, zFormat, ap); | |
| 936 | + fprintf(out, "\n"); | |
| 937 | + va_end(ap); | |
| 938 | + for(i=0; i<sizeof(azEnv)/sizeof(azEnv[0]); i++){ | |
| 939 | + if( (z = getenv(azEnv[i]))!=0 || (z = P(azEnv[i]))!=0 ){ | |
| 940 | + fprintf(out, "%s=%s\n", azEnv[i], z); | |
| 941 | + } | |
| 942 | + } | |
| 943 | + fclose(out); | |
| 944 | +} | |
| 911 | 945 | |
| 912 | 946 | /* |
| 913 | 947 | ** The following variable becomes true while processing a fatal error |
| 914 | 948 | ** or a panic. If additional "recursive-fatal" errors occur while |
| 915 | 949 | ** shutting down, the recursive errors are silently ignored. |
| @@ -931,10 +965,11 @@ | ||
| 931 | 965 | mainInFatalError = 1; |
| 932 | 966 | db_force_rollback(); |
| 933 | 967 | va_start(ap, zFormat); |
| 934 | 968 | sqlite3_vsnprintf(sizeof(z),z,zFormat, ap); |
| 935 | 969 | va_end(ap); |
| 970 | + fossil_errorlog("panic: %s", z); | |
| 936 | 971 | #ifdef FOSSIL_ENABLE_JSON |
| 937 | 972 | if( g.json.isJsonMode ){ |
| 938 | 973 | json_err( 0, z, 1 ); |
| 939 | 974 | if( g.isHTTP ){ |
| 940 | 975 | rc = 0 /* avoid HTTP 500 */; |
| @@ -962,10 +997,11 @@ | ||
| 962 | 997 | va_list ap; |
| 963 | 998 | mainInFatalError = 1; |
| 964 | 999 | va_start(ap, zFormat); |
| 965 | 1000 | z = vmprintf(zFormat, ap); |
| 966 | 1001 | va_end(ap); |
| 1002 | + fossil_errorlog("fatal: %s", z); | |
| 967 | 1003 | #ifdef FOSSIL_ENABLE_JSON |
| 968 | 1004 | if( g.json.isJsonMode ){ |
| 969 | 1005 | json_err( g.json.resultCode, z, 1 ); |
| 970 | 1006 | if( g.isHTTP ){ |
| 971 | 1007 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1004,10 +1040,11 @@ | ||
| 1004 | 1040 | if( mainInFatalError ) return; |
| 1005 | 1041 | mainInFatalError = 1; |
| 1006 | 1042 | va_start(ap, zFormat); |
| 1007 | 1043 | z = vmprintf(zFormat, ap); |
| 1008 | 1044 | va_end(ap); |
| 1045 | + fossil_errorlog("fatal: %s", z); | |
| 1009 | 1046 | #ifdef FOSSIL_ENABLE_JSON |
| 1010 | 1047 | if( g.json.isJsonMode ){ |
| 1011 | 1048 | json_err( g.json.resultCode, z, 1 ); |
| 1012 | 1049 | if( g.isHTTP ){ |
| 1013 | 1050 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1034,10 +1071,11 @@ | ||
| 1034 | 1071 | char *z; |
| 1035 | 1072 | va_list ap; |
| 1036 | 1073 | va_start(ap, zFormat); |
| 1037 | 1074 | z = vmprintf(zFormat, ap); |
| 1038 | 1075 | va_end(ap); |
| 1076 | + fossil_errorlog("warning: %s", z); | |
| 1039 | 1077 | #ifdef FOSSIL_ENABLE_JSON |
| 1040 | 1078 | if(g.json.isJsonMode){ |
| 1041 | 1079 | json_warn( FSL_JSON_W_UNKNOWN, z ); |
| 1042 | 1080 | }else |
| 1043 | 1081 | #endif |
| 1044 | 1082 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -22,10 +22,11 @@ | |
| 22 | #include "printf.h" |
| 23 | #if defined(_WIN32) |
| 24 | # include <io.h> |
| 25 | # include <fcntl.h> |
| 26 | #endif |
| 27 | |
| 28 | /* |
| 29 | ** Conversion types fall into various categories as defined by the |
| 30 | ** following enumeration. |
| 31 | */ |
| @@ -906,10 +907,43 @@ | |
| 906 | fossil_puts(blob_str(&b), 1); |
| 907 | blob_reset(&b); |
| 908 | va_end(ap); |
| 909 | } |
| 910 | |
| 911 | |
| 912 | /* |
| 913 | ** The following variable becomes true while processing a fatal error |
| 914 | ** or a panic. If additional "recursive-fatal" errors occur while |
| 915 | ** shutting down, the recursive errors are silently ignored. |
| @@ -931,10 +965,11 @@ | |
| 931 | mainInFatalError = 1; |
| 932 | db_force_rollback(); |
| 933 | va_start(ap, zFormat); |
| 934 | sqlite3_vsnprintf(sizeof(z),z,zFormat, ap); |
| 935 | va_end(ap); |
| 936 | #ifdef FOSSIL_ENABLE_JSON |
| 937 | if( g.json.isJsonMode ){ |
| 938 | json_err( 0, z, 1 ); |
| 939 | if( g.isHTTP ){ |
| 940 | rc = 0 /* avoid HTTP 500 */; |
| @@ -962,10 +997,11 @@ | |
| 962 | va_list ap; |
| 963 | mainInFatalError = 1; |
| 964 | va_start(ap, zFormat); |
| 965 | z = vmprintf(zFormat, ap); |
| 966 | va_end(ap); |
| 967 | #ifdef FOSSIL_ENABLE_JSON |
| 968 | if( g.json.isJsonMode ){ |
| 969 | json_err( g.json.resultCode, z, 1 ); |
| 970 | if( g.isHTTP ){ |
| 971 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1004,10 +1040,11 @@ | |
| 1004 | if( mainInFatalError ) return; |
| 1005 | mainInFatalError = 1; |
| 1006 | va_start(ap, zFormat); |
| 1007 | z = vmprintf(zFormat, ap); |
| 1008 | va_end(ap); |
| 1009 | #ifdef FOSSIL_ENABLE_JSON |
| 1010 | if( g.json.isJsonMode ){ |
| 1011 | json_err( g.json.resultCode, z, 1 ); |
| 1012 | if( g.isHTTP ){ |
| 1013 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1034,10 +1071,11 @@ | |
| 1034 | char *z; |
| 1035 | va_list ap; |
| 1036 | va_start(ap, zFormat); |
| 1037 | z = vmprintf(zFormat, ap); |
| 1038 | va_end(ap); |
| 1039 | #ifdef FOSSIL_ENABLE_JSON |
| 1040 | if(g.json.isJsonMode){ |
| 1041 | json_warn( FSL_JSON_W_UNKNOWN, z ); |
| 1042 | }else |
| 1043 | #endif |
| 1044 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -22,10 +22,11 @@ | |
| 22 | #include "printf.h" |
| 23 | #if defined(_WIN32) |
| 24 | # include <io.h> |
| 25 | # include <fcntl.h> |
| 26 | #endif |
| 27 | #include <time.h> |
| 28 | |
| 29 | /* |
| 30 | ** Conversion types fall into various categories as defined by the |
| 31 | ** following enumeration. |
| 32 | */ |
| @@ -906,10 +907,43 @@ | |
| 907 | fossil_puts(blob_str(&b), 1); |
| 908 | blob_reset(&b); |
| 909 | va_end(ap); |
| 910 | } |
| 911 | |
| 912 | /* |
| 913 | ** Write a message to the error log, if the error log filename is |
| 914 | ** defined. |
| 915 | */ |
| 916 | static void fossil_errorlog(const char *zFormat, ...){ |
| 917 | struct tm *pNow; |
| 918 | time_t now; |
| 919 | FILE *out; |
| 920 | const char *z; |
| 921 | int i; |
| 922 | va_list ap; |
| 923 | static const char *azEnv[] = { "HTTP_HOST", "HTTP_USER_AGENT", |
| 924 | "PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD", |
| 925 | "REQUEST_URI", "SCRIPT_NAME" }; |
| 926 | if( g.zErrlog==0 ) return; |
| 927 | out = fopen(g.zErrlog, "a"); |
| 928 | if( out==0 ) return; |
| 929 | now = time(0); |
| 930 | pNow = gmtime(&now); |
| 931 | fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n", |
| 932 | pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday+1, |
| 933 | pNow->tm_hour, pNow->tm_min, pNow->tm_sec); |
| 934 | va_start(ap, zFormat); |
| 935 | vfprintf(out, zFormat, ap); |
| 936 | fprintf(out, "\n"); |
| 937 | va_end(ap); |
| 938 | for(i=0; i<sizeof(azEnv)/sizeof(azEnv[0]); i++){ |
| 939 | if( (z = getenv(azEnv[i]))!=0 || (z = P(azEnv[i]))!=0 ){ |
| 940 | fprintf(out, "%s=%s\n", azEnv[i], z); |
| 941 | } |
| 942 | } |
| 943 | fclose(out); |
| 944 | } |
| 945 | |
| 946 | /* |
| 947 | ** The following variable becomes true while processing a fatal error |
| 948 | ** or a panic. If additional "recursive-fatal" errors occur while |
| 949 | ** shutting down, the recursive errors are silently ignored. |
| @@ -931,10 +965,11 @@ | |
| 965 | mainInFatalError = 1; |
| 966 | db_force_rollback(); |
| 967 | va_start(ap, zFormat); |
| 968 | sqlite3_vsnprintf(sizeof(z),z,zFormat, ap); |
| 969 | va_end(ap); |
| 970 | fossil_errorlog("panic: %s", z); |
| 971 | #ifdef FOSSIL_ENABLE_JSON |
| 972 | if( g.json.isJsonMode ){ |
| 973 | json_err( 0, z, 1 ); |
| 974 | if( g.isHTTP ){ |
| 975 | rc = 0 /* avoid HTTP 500 */; |
| @@ -962,10 +997,11 @@ | |
| 997 | va_list ap; |
| 998 | mainInFatalError = 1; |
| 999 | va_start(ap, zFormat); |
| 1000 | z = vmprintf(zFormat, ap); |
| 1001 | va_end(ap); |
| 1002 | fossil_errorlog("fatal: %s", z); |
| 1003 | #ifdef FOSSIL_ENABLE_JSON |
| 1004 | if( g.json.isJsonMode ){ |
| 1005 | json_err( g.json.resultCode, z, 1 ); |
| 1006 | if( g.isHTTP ){ |
| 1007 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1004,10 +1040,11 @@ | |
| 1040 | if( mainInFatalError ) return; |
| 1041 | mainInFatalError = 1; |
| 1042 | va_start(ap, zFormat); |
| 1043 | z = vmprintf(zFormat, ap); |
| 1044 | va_end(ap); |
| 1045 | fossil_errorlog("fatal: %s", z); |
| 1046 | #ifdef FOSSIL_ENABLE_JSON |
| 1047 | if( g.json.isJsonMode ){ |
| 1048 | json_err( g.json.resultCode, z, 1 ); |
| 1049 | if( g.isHTTP ){ |
| 1050 | rc = 0 /* avoid HTTP 500 */; |
| @@ -1034,10 +1071,11 @@ | |
| 1071 | char *z; |
| 1072 | va_list ap; |
| 1073 | va_start(ap, zFormat); |
| 1074 | z = vmprintf(zFormat, ap); |
| 1075 | va_end(ap); |
| 1076 | fossil_errorlog("warning: %s", z); |
| 1077 | #ifdef FOSSIL_ENABLE_JSON |
| 1078 | if(g.json.isJsonMode){ |
| 1079 | json_warn( FSL_JSON_W_UNKNOWN, z ); |
| 1080 | }else |
| 1081 | #endif |
| 1082 |
+1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -1207,10 +1207,11 @@ | ||
| 1207 | 1207 | if( g.perm.Setup ){ |
| 1208 | 1208 | const char *zRedir = P("redirect"); |
| 1209 | 1209 | if( zRedir ) cgi_redirect(zRedir); |
| 1210 | 1210 | } |
| 1211 | 1211 | style_footer(); |
| 1212 | + if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err")); | |
| 1212 | 1213 | } |
| 1213 | 1214 | |
| 1214 | 1215 | /* |
| 1215 | 1216 | ** This page is a honeypot for spiders and bots. |
| 1216 | 1217 | ** |
| 1217 | 1218 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1207,10 +1207,11 @@ | |
| 1207 | if( g.perm.Setup ){ |
| 1208 | const char *zRedir = P("redirect"); |
| 1209 | if( zRedir ) cgi_redirect(zRedir); |
| 1210 | } |
| 1211 | style_footer(); |
| 1212 | } |
| 1213 | |
| 1214 | /* |
| 1215 | ** This page is a honeypot for spiders and bots. |
| 1216 | ** |
| 1217 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1207,10 +1207,11 @@ | |
| 1207 | if( g.perm.Setup ){ |
| 1208 | const char *zRedir = P("redirect"); |
| 1209 | if( zRedir ) cgi_redirect(zRedir); |
| 1210 | } |
| 1211 | style_footer(); |
| 1212 | if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err")); |
| 1213 | } |
| 1214 | |
| 1215 | /* |
| 1216 | ** This page is a honeypot for spiders and bots. |
| 1217 | ** |
| 1218 |
+15
| --- src/util.c | ||
| +++ src/util.c | ||
| @@ -26,10 +26,13 @@ | ||
| 26 | 26 | #ifdef _WIN32 |
| 27 | 27 | # include <windows.h> |
| 28 | 28 | #else |
| 29 | 29 | # include <sys/time.h> |
| 30 | 30 | # include <sys/resource.h> |
| 31 | +# include <unistd.h> | |
| 32 | +# include <fcntl.h> | |
| 33 | +# include <errno.h> | |
| 31 | 34 | #endif |
| 32 | 35 | |
| 33 | 36 | |
| 34 | 37 | /* |
| 35 | 38 | ** Exit. Take care to close the database first. |
| @@ -299,5 +302,17 @@ | ||
| 299 | 302 | int const rc = fossilTimerList[timerId-1].id; |
| 300 | 303 | assert(!rc || (rc == timerId)); |
| 301 | 304 | return fossilTimerList[timerId-1].id; |
| 302 | 305 | } |
| 303 | 306 | } |
| 307 | + | |
| 308 | +/* | |
| 309 | +** Return TRUE if fd is a valid open file descriptor. This only | |
| 310 | +** works on unix. The function always returns true on Windows. | |
| 311 | +*/ | |
| 312 | +int is_valid_fd(int fd){ | |
| 313 | +#ifdef _WIN32 | |
| 314 | + return 1; | |
| 315 | +#else | |
| 316 | + return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF; | |
| 317 | +#endif | |
| 318 | +} | |
| 304 | 319 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -26,10 +26,13 @@ | |
| 26 | #ifdef _WIN32 |
| 27 | # include <windows.h> |
| 28 | #else |
| 29 | # include <sys/time.h> |
| 30 | # include <sys/resource.h> |
| 31 | #endif |
| 32 | |
| 33 | |
| 34 | /* |
| 35 | ** Exit. Take care to close the database first. |
| @@ -299,5 +302,17 @@ | |
| 299 | int const rc = fossilTimerList[timerId-1].id; |
| 300 | assert(!rc || (rc == timerId)); |
| 301 | return fossilTimerList[timerId-1].id; |
| 302 | } |
| 303 | } |
| 304 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -26,10 +26,13 @@ | |
| 26 | #ifdef _WIN32 |
| 27 | # include <windows.h> |
| 28 | #else |
| 29 | # include <sys/time.h> |
| 30 | # include <sys/resource.h> |
| 31 | # include <unistd.h> |
| 32 | # include <fcntl.h> |
| 33 | # include <errno.h> |
| 34 | #endif |
| 35 | |
| 36 | |
| 37 | /* |
| 38 | ** Exit. Take care to close the database first. |
| @@ -299,5 +302,17 @@ | |
| 302 | int const rc = fossilTimerList[timerId-1].id; |
| 303 | assert(!rc || (rc == timerId)); |
| 304 | return fossilTimerList[timerId-1].id; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | /* |
| 309 | ** Return TRUE if fd is a valid open file descriptor. This only |
| 310 | ** works on unix. The function always returns true on Windows. |
| 311 | */ |
| 312 | int is_valid_fd(int fd){ |
| 313 | #ifdef _WIN32 |
| 314 | return 1; |
| 315 | #else |
| 316 | return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF; |
| 317 | #endif |
| 318 | } |
| 319 |