| 11501 | #endif /* CBM_CLI_ENABLE_TEST_API */ |
| 11502 | |
| 11503 | int cbm_cmd_update(int argc, char **argv) { |
| 11504 | parse_auto_answer(argc, argv); |
| 11505 | |
| 11506 | bool dry_run = false; |
| 11507 | bool force = false; |
| 11508 | int variant_flag = 0; /* 0 = ask, 1 = standard, 2 = ui */ |
| 11509 | for (int i = 0; i < argc; i++) { |
| 11510 | if (strcmp(argv[i], "--dry-run") == 0) { |
| 11511 | dry_run = true; |
| 11512 | } else if (strcmp(argv[i], "--standard") == 0) { |
| 11513 | variant_flag = VARIANT_A; |
| 11514 | } else if (strcmp(argv[i], "--ui") == 0) { |
| 11515 | variant_flag = VARIANT_B; |
| 11516 | } else if (strcmp(argv[i], "--force") == 0) { |
| 11517 | force = true; |
| 11518 | } else if (strcmp(argv[i], "-y") != 0 && strcmp(argv[i], "--yes") != 0 && |
| 11519 | strcmp(argv[i], "-n") != 0 && strcmp(argv[i], "--no") != 0) { |
| 11520 | (void)fprintf(stderr, "error: unknown update option: %s\n", argv[i]); |
| 11521 | return CLI_TRUE; |
| 11522 | } |
| 11523 | } |
| 11524 | |
| 11525 | /* Updates run from the install script, not from this process — on every |
| 11526 | * platform. |
| 11527 | * |
| 11528 | * Windows forced the split first: a running .exe cannot replace itself, so |
| 11529 | * an in-process updater needed a second resident binary to swap the first |
| 11530 | * one out, and that launcher stub was exactly the shape Defender's ML |
| 11531 | * scores as a dropper. |
| 11532 | * |
| 11533 | * The rest followed for the same reason rather than a different one. An |
| 11534 | * in-process updater is, structurally, a downloader: it fetches a remote |
| 11535 | * archive, extracts it, marks the result executable and runs it. That is |
| 11536 | * the behaviour Microsoft's Wacatac family describes almost verbatim, and |
| 11537 | * carrying it in the product binary put download/extract/chmod/exec in |
| 11538 | * every shipped artifact for a command most users run a handful of times. |
| 11539 | * |
| 11540 | * The install script already does all of it, is idempotent -- so re-running |
| 11541 | * it IS the update -- and runs while cbm is NOT running. Print the exact |
| 11542 | * command instead of feigning self-update. */ |
| 11543 | #ifndef CBM_CLI_ENABLE_TEST_API |
| 11544 | /* A release build has nothing to do but hand off. The flags are still |
| 11545 | * parsed and validated above, so `update --dry-run` and friends keep |
| 11546 | * rejecting typos instead of silently accepting them. */ |
| 11547 | (void)dry_run; |
| 11548 | (void)force; |
| 11549 | (void)variant_flag; |
| 11550 | #endif |
| 11551 | #ifdef CBM_CLI_ENABLE_TEST_API |
| 11552 | if (g_cli_activation_test_ops_set) { |
| 11553 | (void)fprintf(stderr, "*** cbm test seam: portable update flow engaged; the " |
| 11554 | "script-update handoff is bypassed (test builds only) ***\n"); |
| 11555 | } else |
| 11556 | #endif |
| 11557 | { |
| 11558 | char self_dir[CLI_BUF_1K] = {0}; |
| 11559 | bool have_dir = false; |
| 11560 | /* cbm_detect_self_path resolves wide on Windows (non-ASCII install |
no test coverage detected