1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // A command-line tool that inspects the current system, displaying information 6 // about installed products. Violations are dumped to stderr. The process 7 // exit code is 0 if there are no violations, or 1 otherwise. 8 9 #include <cstdio> 10 #include <cstdlib> 11 12 #include "base/at_exit.h" 13 #include "base/command_line.h" 14 #include "base/file_util.h" 15 #include "base/logging.h" 16 #include "base/path_service.h" 17 #include "chrome/installer/util/installation_validator.h" 18 19 using installer::InstallationValidator; 20 21 namespace { 22 23 // A helper class that initializes logging and installs a log message handler to 24 // direct ERROR messages to stderr. Only one instance of this class may be live 25 // at a time. 26 class ConsoleLogHelper { 27 public: 28 ConsoleLogHelper(); 29 ~ConsoleLogHelper(); 30 31 private: 32 static base::FilePath GetLogFilePath(); 33 static bool DumpLogMessage(int severity, 34 const char* file, 35 int line, 36 size_t message_start, 37 const std::string& str); 38 39 static const wchar_t kLogFileName_[]; 40 static FILE* const kOutputStream_; 41 static const logging::LogSeverity kViolationSeverity_; 42 static logging::LogMessageHandlerFunction old_message_handler_; 43 base::FilePath log_file_path_; 44 }; 45 46 // static 47 const wchar_t ConsoleLogHelper::kLogFileName_[] = L"validate_installation.log"; 48 49 // Dump violations to stderr. 50 // static 51 FILE* const ConsoleLogHelper::kOutputStream_ = stderr; 52 53 // InstallationValidator logs all violations at ERROR level. 54 // static 55 const logging::LogSeverity 56 ConsoleLogHelper::kViolationSeverity_ = logging::LOG_ERROR; 57 58 // static 59 logging::LogMessageHandlerFunction 60 ConsoleLogHelper::old_message_handler_ = NULL; 61 62 ConsoleLogHelper::ConsoleLogHelper() : log_file_path_(GetLogFilePath()) { 63 LOG_ASSERT(old_message_handler_ == NULL); 64 logging::LoggingSettings settings; 65 settings.logging_dest = logging::LOG_TO_FILE; 66 settings.log_file = log_file_path_.value().c_str(); 67 settings.lock_log = logging::DONT_LOCK_LOG_FILE; 68 settings.delete_old = logging::DELETE_OLD_LOG_FILE; 69 logging::InitLogging(settings); 70 71 old_message_handler_ = logging::GetLogMessageHandler(); 72 logging::SetLogMessageHandler(&DumpLogMessage); 73 } 74 75 ConsoleLogHelper::~ConsoleLogHelper() { 76 logging::SetLogMessageHandler(old_message_handler_); 77 old_message_handler_ = NULL; 78 79 logging::CloseLogFile(); 80 81 // Delete the log file if it wasn't written to (this is expected). 82 int64 file_size = 0; 83 if (file_util::GetFileSize(log_file_path_, &file_size) && file_size == 0) 84 base::DeleteFile(log_file_path_, false); 85 } 86 87 // Returns the path to the log file to create. The file should be empty at 88 // process exit since we redirect log messages to stderr. 89 // static 90 base::FilePath ConsoleLogHelper::GetLogFilePath() { 91 base::FilePath log_path; 92 93 if (PathService::Get(base::DIR_TEMP, &log_path)) 94 return log_path.Append(kLogFileName_); 95 else 96 return base::FilePath(kLogFileName_); 97 } 98 99 // A logging::LogMessageHandlerFunction that sends the body of messages logged 100 // at the severity of validation violations to stderr. All other messages are 101 // sent through the default logging pipeline. 102 // static 103 bool ConsoleLogHelper::DumpLogMessage(int severity, 104 const char* file, 105 int line, 106 size_t message_start, 107 const std::string& str) { 108 if (severity == kViolationSeverity_) { 109 fprintf(kOutputStream_, "%s", str.c_str() + message_start); 110 return true; 111 } 112 113 if (old_message_handler_ != NULL) 114 return (old_message_handler_)(severity, file, line, message_start, str); 115 116 return false; 117 } 118 119 const char* LevelToString(bool system_level) { 120 return system_level ? "System-level" : "User-level"; 121 } 122 123 std::string InstallationTypeToString( 124 InstallationValidator::InstallationType type) { 125 std::string result; 126 127 static const struct ProductData { 128 int bit; 129 const char* name; 130 } kProdBitToName[] = { 131 { 132 InstallationValidator::ProductBits::CHROME_SINGLE, 133 "Chrome" 134 }, { 135 InstallationValidator::ProductBits::CHROME_MULTI, 136 "Chrome (multi)" 137 }, { 138 InstallationValidator::ProductBits::CHROME_FRAME_SINGLE, 139 "Chrome Frame" 140 }, { 141 InstallationValidator::ProductBits::CHROME_FRAME_MULTI, 142 "Chrome Frame (multi)" 143 }, { 144 InstallationValidator::ProductBits::CHROME_FRAME_READY_MODE, 145 "Ready-mode Chrome Frame" 146 }, 147 }; 148 149 for (size_t i = 0; i < arraysize(kProdBitToName); ++i) { 150 const ProductData& product_data = kProdBitToName[i]; 151 if ((type & product_data.bit) != 0) { 152 if (!result.empty()) 153 result.append(", "); 154 result.append(product_data.name); 155 } 156 } 157 158 return result; 159 } 160 161 } // namespace 162 163 // The main program. 164 int wmain(int argc, wchar_t *argv[]) { 165 int result = EXIT_SUCCESS; 166 base::AtExitManager exit_manager; 167 168 CommandLine::Init(0, NULL); 169 ConsoleLogHelper log_helper; 170 171 // Check user-level and system-level for products. 172 for (int i = 0; i < 2; ++i) { 173 const bool system_level = (i != 0); 174 InstallationValidator::InstallationType type = 175 InstallationValidator::NO_PRODUCTS; 176 bool is_valid = 177 InstallationValidator::ValidateInstallationType(system_level, &type); 178 if (type != InstallationValidator::NO_PRODUCTS) { 179 FILE* stream = is_valid ? stdout : stderr; 180 fprintf(stream, "%s installations%s: %s\n", LevelToString(system_level), 181 (is_valid ? "" : " (with errors)"), 182 InstallationTypeToString(type).c_str()); 183 } 184 if (!is_valid) 185 result = EXIT_FAILURE; 186 } 187 188 return result; 189 } 190