From 2239b9e4dd08e307ad74dc44b597fd53d2d17de8 Mon Sep 17 00:00:00 2001 From: xunchang Date: Mon, 15 Apr 2019 15:24:24 -0700 Subject: Move load & restore logs to logging.cpp We perform these steps to perserve the recovery logs when wiping /cache partition. Move them to logging.cpp to keep the actually EraseVolume function concise. Bug: 130166585 Test: unit tests pass, mount cache and check last log after cache Change-Id: Idc52833817a446f3a0148a3dd2112f911c9ef48d --- install/include/install/wipe_data.h | 2 - install/wipe_data.cpp | 75 ++------------------------- otautil/include/otautil/logging.h | 14 +++++ otautil/logging.cpp | 100 ++++++++++++++++++++++++++++++++---- recovery_main.cpp | 2 +- 5 files changed, 109 insertions(+), 84 deletions(-) diff --git a/install/include/install/wipe_data.h b/install/include/install/wipe_data.h index 06b1b95d4..b34891f3d 100644 --- a/install/include/install/wipe_data.h +++ b/install/include/install/wipe_data.h @@ -23,8 +23,6 @@ struct selabel_handle; -void SetWipeDataSehandle(selabel_handle* handle); - // Returns true on success. bool WipeCache(RecoveryUI* ui, const std::function& confirm); diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp index 7db79048a..765a8152b 100644 --- a/install/wipe_data.cpp +++ b/install/wipe_data.cpp @@ -16,14 +16,11 @@ #include "install/wipe_data.h" -#include -#include #include #include #include #include -#include #include #include @@ -39,20 +36,6 @@ constexpr const char* CACHE_ROOT = "/cache"; constexpr const char* DATA_ROOT = "/data"; constexpr const char* METADATA_ROOT = "/metadata"; -constexpr const char* CACHE_LOG_DIR = "/cache/recovery"; - -static struct selabel_handle* sehandle; - -void SetWipeDataSehandle(selabel_handle* handle) { - sehandle = handle; -} - -struct saved_log_file { - std::string name; - struct stat sb; - std::string data; -}; - static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) { bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); bool is_data = (strcmp(volume, DATA_ROOT) == 0); @@ -61,43 +44,10 @@ static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) { ui->SetProgressType(RecoveryUI::INDETERMINATE); std::vector log_files; - if (is_cache) { - // If we're reformatting /cache, we load any past logs - // (i.e. "/cache/recovery/last_*") and the current log - // ("/cache/recovery/log") into memory, so we can restore them after - // the reformat. - - ensure_path_mounted(volume); - - struct dirent* de; - std::unique_ptr d(opendir(CACHE_LOG_DIR), closedir); - if (d) { - while ((de = readdir(d.get())) != nullptr) { - if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) { - std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name); - - struct stat sb; - if (stat(path.c_str(), &sb) == 0) { - // truncate files to 512kb - if (sb.st_size > (1 << 19)) { - sb.st_size = 1 << 19; - } - - std::string data(sb.st_size, '\0'); - FILE* f = fopen(path.c_str(), "rbe"); - fread(&data[0], 1, data.size(), f); - fclose(f); - - log_files.emplace_back(saved_log_file{ path, sb, data }); - } - } - } - } else { - if (errno != ENOENT) { - PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR; - } - } + // If we're reformatting /cache, we load any past logs (i.e. "/cache/recovery/last_*") and the + // current log ("/cache/recovery/log") into memory, so we can restore them after the reformat. + log_files = ReadLogFilesToMemory(); } ui->Print("Formatting %s...\n", volume); @@ -128,24 +78,7 @@ static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) { } if (is_cache) { - // Re-create the log dir and write back the log entries. - if (ensure_path_mounted(CACHE_LOG_DIR) == 0 && - mkdir_recursively(CACHE_LOG_DIR, 0777, false, sehandle) == 0) { - for (const auto& log : log_files) { - if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid, - log.sb.st_gid)) { - PLOG(ERROR) << "Failed to write to " << log.name; - } - } - } else { - PLOG(ERROR) << "Failed to mount / create " << CACHE_LOG_DIR; - } - - // Any part of the log we'd copied to cache is now gone. - // Reset the pointer so we copy from the beginning of the temp - // log. - reset_tmplog_offset(); - copy_logs(true /* save_current_log */, true /* has_cache */, sehandle); + RestoreLogFilesAfterFormat(log_files); } return (result == 0); diff --git a/otautil/include/otautil/logging.h b/otautil/include/otautil/logging.h index c4f13292b..608349785 100644 --- a/otautil/include/otautil/logging.h +++ b/otautil/include/otautil/logging.h @@ -18,9 +18,11 @@ #define _LOGGING_H #include +#include #include #include +#include #include @@ -28,6 +30,14 @@ static constexpr int KEEP_LOG_COUNT = 10; struct selabel_handle; +struct saved_log_file { + std::string name; + struct stat sb; + std::string data; +}; + +void SetLoggingSehandle(selabel_handle* handle); + ssize_t logbasename(log_id_t id, char prio, const char* filename, const char* buf, size_t len, void* arg); @@ -48,4 +58,8 @@ void reset_tmplog_offset(); void save_kernel_log(const char* destination); +std::vector ReadLogFilesToMemory(); + +bool RestoreLogFilesAfterFormat(const std::vector& log_files); + #endif //_LOGGING_H diff --git a/otautil/logging.cpp b/otautil/logging.cpp index 7c330ac61..484f1150f 100644 --- a/otautil/logging.cpp +++ b/otautil/logging.cpp @@ -16,17 +16,22 @@ #include "otautil/logging.h" +#include +#include #include #include #include #include +#include +#include #include #include #include #include #include +#include #include /* for AID_SYSTEM */ #include /* private pmsg functions */ #include @@ -35,13 +40,21 @@ #include "otautil/paths.h" #include "otautil/roots.h" -static constexpr const char* LOG_FILE = "/cache/recovery/log"; -static constexpr const char* LAST_INSTALL_FILE = "/cache/recovery/last_install"; -static constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg"; -static constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log"; +constexpr const char* LOG_FILE = "/cache/recovery/log"; +constexpr const char* LAST_INSTALL_FILE = "/cache/recovery/last_install"; +constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg"; +constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log"; -static const std::string LAST_KMSG_FILTER = "recovery/last_kmsg"; -static const std::string LAST_LOG_FILTER = "recovery/last_log"; +constexpr const char* LAST_KMSG_FILTER = "recovery/last_kmsg"; +constexpr const char* LAST_LOG_FILTER = "recovery/last_log"; + +constexpr const char* CACHE_LOG_DIR = "/cache/recovery"; + +static struct selabel_handle* logging_sehandle; + +void SetLoggingSehandle(selabel_handle* handle) { + logging_sehandle = handle; +} // fopen(3)'s the given file, by mounting volumes and making parent dirs as necessary. Returns the // file pointer, or nullptr on error. @@ -74,8 +87,8 @@ void check_and_fclose(FILE* fp, const std::string& name) { ssize_t logbasename(log_id_t /* id */, char /* prio */, const char* filename, const char* /* buf */, size_t len, void* arg) { bool* do_rotate = static_cast(arg); - if (LAST_KMSG_FILTER.find(filename) != std::string::npos || - LAST_LOG_FILTER.find(filename) != std::string::npos) { + if (std::string(LAST_KMSG_FILTER).find(filename) != std::string::npos || + std::string(LAST_LOG_FILTER).find(filename) != std::string::npos) { *do_rotate = true; } return len; @@ -92,8 +105,8 @@ ssize_t logrotate(log_id_t id, char prio, const char* filename, const char* buf, size_t dot = name.find_last_of('.'); std::string sub = name.substr(0, dot); - if (LAST_KMSG_FILTER.find(sub) == std::string::npos && - LAST_LOG_FILTER.find(sub) == std::string::npos) { + if (std::string(LAST_KMSG_FILTER).find(sub) == std::string::npos && + std::string(LAST_LOG_FILTER).find(sub) == std::string::npos) { return __android_log_pmsg_file_write(id, prio, filename, buf, len); } @@ -243,3 +256,70 @@ void save_kernel_log(const char* destination) { buffer.resize(n); android::base::WriteStringToFile(buffer, destination); } + +std::vector ReadLogFilesToMemory() { + ensure_path_mounted("/cache"); + + struct dirent* de; + std::unique_ptr d(opendir(CACHE_LOG_DIR), closedir); + if (!d) { + if (errno != ENOENT) { + PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR; + } + return {}; + } + + std::vector log_files; + while ((de = readdir(d.get())) != nullptr) { + if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) { + std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name); + + struct stat sb; + if (stat(path.c_str(), &sb) != 0) { + PLOG(ERROR) << "Failed to stat " << path; + continue; + } + // Truncate files to 512kb + size_t read_size = std::min(sb.st_size, 1 << 19); + std::string data(read_size, '\0'); + + android::base::unique_fd log_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY))); + if (log_fd == -1 || !android::base::ReadFully(log_fd, data.data(), read_size)) { + PLOG(ERROR) << "Failed to read log file " << path; + continue; + } + + log_files.emplace_back(saved_log_file{ path, sb, data }); + } + } + + return log_files; +} + +bool RestoreLogFilesAfterFormat(const std::vector& log_files) { + // Re-create the log dir and write back the log entries. + if (ensure_path_mounted(CACHE_LOG_DIR) != 0) { + PLOG(ERROR) << "Failed to mount " << CACHE_LOG_DIR; + return false; + } + + if (mkdir_recursively(CACHE_LOG_DIR, 0777, false, logging_sehandle) != 0) { + PLOG(ERROR) << "Failed to create " << CACHE_LOG_DIR; + return false; + } + + for (const auto& log : log_files) { + if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid, + log.sb.st_gid)) { + PLOG(ERROR) << "Failed to write to " << log.name; + } + } + + // Any part of the log we'd copied to cache is now gone. + // Reset the pointer so we copy from the beginning of the temp + // log. + reset_tmplog_offset(); + copy_logs(true /* save_current_log */, true /* has_cache */, logging_sehandle); + + return true; +} diff --git a/recovery_main.cpp b/recovery_main.cpp index 8f3f2a781..5f3ab76dd 100644 --- a/recovery_main.cpp +++ b/recovery_main.cpp @@ -435,7 +435,7 @@ int main(int argc, char** argv) { ui->Print("Warning: No file_contexts\n"); } - SetWipeDataSehandle(sehandle); + SetLoggingSehandle(sehandle); std::atomic action; std::thread listener_thread(ListenRecoverySocket, ui, std::ref(action)); -- cgit v1.2.3