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