Home | History | Annotate | Download | only in tools
      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