diff options
Diffstat (limited to 'updater/updater.cpp')
-rw-r--r-- | updater/updater.cpp | 368 |
1 files changed, 187 insertions, 181 deletions
diff --git a/updater/updater.cpp b/updater/updater.cpp index 452c3530f..e4b8e4641 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -14,19 +14,29 @@ * limitations under the License. */ +#include "updater/updater.h" + #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> -#include "edify/expr.h" -#include "updater.h" -#include "install.h" -#include "blockimg.h" -#include "minzip/Zip.h" -#include "minzip/SysUtil.h" +#include <string> + +#include <android-base/logging.h> +#include <android-base/strings.h> +#include <selinux/android.h> +#include <selinux/label.h> +#include <selinux/selinux.h> +#include <ziparchive/zip_archive.h> + #include "config.h" +#include "edify/expr.h" +#include "otautil/DirUtil.h" +#include "otautil/SysUtil.h" +#include "updater/blockimg.h" +#include "updater/install.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -35,7 +45,8 @@ // Where in the package we expect to find the edify script to execute. // (Note it's "updateR-script", not the older "update-script".) -#define SCRIPT_NAME "META-INF/com/google/android/updater-script" +static constexpr const char* SCRIPT_NAME = "META-INF/com/google/android/updater-script"; + #define SELINUX_CONTEXTS_ZIP "file_contexts" #define SELINUX_CONTEXTS_TMP "/tmp/file_contexts" @@ -43,189 +54,184 @@ extern bool have_eio_error; struct selabel_handle *sehandle; -int main(int argc, char** argv) { - // Various things log information to stdout or stderr more or less - // at random (though we've tried to standardize on stdout). The - // log file makes more sense if buffering is turned off so things - // appear in the right order. - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - if (argc != 4 && argc != 5) { - printf("unexpected number of arguments (%d)\n", argc); - return 1; - } - - char* version = argv[1]; - if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || - version[1] != '\0') { - // We support version 1, 2, or 3. - printf("wrong updater binary API; expected 1, 2, or 3; " - "got %s\n", - argv[1]); - return 2; - } - - // Set up the pipe for sending commands back to the parent process. - - int fd = atoi(argv[2]); - FILE* cmd_pipe = fdopen(fd, "wb"); - setlinebuf(cmd_pipe); - - // Extract the script from the package. - - const char* package_filename = argv[3]; - MemMapping map; - if (sysMapFile(package_filename, &map) != 0) { - printf("failed to map package %s\n", argv[3]); - return 3; - } - ZipArchive za; - int err; - err = mzOpenZipArchive(map.addr, map.length, &za); - if (err != 0) { - printf("failed to open package %s: %s\n", - argv[3], strerror(err)); - return 3; - } - ota_io_init(&za); - - const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); - if (script_entry == NULL) { - printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename); - return 4; - } - - char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1)); - if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { - printf("failed to read script from package\n"); - return 5; - } - script[script_entry->uncompLen] = '\0'; - - const ZipEntry* file_contexts_entry = mzFindZipEntry(&za, SELINUX_CONTEXTS_ZIP); - if (file_contexts_entry != NULL) { - int file_contexts_fd = creat(SELINUX_CONTEXTS_TMP, 0644); - if (file_contexts_fd < 0) { - fprintf(stderr, "Could not extract %s to '%s'\n", SELINUX_CONTEXTS_ZIP, SELINUX_CONTEXTS_TMP); - return 3; - } - - int ret_val = mzExtractZipEntryToFile(&za, file_contexts_entry, file_contexts_fd); - close(file_contexts_fd); - - if (!ret_val) { - fprintf(stderr, "Could not extract '%s'\n", SELINUX_CONTEXTS_ZIP); - return 3; - } - } - - // Configure edify's functions. - - RegisterBuiltins(); - RegisterInstallFunctions(); - RegisterBlockImageFunctions(); - RegisterDeviceExtensions(); - FinishRegistration(); - - // Parse the script. - - Expr* root; - int error_count = 0; - int error = parse_string(script, &root, &error_count); - if (error != 0 || error_count > 0) { - printf("%d parse errors\n", error_count); - return 6; - } - - if (access(SELINUX_CONTEXTS_TMP, R_OK) == 0) { - struct selinux_opt seopts[] = { - { SELABEL_OPT_PATH, SELINUX_CONTEXTS_TMP } - }; +static void UpdaterLogger(android::base::LogId /* id */, android::base::LogSeverity /* severity */, + const char* /* tag */, const char* /* file */, unsigned int /* line */, + const char* message) { + fprintf(stdout, "%s\n", message); +} - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); +int main(int argc, char** argv) { + // Various things log information to stdout or stderr more or less + // at random (though we've tried to standardize on stdout). The + // log file makes more sense if buffering is turned off so things + // appear in the right order. + setbuf(stdout, nullptr); + setbuf(stderr, nullptr); + + // We don't have logcat yet under recovery. Update logs will always be written to stdout + // (which is redirected to recovery.log). + android::base::InitLogging(argv, &UpdaterLogger); + + if (argc != 4 && argc != 5) { + LOG(ERROR) << "unexpected number of arguments: " << argc; + return 1; + } + + char* version = argv[1]; + if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || version[1] != '\0') { + // We support version 1, 2, or 3. + LOG(ERROR) << "wrong updater binary API; expected 1, 2, or 3; got " << argv[1]; + return 2; + } + + // Set up the pipe for sending commands back to the parent process. + + int fd = atoi(argv[2]); + FILE* cmd_pipe = fdopen(fd, "wb"); + setlinebuf(cmd_pipe); + + // Extract the script from the package. + + const char* package_filename = argv[3]; + MemMapping map; + if (sysMapFile(package_filename, &map) != 0) { + LOG(ERROR) << "failed to map package " << argv[3]; + return 3; + } + ZipArchiveHandle za; + int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za); + if (open_err != 0) { + LOG(ERROR) << "failed to open package " << argv[3] << ": " << ErrorCodeString(open_err); + CloseArchive(za); + return 3; + } + + ZipString script_name(SCRIPT_NAME); + ZipEntry script_entry; + int find_err = FindEntry(za, script_name, &script_entry); + if (find_err != 0) { + LOG(ERROR) << "failed to find " << SCRIPT_NAME << " in " << package_filename << ": " + << ErrorCodeString(find_err); + CloseArchive(za); + return 4; + } + + std::string script; + script.resize(script_entry.uncompressed_length); + int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]), + script_entry.uncompressed_length); + if (extract_err != 0) { + LOG(ERROR) << "failed to read script from package: " << ErrorCodeString(extract_err); + CloseArchive(za); + return 5; + } + + // Configure edify's functions. + + RegisterBuiltins(); + RegisterInstallFunctions(); + RegisterBlockImageFunctions(); + RegisterDeviceExtensions(); + + // Parse the script. + + std::unique_ptr<Expr> root; + int error_count = 0; + int error = parse_string(script.c_str(), &root, &error_count); + if (error != 0 || error_count > 0) { + LOG(ERROR) << error_count << " parse errors"; + CloseArchive(za); + return 6; + } + + sehandle = selinux_android_file_context_handle(); + selinux_android_set_sehandle(sehandle); + + if (!sehandle) { + fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); + } + + // Evaluate the parsed script. + + UpdaterInfo updater_info; + updater_info.cmd_pipe = cmd_pipe; + updater_info.package_zip = za; + updater_info.version = atoi(version); + updater_info.package_zip_addr = map.addr; + updater_info.package_zip_len = map.length; + + State state(script, &updater_info); + + if (argc == 5) { + if (strcmp(argv[4], "retry") == 0) { + state.is_retry = true; } else { - struct selinux_opt seopts[] = { - { SELABEL_OPT_PATH, "/file_contexts" } - }; - - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + printf("unexpected argument: %s", argv[4]); } - - if (!sehandle) { - fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); - } - - // Evaluate the parsed script. - - UpdaterInfo updater_info; - updater_info.cmd_pipe = cmd_pipe; - updater_info.package_zip = &za; - updater_info.version = atoi(version); - updater_info.package_zip_addr = map.addr; - updater_info.package_zip_len = map.length; - - State state; - state.cookie = &updater_info; - state.script = script; - state.errmsg = NULL; - - if (argc == 5) { - if (strcmp(argv[4], "retry") == 0) { - state.is_retry = true; - } else { - printf("unexpected argument: %s", argv[4]); + } + ota_io_init(za, state.is_retry); + + if (access(SELINUX_CONTEXTS_TMP, R_OK) == 0) { + struct selinux_opt seopts[] = { + { SELABEL_OPT_PATH, SELINUX_CONTEXTS_TMP } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + } else { + struct selinux_opt seopts[] = { + { SELABEL_OPT_PATH, "/file_contexts" } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + } + + std::string result; + bool status = Evaluate(&state, root, &result); + + if (have_eio_error) { + fprintf(cmd_pipe, "retry_update\n"); + } + + if (!status) { + if (state.errmsg.empty()) { + LOG(ERROR) << "script aborted (no error message)"; + fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); + } else { + LOG(ERROR) << "script aborted: " << state.errmsg; + const std::vector<std::string> lines = android::base::Split(state.errmsg, "\n"); + for (const std::string& line : lines) { + // Parse the error code in abort message. + // Example: "E30: This package is for bullhead devices." + if (!line.empty() && line[0] == 'E') { + if (sscanf(line.c_str(), "E%d: ", &state.error_code) != 1) { + LOG(ERROR) << "Failed to parse error code: [" << line << "]"; + } } + fprintf(cmd_pipe, "ui_print %s\n", line.c_str()); + } } - char* result = Evaluate(&state, root); - - if (have_eio_error) { - fprintf(cmd_pipe, "retry_update\n"); - } - - if (result == NULL) { - if (state.errmsg == NULL) { - printf("script aborted (no error message)\n"); - fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); - } else { - printf("script aborted: %s\n", state.errmsg); - char* line = strtok(state.errmsg, "\n"); - while (line) { - // Parse the error code in abort message. - // Example: "E30: This package is for bullhead devices." - if (*line == 'E') { - if (sscanf(line, "E%u: ", &state.error_code) != 1) { - printf("Failed to parse error code: [%s]\n", line); - } - } - fprintf(cmd_pipe, "ui_print %s\n", line); - line = strtok(NULL, "\n"); - } - fprintf(cmd_pipe, "ui_print\n"); - } - - if (state.error_code != kNoError) { - fprintf(cmd_pipe, "log error: %d\n", state.error_code); - // Cause code should provide additional information about the abort; - // report only when an error exists. - if (state.cause_code != kNoCause) { - fprintf(cmd_pipe, "log cause: %d\n", state.cause_code); - } - } - - free(state.errmsg); - return 7; - } else { - fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); - free(result); + if (state.error_code != kNoError) { + fprintf(cmd_pipe, "log error: %d\n", state.error_code); + // Cause code should provide additional information about the abort; + // report only when an error exists. + if (state.cause_code != kNoCause) { + fprintf(cmd_pipe, "log cause: %d\n", state.cause_code); + } } if (updater_info.package_zip) { - mzCloseZipArchive(updater_info.package_zip); + CloseArchive(updater_info.package_zip); } - sysReleaseMap(&map); - free(script); + return 7; + } else { + fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str()); + } + + if (updater_info.package_zip) { + CloseArchive(updater_info.package_zip); + } + sysReleaseMap(&map); - return 0; + return 0; } |