/* * Copyright 2014 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "error_code.h" #include "edify/expr.h" #include "mounts.h" #include "updater/updater.h" #include "BurnBoot.h" #include "BurnNandBoot.h" #include "BurnSdBoot.h" static Value* executeBurnboot(const char* name, State* state, DeviceBurn burnFunc, const char* path) { ZipArchiveHandle za = static_cast(state->cookie)->package_zip; ZipString zip_string_path(path); ZipEntry entry; if (FindEntry(za, zip_string_path, &entry) != 0) { return ErrorAbort(state, kPackageExtractFileFailure, "%s(): no %s in package", name, path); } std::string buffer; buffer.resize(entry.uncompressed_length); int32_t ret = ExtractToMemory(za, &entry, reinterpret_cast(&buffer[0]), buffer.size()); if (ret != 0) { return ErrorAbort(state, kPackageExtractFileFailure, "%s: Failed to extract entry \"%s\" (%zu bytes) to memory: %s", name, path, buffer.size(), ErrorCodeString(ret)); } BufferExtractCookie* cookie = reinterpret_cast(malloc(sizeof(BufferExtractCookie))); cookie->buffer = (unsigned char *)buffer.c_str(); cookie->len = buffer.size(); burnFunc(cookie); return StringValue(""); } Value* BurnBootFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 0) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects no arg, got %zu", name, argv.size()); } const char* boot0_fex; const char* uboot_fex; DeviceBurn burnboot0_func; DeviceBurn burnuboot_func; int flash_type = getFlashType(); if (flash_type == FLASH_TYPE_UNKNOW) return StringValue(""); int secure = check_soc_is_secure(); if (secure) { boot0_fex = TOC0_FEX; uboot_fex = TOC1_FEX; } else { if (flash_type == FLASH_TYPE_NAND) { boot0_fex = BOOT0_NAND_FEX; } else { boot0_fex = BOOT0_EMMC_FEX; } uboot_fex = UBOOT_FEX; } if (flash_type == FLASH_TYPE_NAND) { burnboot0_func = burnNandBoot0; burnuboot_func = burnNandUboot; } else { burnboot0_func = burnSdBoot0; burnuboot_func = burnSdUboot; } executeBurnboot(name, state, burnboot0_func, boot0_fex); return executeBurnboot(name, state, burnuboot_func, uboot_fex); } Value* AssertBootVersionFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& ver_str = args[0]; double ota_boot_version; if (!android::base::ParseDouble(ver_str.c_str(), &ota_boot_version)) { return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse double in %s\n", name, ver_str.c_str()); } if (ota_boot_version != 0) { int rc = access("sys/nand_driver0/nand_debug", R_OK); double device_boot_version = rc == 0 ? 2.0 : 1.0; if (device_boot_version == ota_boot_version) { printf("device is boot_v%f and ota is boot_v%f\n", device_boot_version, ota_boot_version); } else { return ErrorAbort(state, kArgsParsingFailure, "%s() device is boot_v%f , but ota is boot_v%f\n", name, device_boot_version , ota_boot_version); } } return StringValue("t"); } static int exec_cmd(const char* path, char* const argv[]) { pid_t child; if ((child = vfork()) == 0) { execv(path, argv); _exit(EXIT_FAILURE); } int status; waitpid(child, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOG(ERROR) << path << " failed with status " << WEXITSTATUS(status) << " err " << errno << " " << strerror(errno); } return WEXITSTATUS(status); } Value* Resize2fsFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } std::string cmdline; if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) { bool gpt = cmdline.find("gpt=1") != std::string::npos; LOG(INFO) << name << ": Read /proc/cmdline gpt = " << gpt; if (gpt) { LOG(INFO) << name << ": Device already use gpt partitions"; return StringValue(""); } } else { LOG(WARNING) << name << ": Failed to read /proc/cmdline"; return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to read /proc/cmdline", name); } const std::string& location = args[0]; int fd = open(location.c_str(), O_RDONLY); if (fd == -1) { LOG(ERROR) << name << ": Failed to open \"" << location << "\""; return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to open \"%s\"", name, location.c_str()); } uint64_t size = 0; if (ioctl(fd, BLKGETSIZE64, &size) == -1 || size == 0) { LOG(ERROR) << name << ": Failed to get partition size"; return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to get partition size", name); } else if (size < 1024 * 1024) { LOG(ERROR) << name << ": Partition size " << size << " too small"; return ErrorAbort(state, kArgsParsingFailure, "%s() Partition size %" PRIu64 " too small", name, size); } else { LOG(INFO) << name << ": Partition size " << size; } // gpt use 20K for backup std::string block = android::base::StringPrintf("%" PRIu64 "K", size / 1024 - 20); scan_mounted_volumes(); MountedVolume* vol = find_mounted_volume_by_mount_point("/system"); if (vol == nullptr) { if (mount("/dev/block/by-name/system", "/system", "ext4", MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { LOG(WARNING) << name << ": Failed to mount /system: " << strerror(errno); } } const char* resize2fs_argv[] = { "/system/bin/resize2fs", "-f", location.c_str(), block.c_str(), nullptr }; if (access(resize2fs_argv[0], X_OK) != 0) { LOG(ERROR) << name << ": Failed to access " << resize2fs_argv[0]; return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to access %s", name, resize2fs_argv[0]); } LOG(INFO) << name << ": exec_cmd " << resize2fs_argv[0] << " " << resize2fs_argv[1] << " " << resize2fs_argv[2] << " " << resize2fs_argv[3]; int status = exec_cmd(resize2fs_argv[0], const_cast(resize2fs_argv)); if (status != 0) { LOG(ERROR) << name << ": " << resize2fs_argv[0] << " failed with status " << status << " err " << errno << " " << strerror(errno); return ErrorAbort(state, kArgsParsingFailure, "%s() %s failed with status %d %d %s", name, resize2fs_argv[0], status, errno, strerror(errno)); } if (vol == nullptr) { scan_mounted_volumes(); vol = find_mounted_volume_by_mount_point("/system"); if (vol != nullptr) { int ret = unmount_mounted_volume(vol); if (ret != 0) { LOG(WARNING) << name << ": Failed to unmount /system: " << strerror(errno); } } } return StringValue(""); } void Register_librecovery_updater_common() { RegisterFunction("burnboot", BurnBootFn); RegisterFunction("assert_boot_version", AssertBootVersionFn); RegisterFunction("resize2fs", Resize2fsFn); }