Fossil SCM
Add the "fossil bisect run" command.
Commit
7d4cf0ed6989c410f0d6bb8f40a6d8d50c3093f21a395a6346f6544ea775e3c0
Parent
f6b67e157e53c42…
2 files changed
+96
-2
+25
-4
+96
-2
| --- src/bisect.c | ||
| +++ src/bisect.c | ||
| @@ -373,13 +373,94 @@ | ||
| 373 | 373 | ** Reset the bisect subsystem. |
| 374 | 374 | */ |
| 375 | 375 | void bisect_reset(void){ |
| 376 | 376 | db_multi_exec( |
| 377 | 377 | "DELETE FROM vvar WHERE name IN " |
| 378 | - " ('bisect-good', 'bisect-bad', 'bisect-log')" | |
| 378 | + " ('bisect-good', 'bisect-bad', 'bisect-log', 'bisect-complete')" | |
| 379 | 379 | ); |
| 380 | 380 | } |
| 381 | + | |
| 382 | +/* | |
| 383 | +** fossil bisect run [OPTIONS] COMMAND | |
| 384 | +** | |
| 385 | +** Invoke COMMAND (with arguments) repeatedly to perform the bisect. | |
| 386 | +** Options: | |
| 387 | +** | |
| 388 | +** -i|--interactive Prompt user for decisions rather than | |
| 389 | +** using the return code from COMMAND | |
| 390 | +*/ | |
| 391 | +static void bisect_run(void){ | |
| 392 | + const char *zCmd; | |
| 393 | + int isInteractive = 0; | |
| 394 | + int i; | |
| 395 | + if( g.argc<4 ){ | |
| 396 | + fossil_fatal("Usage: fossil bisect run [OPTIONS] COMMAND\n"); | |
| 397 | + } | |
| 398 | + for(i=3; i<g.argc-1; i++){ | |
| 399 | + const char *zArg = g.argv[i]; | |
| 400 | + if( zArg[0]=='-' && zArg[1]=='-' && zArg[2]!=0 ) zArg++; | |
| 401 | + if( strcmp(zArg, "-i")==0 || strcmp(zArg, "-interactive")==0 ){ | |
| 402 | + isInteractive = 1; | |
| 403 | + continue; | |
| 404 | + } | |
| 405 | + fossil_fatal("unknown command-line option: \"%s\"\n", g.argv[i]); | |
| 406 | + } | |
| 407 | + zCmd = g.argv[i]; | |
| 408 | + if( db_int(0, "SELECT count(*) FROM vvar" | |
| 409 | + " WHERE name IN ('bisect-good','bisect-bad')")!=2 ){ | |
| 410 | + fossil_fatal("need good/bad boundaries to use \"fossil bisect run\""); | |
| 411 | + } | |
| 412 | + while( db_lget_int("bisect-complete",0)==0 ){ | |
| 413 | + int rc; | |
| 414 | + Blob cmd; | |
| 415 | + blob_init(&cmd, 0, 0); | |
| 416 | + blob_append_escaped_arg(&cmd, g.nameOfExe); | |
| 417 | + rc = fossil_unsafe_system(zCmd); | |
| 418 | + if( isInteractive ){ | |
| 419 | + Blob in; | |
| 420 | + fossil_print("test-command result: %d\n", rc); | |
| 421 | + while(1){ | |
| 422 | + int n; | |
| 423 | + char *z; | |
| 424 | + prompt_user("Enter (g)ood, (b)ad, (s)kip, (a)uto, (h)alt: ", &in); | |
| 425 | + n = blob_size(&in); | |
| 426 | + z = blob_str(&in); | |
| 427 | + if( n<1 ) continue; | |
| 428 | + if( sqlite3_strnicmp("good", z, n)==0 ){ | |
| 429 | + rc = 0; | |
| 430 | + break; | |
| 431 | + } | |
| 432 | + if( sqlite3_strnicmp("bad", z, n)==0 ){ | |
| 433 | + rc = 1; | |
| 434 | + break; | |
| 435 | + } | |
| 436 | + if( sqlite3_strnicmp("skip", z, n)==0 ){ | |
| 437 | + rc = 125; | |
| 438 | + break; | |
| 439 | + } | |
| 440 | + if( sqlite3_strnicmp("auto", z, n)==0 ){ | |
| 441 | + isInteractive = 0; | |
| 442 | + break; | |
| 443 | + } | |
| 444 | + if( sqlite3_strnicmp("halt", z, n)==0 ){ | |
| 445 | + return; | |
| 446 | + } | |
| 447 | + blob_reset(&in); | |
| 448 | + } | |
| 449 | + } | |
| 450 | + if( rc==0 ){ | |
| 451 | + blob_append(&cmd, " bisect good", -1); | |
| 452 | + }else if( rc==125 ){ | |
| 453 | + blob_append(&cmd, " bisect skip", -1); | |
| 454 | + }else{ | |
| 455 | + blob_append(&cmd, " bisect bad", -1); | |
| 456 | + } | |
| 457 | + fossil_print("%s\n", blob_str(&cmd)); | |
| 458 | + fossil_system(blob_str(&cmd)); | |
| 459 | + blob_reset(&cmd); | |
| 460 | + } | |
| 461 | +} | |
| 381 | 462 | |
| 382 | 463 | /* |
| 383 | 464 | ** COMMAND: bisect |
| 384 | 465 | ** |
| 385 | 466 | ** Usage: %fossil bisect SUBCOMMAND ... |
| @@ -417,10 +498,20 @@ | ||
| 417 | 498 | ** > fossil bisect reset |
| 418 | 499 | ** |
| 419 | 500 | ** Reinitialize a bisect session. This cancels prior bisect history |
| 420 | 501 | ** and allows a bisect session to start over from the beginning. |
| 421 | 502 | ** |
| 503 | +** > fossil bisect run [OPTIONS] COMMAND | |
| 504 | +** | |
| 505 | +** Invoke COMMAND repeatedly to run the bisect. The exit code for | |
| 506 | +** COMMAND should be 0 for "good", 125 for "skip", and any other value | |
| 507 | +** for "bad". Options: | |
| 508 | +** | |
| 509 | +** -i|--interactive Prompt the user for the good/bad/skip decision | |
| 510 | +** after each step, rather than using the exit | |
| 511 | +** code from COMMAND | |
| 512 | +** | |
| 422 | 513 | ** > fossil bisect skip ?VERSION? |
| 423 | 514 | ** |
| 424 | 515 | ** Cause VERSION (or the current checkout if VERSION is omitted) to |
| 425 | 516 | ** be ignored for the purpose of the current bisect. This might |
| 426 | 517 | ** be done, for example, because VERSION does not compile correctly |
| @@ -540,10 +631,11 @@ | ||
| 540 | 631 | int m = (int)strlen(zDisplay); |
| 541 | 632 | bisect_path(); |
| 542 | 633 | pMid = path_midpoint(); |
| 543 | 634 | if( pMid==0 ){ |
| 544 | 635 | fossil_print("bisect complete\n"); |
| 636 | + db_lset_int("bisect-complete",1); | |
| 545 | 637 | }else{ |
| 546 | 638 | int nSpan = path_length_not_hidden(); |
| 547 | 639 | int nStep = path_search_depth(); |
| 548 | 640 | g.argv[1] = "update"; |
| 549 | 641 | g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); |
| @@ -562,10 +654,12 @@ | ||
| 562 | 654 | } |
| 563 | 655 | }else if( strncmp(zCmd, "log", n)==0 ){ |
| 564 | 656 | bisect_chart(0); |
| 565 | 657 | }else if( strncmp(zCmd, "chart", n)==0 ){ |
| 566 | 658 | bisect_chart(1); |
| 659 | + }else if( strncmp(zCmd, "run", n)==0 ){ | |
| 660 | + bisect_run(); | |
| 567 | 661 | }else if( strncmp(zCmd, "options", n)==0 ){ |
| 568 | 662 | if( g.argc==3 ){ |
| 569 | 663 | unsigned int i; |
| 570 | 664 | for(i=0; i<count(aBisectOption); i++){ |
| 571 | 665 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| @@ -612,8 +706,8 @@ | ||
| 612 | 706 | ){ |
| 613 | 707 | int fAll = find_option("all", "a", 0)!=0; |
| 614 | 708 | bisect_list(!fAll); |
| 615 | 709 | }else if( !foundCmd ){ |
| 616 | 710 | usage: |
| 617 | - usage("bad|good|log|chart|next|options|reset|skip|status|ui|undo"); | |
| 711 | + usage("bad|good|log|chart|next|options|reset|run|skip|status|ui|undo"); | |
| 618 | 712 | } |
| 619 | 713 | } |
| 620 | 714 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -373,13 +373,94 @@ | |
| 373 | ** Reset the bisect subsystem. |
| 374 | */ |
| 375 | void bisect_reset(void){ |
| 376 | db_multi_exec( |
| 377 | "DELETE FROM vvar WHERE name IN " |
| 378 | " ('bisect-good', 'bisect-bad', 'bisect-log')" |
| 379 | ); |
| 380 | } |
| 381 | |
| 382 | /* |
| 383 | ** COMMAND: bisect |
| 384 | ** |
| 385 | ** Usage: %fossil bisect SUBCOMMAND ... |
| @@ -417,10 +498,20 @@ | |
| 417 | ** > fossil bisect reset |
| 418 | ** |
| 419 | ** Reinitialize a bisect session. This cancels prior bisect history |
| 420 | ** and allows a bisect session to start over from the beginning. |
| 421 | ** |
| 422 | ** > fossil bisect skip ?VERSION? |
| 423 | ** |
| 424 | ** Cause VERSION (or the current checkout if VERSION is omitted) to |
| 425 | ** be ignored for the purpose of the current bisect. This might |
| 426 | ** be done, for example, because VERSION does not compile correctly |
| @@ -540,10 +631,11 @@ | |
| 540 | int m = (int)strlen(zDisplay); |
| 541 | bisect_path(); |
| 542 | pMid = path_midpoint(); |
| 543 | if( pMid==0 ){ |
| 544 | fossil_print("bisect complete\n"); |
| 545 | }else{ |
| 546 | int nSpan = path_length_not_hidden(); |
| 547 | int nStep = path_search_depth(); |
| 548 | g.argv[1] = "update"; |
| 549 | g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); |
| @@ -562,10 +654,12 @@ | |
| 562 | } |
| 563 | }else if( strncmp(zCmd, "log", n)==0 ){ |
| 564 | bisect_chart(0); |
| 565 | }else if( strncmp(zCmd, "chart", n)==0 ){ |
| 566 | bisect_chart(1); |
| 567 | }else if( strncmp(zCmd, "options", n)==0 ){ |
| 568 | if( g.argc==3 ){ |
| 569 | unsigned int i; |
| 570 | for(i=0; i<count(aBisectOption); i++){ |
| 571 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| @@ -612,8 +706,8 @@ | |
| 612 | ){ |
| 613 | int fAll = find_option("all", "a", 0)!=0; |
| 614 | bisect_list(!fAll); |
| 615 | }else if( !foundCmd ){ |
| 616 | usage: |
| 617 | usage("bad|good|log|chart|next|options|reset|skip|status|ui|undo"); |
| 618 | } |
| 619 | } |
| 620 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -373,13 +373,94 @@ | |
| 373 | ** Reset the bisect subsystem. |
| 374 | */ |
| 375 | void bisect_reset(void){ |
| 376 | db_multi_exec( |
| 377 | "DELETE FROM vvar WHERE name IN " |
| 378 | " ('bisect-good', 'bisect-bad', 'bisect-log', 'bisect-complete')" |
| 379 | ); |
| 380 | } |
| 381 | |
| 382 | /* |
| 383 | ** fossil bisect run [OPTIONS] COMMAND |
| 384 | ** |
| 385 | ** Invoke COMMAND (with arguments) repeatedly to perform the bisect. |
| 386 | ** Options: |
| 387 | ** |
| 388 | ** -i|--interactive Prompt user for decisions rather than |
| 389 | ** using the return code from COMMAND |
| 390 | */ |
| 391 | static void bisect_run(void){ |
| 392 | const char *zCmd; |
| 393 | int isInteractive = 0; |
| 394 | int i; |
| 395 | if( g.argc<4 ){ |
| 396 | fossil_fatal("Usage: fossil bisect run [OPTIONS] COMMAND\n"); |
| 397 | } |
| 398 | for(i=3; i<g.argc-1; i++){ |
| 399 | const char *zArg = g.argv[i]; |
| 400 | if( zArg[0]=='-' && zArg[1]=='-' && zArg[2]!=0 ) zArg++; |
| 401 | if( strcmp(zArg, "-i")==0 || strcmp(zArg, "-interactive")==0 ){ |
| 402 | isInteractive = 1; |
| 403 | continue; |
| 404 | } |
| 405 | fossil_fatal("unknown command-line option: \"%s\"\n", g.argv[i]); |
| 406 | } |
| 407 | zCmd = g.argv[i]; |
| 408 | if( db_int(0, "SELECT count(*) FROM vvar" |
| 409 | " WHERE name IN ('bisect-good','bisect-bad')")!=2 ){ |
| 410 | fossil_fatal("need good/bad boundaries to use \"fossil bisect run\""); |
| 411 | } |
| 412 | while( db_lget_int("bisect-complete",0)==0 ){ |
| 413 | int rc; |
| 414 | Blob cmd; |
| 415 | blob_init(&cmd, 0, 0); |
| 416 | blob_append_escaped_arg(&cmd, g.nameOfExe); |
| 417 | rc = fossil_unsafe_system(zCmd); |
| 418 | if( isInteractive ){ |
| 419 | Blob in; |
| 420 | fossil_print("test-command result: %d\n", rc); |
| 421 | while(1){ |
| 422 | int n; |
| 423 | char *z; |
| 424 | prompt_user("Enter (g)ood, (b)ad, (s)kip, (a)uto, (h)alt: ", &in); |
| 425 | n = blob_size(&in); |
| 426 | z = blob_str(&in); |
| 427 | if( n<1 ) continue; |
| 428 | if( sqlite3_strnicmp("good", z, n)==0 ){ |
| 429 | rc = 0; |
| 430 | break; |
| 431 | } |
| 432 | if( sqlite3_strnicmp("bad", z, n)==0 ){ |
| 433 | rc = 1; |
| 434 | break; |
| 435 | } |
| 436 | if( sqlite3_strnicmp("skip", z, n)==0 ){ |
| 437 | rc = 125; |
| 438 | break; |
| 439 | } |
| 440 | if( sqlite3_strnicmp("auto", z, n)==0 ){ |
| 441 | isInteractive = 0; |
| 442 | break; |
| 443 | } |
| 444 | if( sqlite3_strnicmp("halt", z, n)==0 ){ |
| 445 | return; |
| 446 | } |
| 447 | blob_reset(&in); |
| 448 | } |
| 449 | } |
| 450 | if( rc==0 ){ |
| 451 | blob_append(&cmd, " bisect good", -1); |
| 452 | }else if( rc==125 ){ |
| 453 | blob_append(&cmd, " bisect skip", -1); |
| 454 | }else{ |
| 455 | blob_append(&cmd, " bisect bad", -1); |
| 456 | } |
| 457 | fossil_print("%s\n", blob_str(&cmd)); |
| 458 | fossil_system(blob_str(&cmd)); |
| 459 | blob_reset(&cmd); |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | /* |
| 464 | ** COMMAND: bisect |
| 465 | ** |
| 466 | ** Usage: %fossil bisect SUBCOMMAND ... |
| @@ -417,10 +498,20 @@ | |
| 498 | ** > fossil bisect reset |
| 499 | ** |
| 500 | ** Reinitialize a bisect session. This cancels prior bisect history |
| 501 | ** and allows a bisect session to start over from the beginning. |
| 502 | ** |
| 503 | ** > fossil bisect run [OPTIONS] COMMAND |
| 504 | ** |
| 505 | ** Invoke COMMAND repeatedly to run the bisect. The exit code for |
| 506 | ** COMMAND should be 0 for "good", 125 for "skip", and any other value |
| 507 | ** for "bad". Options: |
| 508 | ** |
| 509 | ** -i|--interactive Prompt the user for the good/bad/skip decision |
| 510 | ** after each step, rather than using the exit |
| 511 | ** code from COMMAND |
| 512 | ** |
| 513 | ** > fossil bisect skip ?VERSION? |
| 514 | ** |
| 515 | ** Cause VERSION (or the current checkout if VERSION is omitted) to |
| 516 | ** be ignored for the purpose of the current bisect. This might |
| 517 | ** be done, for example, because VERSION does not compile correctly |
| @@ -540,10 +631,11 @@ | |
| 631 | int m = (int)strlen(zDisplay); |
| 632 | bisect_path(); |
| 633 | pMid = path_midpoint(); |
| 634 | if( pMid==0 ){ |
| 635 | fossil_print("bisect complete\n"); |
| 636 | db_lset_int("bisect-complete",1); |
| 637 | }else{ |
| 638 | int nSpan = path_length_not_hidden(); |
| 639 | int nStep = path_search_depth(); |
| 640 | g.argv[1] = "update"; |
| 641 | g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); |
| @@ -562,10 +654,12 @@ | |
| 654 | } |
| 655 | }else if( strncmp(zCmd, "log", n)==0 ){ |
| 656 | bisect_chart(0); |
| 657 | }else if( strncmp(zCmd, "chart", n)==0 ){ |
| 658 | bisect_chart(1); |
| 659 | }else if( strncmp(zCmd, "run", n)==0 ){ |
| 660 | bisect_run(); |
| 661 | }else if( strncmp(zCmd, "options", n)==0 ){ |
| 662 | if( g.argc==3 ){ |
| 663 | unsigned int i; |
| 664 | for(i=0; i<count(aBisectOption); i++){ |
| 665 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| @@ -612,8 +706,8 @@ | |
| 706 | ){ |
| 707 | int fAll = find_option("all", "a", 0)!=0; |
| 708 | bisect_list(!fAll); |
| 709 | }else if( !foundCmd ){ |
| 710 | usage: |
| 711 | usage("bad|good|log|chart|next|options|reset|run|skip|status|ui|undo"); |
| 712 | } |
| 713 | } |
| 714 |
+25
-4
| --- src/util.c | ||
| +++ src/util.c | ||
| @@ -164,13 +164,21 @@ | ||
| 164 | 164 | } |
| 165 | 165 | return zStart; |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | 168 | /* |
| 169 | -** If this local variable is set, fossil_assert_safe_command_string() | |
| 170 | -** returns false on an unsafe command-string rather than abort. Set | |
| 171 | -** this variable for testing. | |
| 169 | +** This local variable determines the behavior of | |
| 170 | +** fossil_assert_safe_command_string(): | |
| 171 | +** | |
| 172 | +** 0 (default) fossil_panic() on an unsafe command string | |
| 173 | +** | |
| 174 | +** 1 Print an error but continue process. Used for | |
| 175 | +** testing of fossil_assert_safe_command_string(). | |
| 176 | +** | |
| 177 | +** 2 No-op. Used to allow any arbitrary command string | |
| 178 | +** through fossil_system(), such as when invoking | |
| 179 | +** COMMAND in "fossil bisect run COMMAND". | |
| 172 | 180 | */ |
| 173 | 181 | static int safeCmdStrTest = 0; |
| 174 | 182 | |
| 175 | 183 | /* |
| 176 | 184 | ** Check the input string to ensure that it is safe to pass into system(). |
| @@ -266,15 +274,16 @@ | ||
| 266 | 274 | } |
| 267 | 275 | } |
| 268 | 276 | } |
| 269 | 277 | if( inQuote ) unsafe = i; |
| 270 | 278 | #endif |
| 271 | - if( unsafe ){ | |
| 279 | + if( unsafe && safeCmdStrTest<2 ){ | |
| 272 | 280 | char *zMsg = mprintf("Unsafe command string: %s\n%*shere ----^", |
| 273 | 281 | z, unsafe+13, ""); |
| 274 | 282 | if( safeCmdStrTest ){ |
| 275 | 283 | fossil_print("%z\n", zMsg); |
| 284 | + fossil_free(zMsg); | |
| 276 | 285 | }else{ |
| 277 | 286 | fossil_panic("%s", zMsg); |
| 278 | 287 | } |
| 279 | 288 | } |
| 280 | 289 | } |
| @@ -315,10 +324,22 @@ | ||
| 315 | 324 | rc = system(zOrigCmd); |
| 316 | 325 | fossil_limit_memory(1); |
| 317 | 326 | #endif |
| 318 | 327 | return rc; |
| 319 | 328 | } |
| 329 | + | |
| 330 | +/* | |
| 331 | +** Like "fossil_system()" but does not check the command-string for | |
| 332 | +** potential security problems. | |
| 333 | +*/ | |
| 334 | +int fossil_unsafe_system(const char *zOrigCmd){ | |
| 335 | + int rc; | |
| 336 | + safeCmdStrTest = 2; | |
| 337 | + rc = fossil_system(zOrigCmd); | |
| 338 | + safeCmdStrTest = 0; | |
| 339 | + return rc; | |
| 340 | +} | |
| 320 | 341 | |
| 321 | 342 | /* |
| 322 | 343 | ** COMMAND: test-fossil-system |
| 323 | 344 | ** |
| 324 | 345 | ** Read lines of input and send them to fossil_system() for evaluation. |
| 325 | 346 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -164,13 +164,21 @@ | |
| 164 | } |
| 165 | return zStart; |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | ** If this local variable is set, fossil_assert_safe_command_string() |
| 170 | ** returns false on an unsafe command-string rather than abort. Set |
| 171 | ** this variable for testing. |
| 172 | */ |
| 173 | static int safeCmdStrTest = 0; |
| 174 | |
| 175 | /* |
| 176 | ** Check the input string to ensure that it is safe to pass into system(). |
| @@ -266,15 +274,16 @@ | |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | if( inQuote ) unsafe = i; |
| 270 | #endif |
| 271 | if( unsafe ){ |
| 272 | char *zMsg = mprintf("Unsafe command string: %s\n%*shere ----^", |
| 273 | z, unsafe+13, ""); |
| 274 | if( safeCmdStrTest ){ |
| 275 | fossil_print("%z\n", zMsg); |
| 276 | }else{ |
| 277 | fossil_panic("%s", zMsg); |
| 278 | } |
| 279 | } |
| 280 | } |
| @@ -315,10 +324,22 @@ | |
| 315 | rc = system(zOrigCmd); |
| 316 | fossil_limit_memory(1); |
| 317 | #endif |
| 318 | return rc; |
| 319 | } |
| 320 | |
| 321 | /* |
| 322 | ** COMMAND: test-fossil-system |
| 323 | ** |
| 324 | ** Read lines of input and send them to fossil_system() for evaluation. |
| 325 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -164,13 +164,21 @@ | |
| 164 | } |
| 165 | return zStart; |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | ** This local variable determines the behavior of |
| 170 | ** fossil_assert_safe_command_string(): |
| 171 | ** |
| 172 | ** 0 (default) fossil_panic() on an unsafe command string |
| 173 | ** |
| 174 | ** 1 Print an error but continue process. Used for |
| 175 | ** testing of fossil_assert_safe_command_string(). |
| 176 | ** |
| 177 | ** 2 No-op. Used to allow any arbitrary command string |
| 178 | ** through fossil_system(), such as when invoking |
| 179 | ** COMMAND in "fossil bisect run COMMAND". |
| 180 | */ |
| 181 | static int safeCmdStrTest = 0; |
| 182 | |
| 183 | /* |
| 184 | ** Check the input string to ensure that it is safe to pass into system(). |
| @@ -266,15 +274,16 @@ | |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | if( inQuote ) unsafe = i; |
| 278 | #endif |
| 279 | if( unsafe && safeCmdStrTest<2 ){ |
| 280 | char *zMsg = mprintf("Unsafe command string: %s\n%*shere ----^", |
| 281 | z, unsafe+13, ""); |
| 282 | if( safeCmdStrTest ){ |
| 283 | fossil_print("%z\n", zMsg); |
| 284 | fossil_free(zMsg); |
| 285 | }else{ |
| 286 | fossil_panic("%s", zMsg); |
| 287 | } |
| 288 | } |
| 289 | } |
| @@ -315,10 +324,22 @@ | |
| 324 | rc = system(zOrigCmd); |
| 325 | fossil_limit_memory(1); |
| 326 | #endif |
| 327 | return rc; |
| 328 | } |
| 329 | |
| 330 | /* |
| 331 | ** Like "fossil_system()" but does not check the command-string for |
| 332 | ** potential security problems. |
| 333 | */ |
| 334 | int fossil_unsafe_system(const char *zOrigCmd){ |
| 335 | int rc; |
| 336 | safeCmdStrTest = 2; |
| 337 | rc = fossil_system(zOrigCmd); |
| 338 | safeCmdStrTest = 0; |
| 339 | return rc; |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | ** COMMAND: test-fossil-system |
| 344 | ** |
| 345 | ** Read lines of input and send them to fossil_system() for evaluation. |
| 346 |