blob: c1fcc96558e8de3b06a982731455ae1d7873e8e6 [file] [log] [blame]
bigbiff1f9e4842020-10-31 11:33:15 -04001#include "twinstall/get_args.h"
bigbiffdf8436b2020-08-30 16:22:34 -04002
3std::string stage;
4bool has_cache = false;
5static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
6
7// command line args come from, in decreasing precedence:
8// - the actual command line
9// - the bootloader control block (one per line, after "recovery")
10// - the contents of COMMAND_FILE (one per line)
11std::vector<std::string> args::get_args(const int *argc, char*** const argv) {
12 CHECK_GT(*argc, 0);
13
14 bootloader_message boot = {};
15 std::string err;
16 if (!read_bootloader_message(&boot, &err)) {
17 LOG(ERROR) << err;
18 // If fails, leave a zeroed bootloader_message.
19 boot = {};
20 }
21 stage = std::string(boot.stage);
22
23 std::string boot_command;
24 if (boot.command[0] != 0) {
25 if (memchr(boot.command, '\0', sizeof(boot.command))) {
26 boot_command = std::string(boot.command);
27 } else {
28 boot_command = std::string(boot.command, sizeof(boot.command));
29 }
30 LOG(INFO) << "Boot command: " << boot_command;
31 printf("boot command: %s\n", boot_command.c_str());
32 }
33
34 if (boot.status[0] != 0) {
35 std::string boot_status = std::string(boot.status, sizeof(boot.status));
36 LOG(INFO) << "Boot status: " << boot_status;
37 }
38
39 std::vector<std::string> args(*argv, *argv + *argc);
40
41 // --- if arguments weren't supplied, look in the bootloader control block
42 if (args.size() == 1) {
43 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
44 std::string boot_recovery(boot.recovery);
45 std::vector<std::string> tokens = android::base::Split(boot_recovery, "\n");
46 if (!tokens.empty() && tokens[0] == "recovery") {
47 for (auto it = tokens.begin() + 1; it != tokens.end(); it++) {
48 // Skip empty and '\0'-filled tokens.
49 if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
50 }
51 LOG(INFO) << "Got " << args.size() << " arguments from boot message";
52 } else if (boot.recovery[0] != 0) {
53 LOG(ERROR) << "Bad boot message: \"" << boot_recovery << "\"";
54 }
55 }
56
57 // --- if that doesn't work, try the command file (if we have /cache).
58 if (args.size() == 1 && has_cache) {
59 std::string content;
60 if (ensure_path_mounted(COMMAND_FILE) == 0 &&
61 android::base::ReadFileToString(COMMAND_FILE, &content)) {
62 std::vector<std::string> tokens = android::base::Split(content, "\n");
63 // All the arguments in COMMAND_FILE are needed (unlike the BCB message,
64 // COMMAND_FILE doesn't use filename as the first argument).
65 for (auto it = tokens.begin(); it != tokens.end(); it++) {
66 // Skip empty and '\0'-filled tokens.
67 if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
68 }
69 LOG(INFO) << "Got " << args.size() << " arguments from " << COMMAND_FILE;
70 }
71 }
72
73 // Write the arguments (excluding the filename in args[0]) back into the
74 // bootloader control block. So the device will always boot into recovery to
75 // finish the pending work, until finish_recovery() is called.
76 std::vector<std::string> options(args.cbegin() + 1, args.cend());
77 if (!update_bootloader_message(options, &err)) {
78 LOG(ERROR) << "Failed to set BCB message: " << err;
79 }
80
81 // Finally, if no arguments were specified, check whether we should boot
82 // into fastboot or rescue mode.
83 if (args.size() == 1 && boot_command == "boot-fastboot") {
84 printf("fastbootd needed\n");
85 args.emplace_back("--fastboot");
86 } else if (args.size() == 1 && boot_command == "boot-rescue") {
87 args.emplace_back("--rescue");
88 }
89
90 return args;
91}