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 #include "chrome/installer/util/logging_installer.h"
6 
7 #include <stdint.h>
8 #include <windows.h>
9 
10 #include "base/command_line.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/logging_win.h"
16 #include "base/path_service.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/win/scoped_handle.h"
20 #include "build/branding_buildflags.h"
21 #include "chrome/installer/util/initial_preferences.h"
22 #include "chrome/installer/util/initial_preferences_constants.h"
23 #include "chrome/installer/util/util_constants.h"
24 
25 // {93BCE0BF-3FAF-43b1-9E28-BEB6FAB5ECE7}
26 static const GUID kSetupTraceProvider = {
27     0x93bce0bf,
28     0x3faf,
29     0x43b1,
30     {0x9e, 0x28, 0xbe, 0xb6, 0xfa, 0xb5, 0xec, 0xe7}};
31 
32 namespace installer {
33 
34 // This should be true for the period between the end of
35 // InitInstallerLogging() and the beginning of EndInstallerLogging().
36 bool installer_logging_ = false;
37 
TruncateLogFileIfNeeded(const base::FilePath & log_file)38 TruncateResult TruncateLogFileIfNeeded(const base::FilePath& log_file) {
39   TruncateResult result = LOGFILE_UNTOUCHED;
40 
41   int64_t log_size = 0;
42   if (base::GetFileSize(log_file, &log_size) &&
43       log_size > kMaxInstallerLogFileSize) {
44     // Cause the old log file to be deleted when we are done with it.
45     uint32_t file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
46                           base::File::FLAG_SHARE_DELETE |
47                           base::File::FLAG_DELETE_ON_CLOSE;
48     base::File old_log_file(log_file, file_flags);
49 
50     if (old_log_file.IsValid()) {
51       result = LOGFILE_DELETED;
52       base::FilePath tmp_log(log_file.value() + FILE_PATH_LITERAL(".tmp"));
53       // Note that base::Move will attempt to replace existing files.
54       if (base::Move(log_file, tmp_log)) {
55         int64_t offset = log_size - kTruncatedInstallerLogFileSize;
56         std::string old_log_data(kTruncatedInstallerLogFileSize, 0);
57         int bytes_read = old_log_file.Read(offset, &old_log_data[0],
58                                            kTruncatedInstallerLogFileSize);
59         if (bytes_read > 0 &&
60             (bytes_read ==
61                  base::WriteFile(log_file, &old_log_data[0], bytes_read) ||
62              base::PathExists(log_file))) {
63           result = LOGFILE_TRUNCATED;
64         }
65       }
66     } else if (base::DeleteFile(log_file)) {
67       // Couldn't get sufficient access to the log file, optimistically try to
68       // delete it.
69       result = LOGFILE_DELETED;
70     }
71   }
72 
73   return result;
74 }
75 
InitInstallerLogging(const installer::InitialPreferences & prefs)76 void InitInstallerLogging(const installer::InitialPreferences& prefs) {
77   if (installer_logging_)
78     return;
79 
80   installer_logging_ = true;
81 
82   bool value = false;
83   if (prefs.GetBool(installer::initial_preferences::kDisableLogging, &value) &&
84       value) {
85     return;
86   }
87 
88   base::FilePath log_file_path(GetLogFilePath(prefs));
89   TruncateLogFileIfNeeded(log_file_path);
90 
91   logging::LoggingSettings settings;
92   settings.logging_dest = logging::LOG_TO_FILE;
93   settings.log_file_path = log_file_path.value().c_str();
94   logging::InitLogging(settings);
95 
96   if (prefs.GetBool(installer::initial_preferences::kVerboseLogging, &value) &&
97       value) {
98     logging::SetMinLogLevel(logging::LOG_VERBOSE);
99   } else {
100     logging::SetMinLogLevel(logging::LOG_ERROR);
101   }
102 
103   // Enable ETW logging.
104   logging::LogEventProvider::Initialize(kSetupTraceProvider);
105 }
106 
EndInstallerLogging()107 void EndInstallerLogging() {
108   logging::CloseLogFile();
109 
110   installer_logging_ = false;
111 }
112 
GetLogFilePath(const installer::InitialPreferences & prefs)113 base::FilePath GetLogFilePath(const installer::InitialPreferences& prefs) {
114   std::string path;
115   prefs.GetString(installer::initial_preferences::kLogFile, &path);
116   if (!path.empty())
117     return base::FilePath(base::UTF8ToWide(path));
118 
119   static const base::FilePath::CharType kLogFilename[] =
120 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
121       FILE_PATH_LITERAL("chrome_installer.log");
122 #else  // BUILDFLAG(CHROMIUM_BRANDING)
123       FILE_PATH_LITERAL("chromium_installer.log");
124 #endif
125 
126   // Fallback to current directory if getting the temp directory fails.
127   base::FilePath tmp_path;
128   ignore_result(base::PathService::Get(base::DIR_TEMP, &tmp_path));
129   return tmp_path.Append(kLogFilename);
130 }
131 
132 }  // namespace installer
133