From de0bc06856bb4d1c36a62c84bc4f8e245138c090 Mon Sep 17 00:00:00 2001 From: Shawn Hoffman Date: Thu, 9 Mar 2023 18:18:09 -0800 Subject: [PATCH] updater: flush log after each write --- Source/Core/MacUpdater/MacUI.mm | 14 ++- Source/Core/UpdaterCommon/Platform.h | 2 +- Source/Core/UpdaterCommon/UpdaterCommon.cpp | 110 +++++++++++--------- Source/Core/UpdaterCommon/UpdaterCommon.h | 1 + Source/Core/WinUpdater/Platform.cpp | 10 +- 5 files changed, 72 insertions(+), 65 deletions(-) diff --git a/Source/Core/MacUpdater/MacUI.mm b/Source/Core/MacUpdater/MacUI.mm index 388f5a1da4..f60199034a 100644 --- a/Source/Core/MacUpdater/MacUI.mm +++ b/Source/Core/MacUpdater/MacUI.mm @@ -140,8 +140,7 @@ void UI::Init() } bool Platform::VersionCheck(const std::vector& to_update, - const std::string& install_base_path, const std::string& temp_dir, - FILE* log_fp) + const std::string& install_base_path, const std::string& temp_dir) { const auto op_it = std::find_if(to_update.cbegin(), to_update.cend(), [&](const auto& op) { return op.filename == "Dolphin.app/Contents/Info.plist"; @@ -155,7 +154,7 @@ bool Platform::VersionCheck(const std::vector& to_update, NSData* data = [NSData dataWithContentsOfFile:[NSString stringWithCString:plist_path.c_str()]]; if (!data) { - fprintf(log_fp, "Failed to read %s, skipping platform version check.\n", plist_path.c_str()); + LogToFile("Failed to read %s, skipping platform version check.\n", plist_path.c_str()); return true; } @@ -167,13 +166,13 @@ bool Platform::VersionCheck(const std::vector& to_update, error:&error]; if (error) { - fprintf(log_fp, "Failed to parse %s, skipping platform version check.\n", plist_path.c_str()); + LogToFile("Failed to parse %s, skipping platform version check.\n", plist_path.c_str()); return true; } NSString* min_version_str = info_dict[@"LSMinimumSystemVersion"]; if (!min_version_str) { - fprintf(log_fp, "LSMinimumSystemVersion key missing, skipping platform version check.\n"); + LogToFile("LSMinimumSystemVersion key missing, skipping platform version check.\n"); return true; } @@ -181,9 +180,8 @@ bool Platform::VersionCheck(const std::vector& to_update, NSOperatingSystemVersion next_version{ [components[0] integerValue], [components[1] integerValue], [components[2] integerValue]}; - fprintf(log_fp, "Platform version check: next_version=%ld.%ld.%ld\n", - (long)next_version.majorVersion, (long)next_version.minorVersion, - (long)next_version.patchVersion); + LogToFile("Platform version check: next_version=%ld.%ld.%ld\n", (long)next_version.majorVersion, + (long)next_version.minorVersion, (long)next_version.patchVersion); if (![[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:next_version]) { diff --git a/Source/Core/UpdaterCommon/Platform.h b/Source/Core/UpdaterCommon/Platform.h index 546ceff98b..e2580ec694 100644 --- a/Source/Core/UpdaterCommon/Platform.h +++ b/Source/Core/UpdaterCommon/Platform.h @@ -15,5 +15,5 @@ namespace Platform { bool VersionCheck(const std::vector& to_update, - const std::string& install_base_path, const std::string& temp_dir, FILE* log_fp); + const std::string& install_base_path, const std::string& temp_dir); } // namespace Platform diff --git a/Source/Core/UpdaterCommon/UpdaterCommon.cpp b/Source/Core/UpdaterCommon/UpdaterCommon.cpp index f16354421d..0d50603139 100644 --- a/Source/Core/UpdaterCommon/UpdaterCommon.cpp +++ b/Source/Core/UpdaterCommon/UpdaterCommon.cpp @@ -34,14 +34,25 @@ // Refer to docs/autoupdate_overview.md for a detailed overview of the autoupdate process -// Where to log updater output. -static FILE* log_fp = stderr; - // Public key used to verify update manifests. const std::array UPDATE_PUB_KEY = { 0x2a, 0xb3, 0xd1, 0xdc, 0x6e, 0xf5, 0x07, 0xf6, 0xa0, 0x6c, 0x7c, 0x54, 0xdf, 0x54, 0xf4, 0x42, 0x80, 0xa6, 0x28, 0x8b, 0x6d, 0x70, 0x14, 0xb5, 0x4c, 0x34, 0x95, 0x20, 0x4d, 0xd4, 0xd3, 0x5d}; +// Where to log updater output. +static FILE* log_fp = stderr; + +void LogToFile(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + vfprintf(log_fp, fmt, args); + fflush(log_fp); + + va_end(args); +} + bool ProgressCallback(double total, double now, double, double) { UI::SetCurrentProgress(static_cast(now), static_cast(total)); @@ -120,7 +131,7 @@ std::optional GzipInflate(const std::string& data) if (ret != Z_STREAM_END) { - fprintf(log_fp, "Could not read the data as gzip: error %d.\n", ret); + LogToFile("Could not read the data as gzip: error %d.\n", ret); return {}; } @@ -148,7 +159,7 @@ bool VerifySignature(const std::string& data, const std::string& b64_signature) b64_signature.size()) || sig_size != sizeof(signature)) { - fprintf(log_fp, "Invalid base64: %s\n", b64_signature.c_str()); + LogToFile("Invalid base64: %s\n", b64_signature.c_str()); return false; } @@ -166,22 +177,22 @@ void TodoList::Log() const { if (to_update.size()) { - fprintf(log_fp, "Updating:\n"); + LogToFile("Updating:\n"); for (const auto& op : to_update) { std::string old_desc = op.old_hash ? HexEncode(op.old_hash->data(), op.old_hash->size()) : "(new)"; - fprintf(log_fp, " - %s: %s -> %s\n", op.filename.c_str(), old_desc.c_str(), - HexEncode(op.new_hash.data(), op.new_hash.size()).c_str()); + LogToFile(" - %s: %s -> %s\n", op.filename.c_str(), old_desc.c_str(), + HexEncode(op.new_hash.data(), op.new_hash.size()).c_str()); } } if (to_delete.size()) { - fprintf(log_fp, "Deleting:\n"); + LogToFile("Deleting:\n"); for (const auto& op : to_delete) { - fprintf(log_fp, " - %s (%s)\n", op.filename.c_str(), - HexEncode(op.old_hash.data(), op.old_hash.size()).c_str()); + LogToFile(" - %s (%s)\n", op.filename.c_str(), + HexEncode(op.old_hash.data(), op.old_hash.size()).c_str()); } } } @@ -215,7 +226,7 @@ bool DownloadContent(const std::vector& to_download, content_store_path.insert(2, "/"); std::string url = content_base_url + content_store_path; - fprintf(log_fp, "Downloading %s ...\n", url.c_str()); + LogToFile("Downloading %s ...\n", url.c_str()); auto resp = req.Get(url); if (!resp) @@ -234,14 +245,14 @@ bool DownloadContent(const std::vector& to_download, Manifest::Hash contents_hash = ComputeHash(decompressed); if (contents_hash != download.hash) { - fprintf(log_fp, "Wrong hash on downloaded content %s.\n", url.c_str()); + LogToFile("Wrong hash on downloaded content %s.\n", url.c_str()); return false; } const std::string out = temp_path + DIR_SEP + hash_filename; if (!File::WriteStringToFile(out, decompressed)) { - fprintf(log_fp, "Could not write cache file %s.\n", out.c_str()); + LogToFile("Could not write cache file %s.\n", out.c_str()); return false; } } @@ -252,7 +263,7 @@ bool PlatformVersionCheck(const std::vector& to_update, const std::string& install_base_path, const std::string& temp_dir) { UI::SetDescription("Checking platform..."); - return Platform::VersionCheck(to_update, install_base_path, temp_dir, log_fp); + return Platform::VersionCheck(to_update, install_base_path, temp_dir); } TodoList ComputeActionsToDo(Manifest this_manifest, Manifest next_manifest) @@ -310,10 +321,10 @@ void CleanUpTempDir(const std::string& temp_dir, const TodoList& todo) bool BackupFile(const std::string& path) { std::string backup_path = path + ".bak"; - fprintf(log_fp, "Backing up existing %s to .bak.\n", path.c_str()); + LogToFile("Backing up existing %s to .bak.\n", path.c_str()); if (!File::Rename(path, backup_path)) { - fprintf(log_fp, "Cound not rename %s to %s for backup.\n", path.c_str(), backup_path.c_str()); + LogToFile("Cound not rename %s to %s for backup.\n", path.c_str(), backup_path.c_str()); return false; } return true; @@ -328,7 +339,7 @@ bool DeleteObsoleteFiles(const std::vector& to_delete, if (!File::Exists(path)) { - fprintf(log_fp, "File %s is already missing.\n", op.filename.c_str()); + LogToFile("File %s is already missing.\n", op.filename.c_str()); continue; } else @@ -336,7 +347,7 @@ bool DeleteObsoleteFiles(const std::vector& to_delete, std::string contents; if (!File::ReadFileToString(path, contents)) { - fprintf(log_fp, "Could not read file planned for deletion: %s.\n", op.filename.c_str()); + LogToFile("Could not read file planned for deletion: %s.\n", op.filename.c_str()); return false; } Manifest::Hash contents_hash = ComputeHash(contents); @@ -365,7 +376,7 @@ bool UpdateFiles(const std::vector& to_update, std::string path = install_base_path + DIR_SEP + op.filename; if (!File::CreateFullPath(path)) { - fprintf(log_fp, "Could not create directory structure for %s.\n", op.filename.c_str()); + LogToFile("Could not create directory structure for %s.\n", op.filename.c_str()); return false; } @@ -385,7 +396,7 @@ bool UpdateFiles(const std::vector& to_update, if (S_ISLNK(file_stats.st_mode)) { - fprintf(log_fp, "%s is symlink, skipping\n", path.c_str()); + LogToFile("%s is symlink, skipping\n", path.c_str()); continue; } @@ -408,13 +419,13 @@ bool UpdateFiles(const std::vector& to_update, std::string contents; if (!File::ReadFileToString(path, contents)) { - fprintf(log_fp, "Could not read existing file %s.\n", op.filename.c_str()); + LogToFile("Could not read existing file %s.\n", op.filename.c_str()); return false; } Manifest::Hash contents_hash = ComputeHash(contents); if (contents_hash == op.new_hash) { - fprintf(log_fp, "File %s was already up to date. Partial update?\n", op.filename.c_str()); + LogToFile("File %s was already up to date. Partial update?\n", op.filename.c_str()); continue; } else if (!op.old_hash || contents_hash != *op.old_hash || is_self) @@ -426,8 +437,8 @@ bool UpdateFiles(const std::vector& to_update, // Now we can safely move the new contents to the location. std::string content_filename = HexEncode(op.new_hash.data(), op.new_hash.size()); - fprintf(log_fp, "Updating file %s from content %s...\n", op.filename.c_str(), - content_filename.c_str()); + LogToFile("Updating file %s from content %s...\n", op.filename.c_str(), + content_filename.c_str()); #ifdef __APPLE__ // macOS caches the code signature of Mach-O executables when they're first loaded. // Unfortunately, there is a quirk in the kernel with how it handles the cache: if the file is @@ -440,8 +451,7 @@ bool UpdateFiles(const std::vector& to_update, const std::string temporary_file = temp_path + DIR_SEP + "temporary_file"; if (!File::CopyRegularFile(temp_path + DIR_SEP + content_filename, temporary_file)) { - fprintf(log_fp, "Could not copy %s to %s.\n", content_filename.c_str(), - temporary_file.c_str()); + LogToFile("Could not copy %s to %s.\n", content_filename.c_str(), temporary_file.c_str()); return false; } @@ -450,7 +460,7 @@ bool UpdateFiles(const std::vector& to_update, if (!File::CopyRegularFile(temp_path + DIR_SEP + content_filename, path)) #endif { - fprintf(log_fp, "Could not update file %s.\n", op.filename.c_str()); + LogToFile("Could not update file %s.\n", op.filename.c_str()); return false; } @@ -465,32 +475,32 @@ bool UpdateFiles(const std::vector& to_update, bool PerformUpdate(const TodoList& todo, const std::string& install_base_path, const std::string& content_base_url, const std::string& temp_path) { - fprintf(log_fp, "Starting download step...\n"); + LogToFile("Starting download step...\n"); if (!DownloadContent(todo.to_download, content_base_url, temp_path)) return false; - fprintf(log_fp, "Download step completed.\n"); + LogToFile("Download step completed.\n"); - fprintf(log_fp, "Starting platform version check step...\n"); + LogToFile("Starting platform version check step...\n"); if (!PlatformVersionCheck(todo.to_update, install_base_path, temp_path)) return false; - fprintf(log_fp, "Platform version check step completed.\n"); + LogToFile("Platform version check step completed.\n"); - fprintf(log_fp, "Starting update step...\n"); + LogToFile("Starting update step...\n"); if (!UpdateFiles(todo.to_update, install_base_path, temp_path)) return false; - fprintf(log_fp, "Update step completed.\n"); + LogToFile("Update step completed.\n"); - fprintf(log_fp, "Starting deletion step...\n"); + LogToFile("Starting deletion step...\n"); if (!DeleteObsoleteFiles(todo.to_delete, install_base_path)) return false; - fprintf(log_fp, "Deletion step completed.\n"); + LogToFile("Deletion step completed.\n"); return true; } void FatalError(const std::string& message) { - fprintf(log_fp, "%s\n", message.c_str()); + LogToFile("%s\n", message.c_str()); UI::SetVisible(true); UI::Error(message); @@ -506,13 +516,13 @@ std::optional ParseManifest(const std::string& manifest) size_t filename_end_pos = manifest.find('\t', pos); if (filename_end_pos == std::string::npos) { - fprintf(log_fp, "Manifest entry %zu: could not find filename end.\n", parsed.entries.size()); + LogToFile("Manifest entry %zu: could not find filename end.\n", parsed.entries.size()); return {}; } size_t hash_end_pos = manifest.find('\n', filename_end_pos); if (hash_end_pos == std::string::npos) { - fprintf(log_fp, "Manifest entry %zu: could not find hash end.\n", parsed.entries.size()); + LogToFile("Manifest entry %zu: could not find hash end.\n", parsed.entries.size()); return {}; } @@ -520,16 +530,14 @@ std::optional ParseManifest(const std::string& manifest) std::string hash = manifest.substr(filename_end_pos + 1, hash_end_pos - filename_end_pos - 1); if (hash.size() != 32) { - fprintf(log_fp, "Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(), - hash.c_str()); + LogToFile("Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(), hash.c_str()); return {}; } Manifest::Hash decoded_hash; if (!HexDecode(hash, decoded_hash.data(), decoded_hash.size())) { - fprintf(log_fp, "Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(), - hash.c_str()); + LogToFile("Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(), hash.c_str()); return {}; } @@ -548,7 +556,7 @@ std::optional FetchAndParseManifest(const std::string& url) Common::HttpRequest::Response resp = http.Get(url); if (!resp) { - fprintf(log_fp, "Manifest download failed.\n"); + LogToFile("Manifest download failed.\n"); return {}; } @@ -562,7 +570,7 @@ std::optional FetchAndParseManifest(const std::string& url) size_t boundary = decompressed.rfind("\n\n"); if (boundary == std::string::npos) { - fprintf(log_fp, "No signature was found in manifest.\n"); + LogToFile("No signature was found in manifest.\n"); return {}; } @@ -581,7 +589,7 @@ std::optional FetchAndParseManifest(const std::string& url) } if (!found_valid_signature) { - fprintf(log_fp, "Could not verify signature of the manifest.\n"); + LogToFile("Could not verify signature of the manifest.\n"); return {}; } @@ -692,9 +700,9 @@ bool RunUpdater(std::vector args) atexit(FlushLog); } - fprintf(log_fp, "Updating from: %s\n", opts.this_manifest_url.c_str()); - fprintf(log_fp, "Updating to: %s\n", opts.next_manifest_url.c_str()); - fprintf(log_fp, "Install path: %s\n", opts.install_base_path.c_str()); + LogToFile("Updating from: %s\n", opts.this_manifest_url.c_str()); + LogToFile("Updating to: %s\n", opts.next_manifest_url.c_str()); + LogToFile("Install path: %s\n", opts.install_base_path.c_str()); if (!File::IsDirectory(opts.install_base_path)) { @@ -704,13 +712,13 @@ bool RunUpdater(std::vector args) if (opts.parent_pid) { - fprintf(log_fp, "Waiting for parent PID %d to complete...\n", *opts.parent_pid); + LogToFile("Waiting for parent PID %d to complete...\n", *opts.parent_pid); auto pid = opts.parent_pid.value(); UI::WaitForPID(static_cast(pid)); - fprintf(log_fp, "Completed! Proceeding with update.\n"); + LogToFile("Completed! Proceeding with update.\n"); } UI::SetVisible(true); diff --git a/Source/Core/UpdaterCommon/UpdaterCommon.h b/Source/Core/UpdaterCommon/UpdaterCommon.h index 679a339f90..a636a0c323 100644 --- a/Source/Core/UpdaterCommon/UpdaterCommon.h +++ b/Source/Core/UpdaterCommon/UpdaterCommon.h @@ -49,6 +49,7 @@ struct TodoList void Log() const; }; +void LogToFile(const char* fmt, ...); std::string HexEncode(const u8* buffer, size_t size); Manifest::Hash ComputeHash(const std::string& contents); bool RunUpdater(std::vector args); diff --git a/Source/Core/WinUpdater/Platform.cpp b/Source/Core/WinUpdater/Platform.cpp index f60a6621c0..1cfa6b4327 100644 --- a/Source/Core/WinUpdater/Platform.cpp +++ b/Source/Core/WinUpdater/Platform.cpp @@ -241,7 +241,7 @@ static VersionCheckResult OSVersionCheck(const BuildInfo& build_info) std::optional InitBuildInfos(const std::vector& to_update, const std::string& install_base_path, - const std::string& temp_dir, FILE* log_fp) + const std::string& temp_dir) { const auto op_it = std::find_if(to_update.cbegin(), to_update.cend(), [&](const auto& op) { return op.filename == "build_info.txt"; }); @@ -255,7 +255,7 @@ std::optional InitBuildInfos(const std::vector& if (!File::ReadFileToString(build_info_path, build_info_content) || op.new_hash != ComputeHash(build_info_content)) { - fprintf(log_fp, "Failed to read %s\n.", build_info_path.c_str()); + LogToFile("Failed to read %s\n.", build_info_path.c_str()); return {}; } BuildInfos build_infos; @@ -266,7 +266,7 @@ std::optional InitBuildInfos(const std::vector& if (File::ReadFileToString(build_info_path, build_info_content)) { if (op.old_hash != ComputeHash(build_info_content)) - fprintf(log_fp, "Using modified existing BuildInfo %s.\n", build_info_path.c_str()); + LogToFile("Using modified existing BuildInfo %s.\n", build_info_path.c_str()); build_infos.current = Platform::BuildInfo(build_info_content); } return build_infos; @@ -305,9 +305,9 @@ bool CheckBuildInfo(const BuildInfos& build_infos) } bool VersionCheck(const std::vector& to_update, - const std::string& install_base_path, const std::string& temp_dir, FILE* log_fp) + const std::string& install_base_path, const std::string& temp_dir) { - auto build_infos = InitBuildInfos(to_update, install_base_path, temp_dir, log_fp); + auto build_infos = InitBuildInfos(to_update, install_base_path, temp_dir); // If there's no build info, it means the check should be skipped. if (!build_infos.has_value()) {