| 11534 | #endif /* CBM_CLI_ENABLE_TEST_API */ |
| 11535 | |
| 11536 | int cbm_cmd_update(int argc, char **argv) { |
| 11537 | parse_auto_answer(argc, argv); |
| 11538 | |
| 11539 | bool dry_run = false; |
| 11540 | bool force = false; |
| 11541 | bool legacy_variant_flag = false; |
| 11542 | for (int i = 0; i < argc; i++) { |
| 11543 | if (strcmp(argv[i], "--dry-run") == 0) { |
| 11544 | dry_run = true; |
| 11545 | } else if (strcmp(argv[i], "--force") == 0) { |
| 11546 | force = true; |
| 11547 | } else if (strcmp(argv[i], "--ui") == 0 || strcmp(argv[i], "--standard") == 0) { |
| 11548 | /* v0.10.2 deleted the ui/standard chooser and, with it, these flags — |
| 11549 | * which turned `update --ui` from a working command into a hard |
| 11550 | * error for everyone who had it in a script, an alias, or muscle |
| 11551 | * memory (#1544). Removing a CHOICE is fine; removing the WORDS |
| 11552 | * people type is a break we owe them nothing for. Accept both, |
| 11553 | * ignore them, and say once why they no longer mean anything. */ |
| 11554 | legacy_variant_flag = true; |
| 11555 | } else if (strcmp(argv[i], "-y") != 0 && strcmp(argv[i], "--yes") != 0 && |
| 11556 | strcmp(argv[i], "-n") != 0 && strcmp(argv[i], "--no") != 0) { |
| 11557 | (void)fprintf(stderr, "error: unknown update option: %s\n", argv[i]); |
| 11558 | return CLI_TRUE; |
| 11559 | } |
| 11560 | } |
| 11561 | if (legacy_variant_flag) { |
| 11562 | (void)fprintf(stderr, "note: --ui/--standard are accepted but no longer do anything; since " |
| 11563 | "v0.10.0 there is one build per platform and it always includes the " |
| 11564 | "graph UI.\n"); |
| 11565 | } |
| 11566 | |
| 11567 | /* Updates run from the install script, not from this process — on every |
| 11568 | * platform. |
| 11569 | * |
| 11570 | * Windows forced the split first: a running .exe cannot replace itself, so |
| 11571 | * an in-process updater needed a second resident binary to swap the first |
| 11572 | * one out, and that launcher stub was exactly the shape Defender's ML |
| 11573 | * scores as a dropper. |
| 11574 | * |
| 11575 | * The rest followed for the same reason rather than a different one. An |
| 11576 | * in-process updater is, structurally, a downloader: it fetches a remote |
| 11577 | * archive, extracts it, marks the result executable and runs it. That is |
| 11578 | * the behaviour Microsoft's Wacatac family describes almost verbatim, and |
| 11579 | * carrying it in the product binary put download/extract/chmod/exec in |
| 11580 | * every shipped artifact for a command most users run a handful of times. |
| 11581 | * |
| 11582 | * The install script already does all of it, is idempotent -- so re-running |
| 11583 | * it IS the update -- and runs while cbm is NOT running. Print the exact |
| 11584 | * command instead of feigning self-update. */ |
| 11585 | #ifndef CBM_CLI_ENABLE_TEST_API |
| 11586 | /* A release build has nothing to do but hand off. The flags are still |
| 11587 | * parsed and validated above, so `update --dry-run` and friends keep |
| 11588 | * rejecting typos instead of silently accepting them. */ |
| 11589 | (void)dry_run; |
| 11590 | (void)force; |
| 11591 | #endif |
| 11592 | #ifdef CBM_CLI_ENABLE_TEST_API |
| 11593 | if (g_cli_activation_test_ops_set) { |
no test coverage detected