15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A command-line tool that inspects the current system, displaying information 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// about installed products. Violations are dumped to stderr. The process 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// exit code is 0 if there are no violations, or 1 otherwise. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstdio> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstdlib> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/installation_validator.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using installer::InstallationValidator; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper class that initializes logging and installs a log message handler to 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// direct ERROR messages to stderr. Only one instance of this class may be live 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at a time. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ConsoleLogHelper { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConsoleLogHelper(); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~ConsoleLogHelper(); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::FilePath GetLogFilePath(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool DumpLogMessage(int severity, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* file, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t message_start, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& str); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const wchar_t kLogFileName_[]; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static FILE* const kOutputStream_; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const logging::LogSeverity kViolationSeverity_; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static logging::LogMessageHandlerFunction old_message_handler_; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath log_file_path_; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t ConsoleLogHelper::kLogFileName_[] = L"validate_installation.log"; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dump violations to stderr. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE* const ConsoleLogHelper::kOutputStream_ = stderr; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// InstallationValidator logs all violations at ERROR level. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const logging::LogSeverity 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConsoleLogHelper::kViolationSeverity_ = logging::LOG_ERROR; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)logging::LogMessageHandlerFunction 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConsoleLogHelper::old_message_handler_ = NULL; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConsoleLogHelper::ConsoleLogHelper() : log_file_path_(GetLogFilePath()) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG_ASSERT(old_message_handler_ == NULL); 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch logging::LoggingSettings settings; 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch settings.logging_dest = logging::LOG_TO_FILE; 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch settings.log_file = log_file_path_.value().c_str(); 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch settings.lock_log = logging::DONT_LOCK_LOG_FILE; 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch settings.delete_old = logging::DELETE_OLD_LOG_FILE; 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch logging::InitLogging(settings); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_message_handler_ = logging::GetLogMessageHandler(); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging::SetLogMessageHandler(&DumpLogMessage); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConsoleLogHelper::~ConsoleLogHelper() { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging::SetLogMessageHandler(old_message_handler_); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_message_handler_ = NULL; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging::CloseLogFile(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the log file if it wasn't written to (this is expected). 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 file_size = 0; 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (base::GetFileSize(log_file_path_, &file_size) && file_size == 0) 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(log_file_path_, false); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the path to the log file to create. The file should be empty at 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// process exit since we redirect log messages to stderr. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath ConsoleLogHelper::GetLogFilePath() { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath log_path; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (PathService::Get(base::DIR_TEMP, &log_path)) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return log_path.Append(kLogFileName_); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(kLogFileName_); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A logging::LogMessageHandlerFunction that sends the body of messages logged 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at the severity of validation violations to stderr. All other messages are 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sent through the default logging pipeline. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ConsoleLogHelper::DumpLogMessage(int severity, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* file, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t message_start, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& str) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (severity == kViolationSeverity_) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(kOutputStream_, "%s", str.c_str() + message_start); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_message_handler_ != NULL) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (old_message_handler_)(severity, file, line, message_start, str); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* LevelToString(bool system_level) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return system_level ? "System-level" : "User-level"; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string InstallationTypeToString( 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::InstallationType type) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct ProductData { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bit; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } kProdBitToName[] = { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ProductBits::CHROME_SINGLE, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Chrome" 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ProductBits::CHROME_MULTI, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Chrome (multi)" 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ProductBits::CHROME_FRAME_SINGLE, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Chrome Frame" 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ProductBits::CHROME_FRAME_MULTI, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Chrome Frame (multi)" 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ProductBits::CHROME_FRAME_READY_MODE, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Ready-mode Chrome Frame" 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kProdBitToName); ++i) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ProductData& product_data = kProdBitToName[i]; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((type & product_data.bit) != 0) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result.empty()) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.append(", "); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.append(product_data.name); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The main program. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int wmain(int argc, wchar_t *argv[]) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = EXIT_SUCCESS; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AtExitManager exit_manager; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine::Init(0, NULL); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConsoleLogHelper log_helper; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check user-level and system-level for products. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 2; ++i) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool system_level = (i != 0); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::InstallationType type = 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::NO_PRODUCTS; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_valid = 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationValidator::ValidateInstallationType(system_level, &type); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != InstallationValidator::NO_PRODUCTS) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE* stream = is_valid ? stdout : stderr; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(stream, "%s installations%s: %s\n", LevelToString(system_level), 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (is_valid ? "" : " (with errors)"), 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallationTypeToString(type).c_str()); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_valid) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = EXIT_FAILURE; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 190