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.
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.
12 #include "base/at_exit.h"
13 #include "base/command_line.h"
14 #include "base/files/file_util.h"
15 #include "base/logging.h"
16 #include "base/path_service.h"
17 #include "chrome/installer/util/installation_validator.h"
19 using installer::InstallationValidator
;
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
26 class ConsoleLogHelper
{
32 static base::FilePath
GetLogFilePath();
33 static bool DumpLogMessage(int severity
,
37 const std::string
& str
);
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_
;
47 const wchar_t ConsoleLogHelper::kLogFileName_
[] = L
"validate_installation.log";
49 // Dump violations to stderr.
51 FILE* const ConsoleLogHelper::kOutputStream_
= stderr
;
53 // InstallationValidator logs all violations at ERROR level.
55 const logging::LogSeverity
56 ConsoleLogHelper::kViolationSeverity_
= logging::LOG_ERROR
;
59 logging::LogMessageHandlerFunction
60 ConsoleLogHelper::old_message_handler_
= NULL
;
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
);
71 old_message_handler_
= logging::GetLogMessageHandler();
72 logging::SetLogMessageHandler(&DumpLogMessage
);
75 ConsoleLogHelper::~ConsoleLogHelper() {
76 logging::SetLogMessageHandler(old_message_handler_
);
77 old_message_handler_
= NULL
;
79 logging::CloseLogFile();
81 // Delete the log file if it wasn't written to (this is expected).
83 if (base::GetFileSize(log_file_path_
, &file_size
) && file_size
== 0)
84 base::DeleteFile(log_file_path_
, false);
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.
90 base::FilePath
ConsoleLogHelper::GetLogFilePath() {
91 base::FilePath log_path
;
93 if (PathService::Get(base::DIR_TEMP
, &log_path
))
94 return log_path
.Append(kLogFileName_
);
96 return base::FilePath(kLogFileName_
);
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.
103 bool ConsoleLogHelper::DumpLogMessage(int severity
,
106 size_t message_start
,
107 const std::string
& str
) {
108 if (severity
== kViolationSeverity_
) {
109 fprintf(kOutputStream_
, "%s", str
.c_str() + message_start
);
113 if (old_message_handler_
!= NULL
)
114 return (old_message_handler_
)(severity
, file
, line
, message_start
, str
);
119 const char* LevelToString(bool system_level
) {
120 return system_level
? "System-level" : "User-level";
123 std::string
InstallationTypeToString(
124 InstallationValidator::InstallationType type
) {
127 static const struct ProductData
{
130 } kProdBitToName
[] = {
132 InstallationValidator::ProductBits::CHROME_SINGLE
,
135 InstallationValidator::ProductBits::CHROME_MULTI
,
138 InstallationValidator::ProductBits::CHROME_FRAME_SINGLE
,
141 InstallationValidator::ProductBits::CHROME_FRAME_MULTI
,
142 "Chrome Frame (multi)"
144 InstallationValidator::ProductBits::CHROME_FRAME_READY_MODE
,
145 "Ready-mode Chrome Frame"
149 for (size_t i
= 0; i
< arraysize(kProdBitToName
); ++i
) {
150 const ProductData
& product_data
= kProdBitToName
[i
];
151 if ((type
& product_data
.bit
) != 0) {
154 result
.append(product_data
.name
);
164 int wmain(int argc
, wchar_t *argv
[]) {
165 int result
= EXIT_SUCCESS
;
166 base::AtExitManager exit_manager
;
168 base::CommandLine::Init(0, NULL
);
169 ConsoleLogHelper log_helper
;
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
;
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());
185 result
= EXIT_FAILURE
;