1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "udev_collector.h" 18 19 #include <map> 20 #include <utility> 21 #include <vector> 22 23 #include <base/files/file_enumerator.h> 24 #include <base/files/file_util.h> 25 #include <base/logging.h> 26 #include <base/strings/string_number_conversions.h> 27 #include <base/strings/string_split.h> 28 #include <base/strings/string_util.h> 29 #include <base/strings/stringprintf.h> 30 #include <brillo/process.h> 31 32 using base::FilePath; 33 34 namespace { 35 36 const char kCollectUdevSignature[] = "crash_reporter-udev-collection"; 37 const char kGzipPath[] = "/bin/gzip"; 38 const char kUdevExecName[] = "udev"; 39 const char kUdevSignatureKey[] = "sig"; 40 const char kUdevSubsystemDevCoredump[] = "devcoredump"; 41 const char kDefaultDevCoredumpDirectory[] = "/sys/class/devcoredump"; 42 const char kDevCoredumpFilePrefixFormat[] = "devcoredump_%s"; 43 44 } // namespace 45 46 UdevCollector::UdevCollector() 47 : dev_coredump_directory_(kDefaultDevCoredumpDirectory) {} 48 49 UdevCollector::~UdevCollector() {} 50 51 bool UdevCollector::HandleCrash(const std::string &udev_event) { 52 if (IsDeveloperImage()) { 53 LOG(INFO) << "developer image - collect udev crash info."; 54 } else if (is_feedback_allowed_function_()) { 55 LOG(INFO) << "Consent given - collect udev crash info."; 56 } else { 57 LOG(INFO) << "Ignoring - Non-developer image and no consent given."; 58 return false; 59 } 60 61 // Process the udev event string. 62 // First get all the key-value pairs. 63 std::vector<std::pair<std::string, std::string>> udev_event_keyval; 64 base::SplitStringIntoKeyValuePairs(udev_event, '=', ':', &udev_event_keyval); 65 std::vector<std::pair<std::string, std::string>>::const_iterator iter; 66 std::map<std::string, std::string> udev_event_map; 67 for (iter = udev_event_keyval.begin(); 68 iter != udev_event_keyval.end(); 69 ++iter) { 70 udev_event_map[iter->first] = iter->second; 71 } 72 73 // Make sure the crash directory exists, or create it if it doesn't. 74 FilePath crash_directory; 75 if (!GetCreatedCrashDirectoryByEuid(0, &crash_directory, nullptr)) { 76 LOG(ERROR) << "Could not get crash directory."; 77 return false; 78 } 79 80 if (udev_event_map["SUBSYSTEM"] == kUdevSubsystemDevCoredump) { 81 int instance_number; 82 if (!base::StringToInt(udev_event_map["KERNEL_NUMBER"], &instance_number)) { 83 LOG(ERROR) << "Invalid kernel number: " 84 << udev_event_map["KERNEL_NUMBER"]; 85 return false; 86 } 87 return ProcessDevCoredump(crash_directory, instance_number); 88 } 89 90 return ProcessUdevCrashLogs(crash_directory, 91 udev_event_map["ACTION"], 92 udev_event_map["KERNEL"], 93 udev_event_map["SUBSYSTEM"]); 94 } 95 96 bool UdevCollector::ProcessUdevCrashLogs(const FilePath& crash_directory, 97 const std::string& action, 98 const std::string& kernel, 99 const std::string& subsystem) { 100 // Construct the basename string for crash_reporter_logs.conf: 101 // "crash_reporter-udev-collection-[action]-[name]-[subsystem]" 102 // If a udev field is not provided, "" is used in its place, e.g.: 103 // "crash_reporter-udev-collection-[action]--[subsystem]" 104 // Hence, "" is used as a wildcard name string. 105 // TODO(sque, crosbug.com/32238): Implement wildcard checking. 106 std::string basename = action + "-" + kernel + "-" + subsystem; 107 std::string udev_log_name = std::string(kCollectUdevSignature) + '-' + 108 basename; 109 110 // Create the destination path. 111 std::string log_file_name = 112 FormatDumpBasename(basename, time(nullptr), 0); 113 FilePath crash_path = GetCrashPath(crash_directory, log_file_name, "log"); 114 115 // Handle the crash. 116 bool result = GetLogContents(log_config_path_, udev_log_name, crash_path); 117 if (!result) { 118 LOG(ERROR) << "Error reading udev log info " << udev_log_name; 119 return false; 120 } 121 122 // Compress the output using gzip. 123 brillo::ProcessImpl gzip_process; 124 gzip_process.AddArg(kGzipPath); 125 gzip_process.AddArg(crash_path.value()); 126 int process_result = gzip_process.Run(); 127 FilePath crash_path_zipped = FilePath(crash_path.value() + ".gz"); 128 // If the zip file was not created, use the uncompressed file. 129 if (process_result != 0 || !base::PathExists(crash_path_zipped)) 130 LOG(ERROR) << "Could not create zip file " << crash_path_zipped.value(); 131 else 132 crash_path = crash_path_zipped; 133 134 std::string exec_name = std::string(kUdevExecName) + "-" + subsystem; 135 AddCrashMetaData(kUdevSignatureKey, udev_log_name); 136 WriteCrashMetaData(GetCrashPath(crash_directory, log_file_name, "meta"), 137 exec_name, crash_path.value()); 138 return true; 139 } 140 141 bool UdevCollector::ProcessDevCoredump(const FilePath& crash_directory, 142 int instance_number) { 143 FilePath coredump_path = 144 FilePath(base::StringPrintf("%s/devcd%d/data", 145 dev_coredump_directory_.c_str(), 146 instance_number)); 147 if (!base::PathExists(coredump_path)) { 148 LOG(ERROR) << "Device coredump file " << coredump_path.value() 149 << " does not exist"; 150 return false; 151 } 152 153 // Add coredump file to the crash directory. 154 if (!AppendDevCoredump(crash_directory, coredump_path, instance_number)) { 155 ClearDevCoredump(coredump_path); 156 return false; 157 } 158 159 // Clear the coredump data to allow generation of future device coredumps 160 // without having to wait for the 5-minutes timeout. 161 return ClearDevCoredump(coredump_path); 162 } 163 164 bool UdevCollector::AppendDevCoredump(const FilePath& crash_directory, 165 const FilePath& coredump_path, 166 int instance_number) { 167 // Retrieve the driver name of the failing device. 168 std::string driver_name = GetFailingDeviceDriverName(instance_number); 169 if (driver_name.empty()) { 170 LOG(ERROR) << "Failed to obtain driver name for instance: " 171 << instance_number; 172 return false; 173 } 174 175 std::string coredump_prefix = 176 base::StringPrintf(kDevCoredumpFilePrefixFormat, driver_name.c_str()); 177 178 std::string dump_basename = FormatDumpBasename(coredump_prefix, 179 time(nullptr), 180 instance_number); 181 FilePath core_path = GetCrashPath(crash_directory, dump_basename, "devcore"); 182 FilePath log_path = GetCrashPath(crash_directory, dump_basename, "log"); 183 FilePath meta_path = GetCrashPath(crash_directory, dump_basename, "meta"); 184 185 // Collect coredump data. 186 if (!base::CopyFile(coredump_path, core_path)) { 187 LOG(ERROR) << "Failed to copy device coredumpm file from " 188 << coredump_path.value() << " to " << core_path.value(); 189 return false; 190 } 191 192 // Collect additional logs if one is specified in the config file. 193 std::string udev_log_name = std::string(kCollectUdevSignature) + '-' + 194 kUdevSubsystemDevCoredump + '-' + driver_name; 195 bool result = GetLogContents(log_config_path_, udev_log_name, log_path); 196 if (result) { 197 AddCrashMetaUploadFile("logs", log_path.value()); 198 } 199 200 WriteCrashMetaData(meta_path, coredump_prefix, core_path.value()); 201 202 return true; 203 } 204 205 bool UdevCollector::ClearDevCoredump(const FilePath& coredump_path) { 206 if (!base::WriteFile(coredump_path, "0", 1)) { 207 LOG(ERROR) << "Failed to delete the coredump data file " 208 << coredump_path.value(); 209 return false; 210 } 211 return true; 212 } 213 214 std::string UdevCollector::GetFailingDeviceDriverName(int instance_number) { 215 FilePath failing_uevent_path = 216 FilePath(base::StringPrintf("%s/devcd%d/failing_device/uevent", 217 dev_coredump_directory_.c_str(), 218 instance_number)); 219 if (!base::PathExists(failing_uevent_path)) { 220 LOG(ERROR) << "Failing uevent path " << failing_uevent_path.value() 221 << " does not exist"; 222 return ""; 223 } 224 225 std::string uevent_content; 226 if (!base::ReadFileToString(failing_uevent_path, &uevent_content)) { 227 LOG(ERROR) << "Failed to read uevent file " << failing_uevent_path.value(); 228 return ""; 229 } 230 231 // Parse uevent file contents as key-value pairs. 232 std::vector<std::pair<std::string, std::string>> uevent_keyval; 233 base::SplitStringIntoKeyValuePairs(uevent_content, '=', '\n', &uevent_keyval); 234 std::vector<std::pair<std::string, std::string>>::const_iterator iter; 235 for (iter = uevent_keyval.begin(); 236 iter != uevent_keyval.end(); 237 ++iter) { 238 if (iter->first == "DRIVER") { 239 return iter->second; 240 } 241 } 242 243 return ""; 244 } 245