// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // A command-line tool that inspects the current system, displaying information // about installed products. Violations are dumped to stderr. The process // exit code is 0 if there are no violations, or 1 otherwise. #include <cstdio> #include <cstdlib> #include "base/at_exit.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/path_service.h" #include "chrome/installer/util/installation_validator.h" using installer::InstallationValidator; namespace { // A helper class that initializes logging and installs a log message handler to // direct ERROR messages to stderr. Only one instance of this class may be live // at a time. class ConsoleLogHelper { public: ConsoleLogHelper(); ~ConsoleLogHelper(); private: static base::FilePath GetLogFilePath(); static bool DumpLogMessage(int severity, const char* file, int line, size_t message_start, const std::string& str); static const wchar_t kLogFileName_[]; static FILE* const kOutputStream_; static const logging::LogSeverity kViolationSeverity_; static logging::LogMessageHandlerFunction old_message_handler_; base::FilePath log_file_path_; }; // static const wchar_t ConsoleLogHelper::kLogFileName_[] = L"validate_installation.log"; // Dump violations to stderr. // static FILE* const ConsoleLogHelper::kOutputStream_ = stderr; // InstallationValidator logs all violations at ERROR level. // static const logging::LogSeverity ConsoleLogHelper::kViolationSeverity_ = logging::LOG_ERROR; // static logging::LogMessageHandlerFunction ConsoleLogHelper::old_message_handler_ = NULL; ConsoleLogHelper::ConsoleLogHelper() : log_file_path_(GetLogFilePath()) { LOG_ASSERT(old_message_handler_ == NULL); logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_FILE; settings.log_file = log_file_path_.value().c_str(); settings.lock_log = logging::DONT_LOCK_LOG_FILE; settings.delete_old = logging::DELETE_OLD_LOG_FILE; logging::InitLogging(settings); old_message_handler_ = logging::GetLogMessageHandler(); logging::SetLogMessageHandler(&DumpLogMessage); } ConsoleLogHelper::~ConsoleLogHelper() { logging::SetLogMessageHandler(old_message_handler_); old_message_handler_ = NULL; logging::CloseLogFile(); // Delete the log file if it wasn't written to (this is expected). int64 file_size = 0; if (base::GetFileSize(log_file_path_, &file_size) && file_size == 0) base::DeleteFile(log_file_path_, false); } // Returns the path to the log file to create. The file should be empty at // process exit since we redirect log messages to stderr. // static base::FilePath ConsoleLogHelper::GetLogFilePath() { base::FilePath log_path; if (PathService::Get(base::DIR_TEMP, &log_path)) return log_path.Append(kLogFileName_); else return base::FilePath(kLogFileName_); } // A logging::LogMessageHandlerFunction that sends the body of messages logged // at the severity of validation violations to stderr. All other messages are // sent through the default logging pipeline. // static bool ConsoleLogHelper::DumpLogMessage(int severity, const char* file, int line, size_t message_start, const std::string& str) { if (severity == kViolationSeverity_) { fprintf(kOutputStream_, "%s", str.c_str() + message_start); return true; } if (old_message_handler_ != NULL) return (old_message_handler_)(severity, file, line, message_start, str); return false; } const char* LevelToString(bool system_level) { return system_level ? "System-level" : "User-level"; } std::string InstallationTypeToString( InstallationValidator::InstallationType type) { std::string result; static const struct ProductData { int bit; const char* name; } kProdBitToName[] = { { InstallationValidator::ProductBits::CHROME_SINGLE, "Chrome" }, { InstallationValidator::ProductBits::CHROME_MULTI, "Chrome (multi)" }, { InstallationValidator::ProductBits::CHROME_FRAME_SINGLE, "Chrome Frame" }, { InstallationValidator::ProductBits::CHROME_FRAME_MULTI, "Chrome Frame (multi)" }, { InstallationValidator::ProductBits::CHROME_FRAME_READY_MODE, "Ready-mode Chrome Frame" }, }; for (size_t i = 0; i < arraysize(kProdBitToName); ++i) { const ProductData& product_data = kProdBitToName[i]; if ((type & product_data.bit) != 0) { if (!result.empty()) result.append(", "); result.append(product_data.name); } } return result; } } // namespace // The main program. int wmain(int argc, wchar_t *argv[]) { int result = EXIT_SUCCESS; base::AtExitManager exit_manager; base::CommandLine::Init(0, NULL); ConsoleLogHelper log_helper; // Check user-level and system-level for products. for (int i = 0; i < 2; ++i) { const bool system_level = (i != 0); InstallationValidator::InstallationType type = InstallationValidator::NO_PRODUCTS; bool is_valid = InstallationValidator::ValidateInstallationType(system_level, &type); if (type != InstallationValidator::NO_PRODUCTS) { FILE* stream = is_valid ? stdout : stderr; fprintf(stream, "%s installations%s: %s\n", LevelToString(system_level), (is_valid ? "" : " (with errors)"), InstallationTypeToString(type).c_str()); } if (!is_valid) result = EXIT_FAILURE; } return result; }